JSPatch – 动态更新iOS APP

Posted iOS开发by唐巧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JSPatch – 动态更新iOS APP相关的知识,希望对你有一定的参考价值。

作者介绍:bang,ios/前端开发者,推特中文圈/伊书/JSPatch作者,博客 http://cnbang.net, 目前就职于广州腾讯。

文章介绍:由于苹果审核效率的问题,动态 Patch 技术从来都是 iOS 开发者的梦想。业界也出了一些解决方案,但由于各种原因,现在都还没有被普遍应用。bang 开源的 JSPatch 框架简单小巧,相比 lua 来说更符合苹果的审核标准,希望能够有助于动态 Patch 技术的推广,造福广大开发者。


是最近业余做的项目,只需在项目中引入极小的引擎,就可以使用 javascript 调用任何 Objective-C 的原生接口,获得脚本语言的能力:动态更新 APP,替换项目原生代码修复 bug。

用途

是否有过这样的经历:新版本上线后发现有个严重的 bug,可能会导致 crash 率激增,可能会使网络请求无法发出,这时能做的只是赶紧修复 bug 然后提交等待漫长的 AppStore 审核,再盼望用户快点升级,付出巨大的人力和时间成本,才能完成此次 bug 的修复。

使用 JSPatch 可以解决这样的问题,只需在项目中引入 JSPatch,就可以在发现 bug 时下发 JS 脚本补丁,替换原生方法,无需更新 APP 即时修复 bug。

例子

@implementation JPTableViewController]
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  NSString *content = self.dataSource[[indexPath row]];  // 可能会超出数组范围导致 crash
  JPViewController *ctrl = [[JPViewController alloc] initWithContent:content];
  [self.navigationController pushViewController:ctrl];
}
...
@end

上述代码中取数组元素处可能会超出数组范围导致 crash。如果在项目里引用了 JSPatch,就可以下发 JS 脚本修复这个 bug:

#import “JPEngine.m"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [JPEngine startEngine];
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://cnbang.net/bugfix.JS"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (script) {
      [JPEngine evaluateScript:script];
    }
}];
   ….
    return YES;
}
@end
//JS
defineClass("JPTableViewController", {
  //instance method definitions
  tableView_didSelectRowAtIndexPath: function(tableView, indexPath) {
    var row = indexPath.row()
    if (self.dataSource().length > row) {  // 加上判断越界的逻辑
      var content = self.dataArr()[row];
      var ctrl = JPViewController.alloc().initWithContent(content);
      self.navigationController().pushViewController(ctrl);
    }
  }
}, {})

这样 JPTableViewController 里的 -tableView:didSelectRowAtIndexPath: 就替换成了这个 JS 脚本里的实现,在用户无感知的情况下修复了这个 bug。

更多的使用文档和 demo 请参考 。

原理

JSPatch 用 iOS 内置的 JavaScriptCore.framework 作为 JS 引擎,但没有用它 JSExport 的特性进行 JS-OC 函数互调,而是通过 Objective-C Runtime,从 JS 传递要调用的类名函数名到 Objective-C,再使用 NSInvocation 动态调用对应的 OC 方法。详细的实现原理以及实现过程中遇到的各种坑和 hack 方法会另有文章介绍。

方案对比

目前已经有一些方案可以实现动态打补丁,例如 WaxPatch,可以用 Lua 调用 OC 方法,相对于 WaxPatch,JSPatch 的优势是:

  1. JS 语言

    JS 比 Lua 在应用开发领域有更广泛的应用,目前前端开发和终端开发有融合的趋势,作为扩展的脚本语言,JS 是不二之选。

  2. 符合 Apple 规则

    JSPatch 更符合 Apple 的规则。 里 3.3.2 提到不可动态下发可执行代码,但通过苹果 JavaScriptCore.framework 或 WebKit 执行的代码除外,JS 正是通过 JavaScriptCore.framework 执行的。

  3. 小巧

    使用系统内置的 JavaScriptCore.framework,无需内嵌脚本引擎,体积小巧。

  4. 支持 block

    wax 在几年前就停止了开发和维护,不支持 Objective-C 里 block 跟 Lua 程序的互传,虽然一些第三方已经实现 block,但使用时参数上也有比较多的限制。

相对于 WaxPatch,JSPatch 劣势在于不支持 iOS6,因为需要引入 JavaScriptCore.framework。另外目前内存的使用上会高于 wax,持续改进中。

风险

JSPatch 让脚本语言获得调用所有原生 OC 方法的能力,不像 web 前端把能力局限在浏览器,使用上会有一些安全风险:

  1. 若在网络传输过程中下发明文 JS,可能会被中间人篡改 JS 脚本,执行任意方法,盗取 APP 里的相关信息。可以对传输过程进行加密,或用直接使用 https 解决。

  2. 若下载完后的 JS 保存在本地没有加密,在未越狱的机器上用户也可以手动替换或篡改脚本。这点危害没有第一点大,因为操作者是手机拥有者,不存在 APP 内相关信息被盗用的风险。若要避免用户修改代码影响 APP 运行,可以选择简单的加密存储。

其他用途

JSPatch 可以动态打补丁,自由修改 APP 里的代码,理论上还可以完全用 JSPatch 实现一个业务模块,甚至整个 APP,跟 wax 一样,但不推荐这么做,因为:

  1. JSPatch 和 wax 一样都是通过 Objective-C Runtime 的接口通过字符串反射找到对应的类和方法进行调用,这中间的字符串处理会损耗一定的性能,另外两种语言间的类型转换也有性能损耗,若用来做一个完整的业务模块,大量的频繁来回互调,可能有性能问题。

  2. 开发过程中需要用 OC 的思维写 JS/Lua,丧失了脚本语言自己的特性。

  3. JSPatch 和 wax 都没有 IDE 支持,开发效率低。

若想动态为 APP 添加模块,目前 React Native 给出了很好的方案,解决了上述三个问题:

  1. JS/OC 不会频繁通信,会在事件触发时批量传递,提高效率。(详见 )

  2. 开发过程无需考虑 OC 的感受,遵从 React 框架的思想进行纯 JS 开发就行,剩下的事情 React Native 帮你处理好了。

  3. React Native 连 都准备好了。

所以动态添加业务模块目前还是推荐尝试 React Native,但 React Native 并不会提供原生 OC 接口的反射调用和方法替换,无法做到修改原生代码,JSPatch 以小巧的引擎补足这个缺口,配合 React Native 用统一的 JS 语言让一个原生 APP 时刻处于可扩展可修改的状态。


以上是关于JSPatch – 动态更新iOS APP的主要内容,如果未能解决你的问题,请参考以下文章

项目推荐JSPatch

JSPatch 实现原理完整详(上篇)

iOS开发热更新JSPatch

iOS中 动态热修补技术JSPatch 韩俊强的博客

iOS中 动态热修补技术JSPatch 韩俊强的博客

DTalk实战JSPatch 被禁?你的APP需要另一种发布模式!