{"id":13427842,"url":"https://github.com/bang590/JSPatch","last_synced_at":"2025-03-16T00:32:35.238Z","repository":{"id":32619955,"uuid":"36205608","full_name":"bang590/JSPatch","owner":"bang590","description":"JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.","archived":false,"fork":false,"pushed_at":"2020-12-01T02:18:35.000Z","size":7890,"stargazers_count":11364,"open_issues_count":107,"forks_count":2240,"subscribers_count":502,"default_branch":"master","last_synced_at":"2024-10-25T08:51:25.511Z","etag":null,"topics":["hotfix","jsbridge","jspatch","objc-runtime"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bang590.png","metadata":{"files":{"readme":"README-CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-25T02:37:22.000Z","updated_at":"2024-10-24T14:58:07.000Z","dependencies_parsed_at":"2022-07-07T22:34:37.051Z","dependency_job_id":null,"html_url":"https://github.com/bang590/JSPatch","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bang590%2FJSPatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bang590%2FJSPatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bang590%2FJSPatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bang590%2FJSPatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bang590","download_url":"https://codeload.github.com/bang590/JSPatch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221565634,"owners_count":16844444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hotfix","jsbridge","jspatch","objc-runtime"],"created_at":"2024-07-31T01:00:41.215Z","updated_at":"2024-10-27T05:30:31.070Z","avatar_url":"https://github.com/bang590.png","language":"Objective-C","funding_links":[],"categories":["Bridging","C","Tools","Objective-C  Stars 1000以内排名整理","Objective-C"],"sub_categories":["Other free courses","Getting Started"],"readme":"# JSPatch\n\nJSPatch 可以让你用 JavaScript 书写原生 iOS APP。只需在项目引入极小的引擎，就可以使用 JavaScript 调用任何 Objective-C 的原生接口，获得脚本语言的优势：为项目动态添加模块，或替换项目原生代码动态修复 bug。\n\n项目仍在开发中，欢迎一起完善这个项目。\n\n**注意**：完善的文档请移步 [Wiki](https://github.com/bang590/JSPatch/wiki/)。\n\n## 示例\n\n```objc\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions \n{\n    [JPEngine startEngine];\n    NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@\"demo\" ofType:@\"js\"];\n    NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];\n    [JPEngine evaluateScript:script];\n    \n    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];\n    [self.window addSubview:[self genView]];\n    [self.window makeKeyAndVisible];\n    \n    return YES;\n}\n\n- (UIView *)genView\n{\n    return [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];\n}\n\n@end\n```\n\n```js\n// demo.js\nrequire('UIView, UIColor, UILabel')\ndefineClass('AppDelegate', {\n  // replace the -genView method\n  genView: function() {\n    var view = self.ORIGgenView();\n    view.setBackgroundColor(UIColor.greenColor())\n    var label = UILabel.alloc().initWithFrame(view.frame());\n    label.setText(\"JSPatch\");\n    label.setTextAlignment(1);\n    view.addSubview(label);\n    return view;\n  }\n});\n```\n\n可以使用 [JSPatch Convertor](https://github.com/bang590/JSPatchConvertor) 自动把 Objective-C 代码转为 JavaScript 代码。\n\n## 安装\n\n拷贝 `JSPatch/` 目录下的三个文件 `JSEngine.m` / `JSEngine.h` / `JSPatch.js` 到项目里即可。\n\n## 使用\n\n### Objective-C:\n1. `#import \"JPEngine.h\"`\n2. 调用`[JPEngine startEngine]`\n3. 通过`[JPEngine evaluateScript:@\"\"]`接口执行 JavaScript。\n\n```objc\n[JPEngine startEngine];\n\n// 直接执行js\n[JPEngine evaluateScript:@\"\\\n var alertView = require('UIAlertView').alloc().init();\\\n alertView.setTitle('Alert');\\\n alertView.setMessage('AlertView from js'); \\\n alertView.addButtonWithTitle('OK');\\\n alertView.show(); \\\n\"];\n\n// 从网络拉回js脚本执行\n[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@\"http://cnbang.net/test.js\"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {\n    NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n    [JPEngine evaluateScript:script];\n}];\n\n// 执行本地js文件\nNSString *sourcePath = [[NSBundle mainBundle] pathForResource:@\"sample\" ofType:@\"js\"];\nNSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];\n[JPEngine evaluateScript:script];\n```\n\n### JavaScript:\n\n#### 基础使用方式\n\n```js\n// 调用require引入要使用的OC类\nrequire('UIView, UIColor, UISlider, NSIndexPath')\n\n// 调用类方法\nvar redColor = UIColor.redColor();\n\n// 调用实例方法\nvar view = UIView.alloc().init();\nview.setNeedsLayout();\n\n// set proerty\nview.setBackgroundColor(redColor);\n\n// get property \nvar bgColor = view.backgroundColor();\n\n// 多参数方法名用'_'隔开：\n// OC：NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];\nvar indexPath = NSIndexPath.indexPathForRow_inSection(0, 1);\n\n// 方法名包含下划线'_'，js用双下划线表示\n// OC: [JPObject _privateMethod];\nJPObject.__privateMethod()\n\n// 如果要把 `NSArray` / `NSString` / `NSDictionary` 转为对应的 JS 类型，使用 `.toJS()` 接口.\nvar arr = require('NSMutableArray').alloc().init()\narr.addObject(\"JS\")\njsArr = arr.toJS()\nconsole.log(jsArr.push(\"Patch\").join(''))  //output: JSPatch\n\n// 在JS用字典的方式表示 CGRect / CGSize / CGPoint / NSRange\nvar view = UIView.alloc().initWithFrame({x:20, y:20, width:100, height:100});\nvar x = view.bounds().x;\n\n// block 从 JavaScript 传入 Objective-C 时，需要写上每个参数的类型。\n// OC Method: + (void)request:(void(^)(NSString *content, BOOL success))callback\nrequire('JPObject').request(block(\"NSString *, BOOL\", function(ctn, succ) {\n  if (succ) log(ctn)\n}));\n\n// GCD\ndispatch_after(function(1.0, function(){\n  // do something\n}))\ndispatch_async_main(function(){\n  // do something\n})\n```\n\n详细文档请参考wiki页面：[Base Usage](https://github.com/bang590/JSPatch/wiki/Base-usage)\n\n\n#### 定义类/替换方法\n\n用 `defineClass()` 定义 Objective-C 的类，对类和实例方法进行动态替换。\n\n```objc\n// OC\n@implementation JPTableViewController\n...\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath\n{\n  NSString *content = self.dataSource[[indexPath row]];  //may cause out of bound\n  JPViewController *ctrl = [[JPViewController alloc] initWithContent:content];\n  [self.navigationController pushViewController:ctrl];\n}\n- (NSArray *)dataSource\n{\n  return @[@\"JSPatch\", @\"is\"];\n}\n- (void)customMethod\n{\n  NSLog(@\"callCustom method\")\n}\n@end\n```\n\n```objc\n// JS\ndefineClass(\"JPTableViewController\", {\n  // instance method definitions\n  tableView_didSelectRowAtIndexPath: function(tableView, indexPath) {\n    var row = indexPath.row()\n    if (self.dataSource().count() \u003e row) {  //fix the out of bound bug here\n      var content = self.dataSource().objectAtIndex(row);\n      var ctrl = JPViewController.alloc().initWithContent(content);\n      self.navigationController().pushViewController(ctrl);\n    }\n  },\n\n  dataSource: function() {\n    // get the original method by adding prefix 'ORIG'\n    var data = self.ORIGdataSource().toJS();\n    return data.push('Good!');\n  }\n}, {})\n```\n\n详细文档请参考wiki页面：[Usage of defineClass](https://github.com/bang590/JSPatch/wiki/Usage-of-defineClass)\n\n\n#### 扩展\n\n一些自定义的struct类型、C函数调用以及其他功能可以通过扩展实现，调用 `+addExtensions:` 可以加载扩展接口：\n\n```objc\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions \n{\n    [JPEngine startEngine];\n\n    //添加扩展\n    [JPEngine addExtensions:@[@\"JPInclude\", @\"JPCGTransform\"]];\n\n    NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@\"demo\" ofType:@\"js\"];\n    NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];\n    [JPEngine evaluateScript:script];\n}\n```\n\n```js\ninclude('test.js')   //`include()`方法在扩展 JPInclude.m 里提供\nvar view = require('UIView').alloc().init()\n\n//struct CGAffineTransform 类型在 JPCGTransform.m 里提供支持\nview.setTransform({a:1, b:0, c:0, d:1, tx:0, ty:100})\n```\n\n扩展可以在JS动态加载，更推荐这种加载方式，在需要用到时才加载：\n\n```js\nrequire('JPEngine').addExtensions(['JPInclude', 'JPCGTransform'])\n\n// `include()` and `CGAffineTransform` is avaliable now.\n```\n\n可以通过新增扩展为自己项目里的 struct 类型以及C函数添加支持，详情请见wiki页面：[Adding new extensions](https://github.com/bang590/JSPatch/wiki/Adding-new-extensions)\n\n\n## 运行环境\n- iOS 7+\n- JavaScriptCore.framework\n- 支持 armv7/armv7s/arm64\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbang590%2FJSPatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbang590%2FJSPatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbang590%2FJSPatch/lists"}