JSPatchDemo

简介:

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


用途:

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

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


Demo:

JSPatchDemo

原理:

      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的规则。iOS Developer Program License Agreement里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,持续改进中。


脚本部署:

Plan A:部署到自己的服务端.

Plan B[不推荐]:JSPatch 平台 (提供了脚本后台托管,版本管理,保证传输安全等功能,让你无需搭建一个后台,无需关心部署操作,只需引入一个 JSPatch SDK 即可立即使用 JSPatch.通过 JSPatch 平台上传的脚本文件都会保存在七牛云存储上,客户端 APP 只跟七牛服务器通讯,支持高并发,CDN分布全国,速度和稳定性有保证。)


风险:

1.传输安全:若在网络传输过程中下发明文JS,可能会被中间人篡改JS脚本,执行任意方法.方案a:对称加密

若要让 JS 代码传输过程中不轻易被中间人截获替换,很容易想到的方式就是对代码进行加密,可以用 zip 的加密压缩,也可以用 AES 等加密算法。这个方案的优点是非常简单,缺点是安全性低,容易被破解。因为密钥是要保存在客户端的,只要客户端被人拿去反编译,把密码字段找出来,就完成破解了。

对此也有一些改进方案,例如:

1.可以把密码保存到 keychain 上,但这种方式也是不可靠的,只要随便找一台机器越狱装了这个 APP,用 hook 的方式在 APP 上添加一些代码,获得 keychain 里的密钥值,就可以用于其他所有机器的传输解密了。

2.给每个用户下发不同的密钥。但这样就非常繁琐,需要对下发密钥的请求做好保护,后台需要每次都对脚本进行不同密钥的加密操作,复杂性高了。

综上,对称加密安全性低,若要稍微提高点安全性,就会提升程序复杂度。

方案b:HTTPS

第二个方案是直接使用 HTTPS 传输,优点是安全性高,只要使用正确,证书在服务端未泄露,就不会被破解。缺点是部署麻烦,需要使用者服务器支持 HTTPS,门槛较高。另外客户端需要做好 HTTPS 的证书验证(有些使用者可能会漏掉这个验证,导致安全性大降),具体的认证方式可见网上一些文章,例如这篇。如果服务器本来就支持 HTTPS,使用这种方案也是一种不错的选择。

方案c:RSA 校验

有没有安全性高,部署简单,门槛低的方案?RSA 校验就是。

这种方式属于数字签名,用了跟 HTTPS 一样的非对称加密,只是简化了,把非对称加密只用于校验文件,而不解决传输过程中数据内容泄露的问题,而我们的目的只是防止传输过程中数据被篡改,对于数据内容泄露并不是太在意。整个校验过程如下:

服务端计算出脚本文件的 MD5 值,作为这个文件的数字签名。

服务端通过私钥加密第 1 步算出的 MD5 值,得到一个加密后的 MD5 值。

把脚本文件和加密后的 MD5 值一起下发给客户端。

客户端拿到加密后的 MD5 值,通过保存在客户端的公钥解密。

客户端计算脚本文件的 MD5 值。

对比第 4/5 步的两个 MD5 值(分别是客户端和服务端计算出来的 MD5 值),若相等则通过校验。

只要通过校验,就能确保脚本在传输的过程中没有被篡改,因为第三方若要篡改脚本文件,必须计算出新的脚本文件 MD5 并用私钥加密,客户端公钥才能解密出这个 MD5 值,而在服务端未泄露的情况下第三方是拿不到私钥的。

这种方案安全性跟 HTTPS 一致,但不像 HTTPS 一样部署麻烦,一套代码即可通用。对于它的缺点:数据内容泄露,其实在传输过程中不泄露,保存在本地同样会泄露,若对此在意,可以对脚本文件再加一层简单的对称加密。这个方案优点多缺点少,推荐使用,目前JSPatch 平台就是使用这个方案。

最后有个小问题,保存在客户端的代码也可能被人篡改,需不需要采取措施?这个要看各人需求了,因为这个安全问题不大,能篡改本地文件,差不多已经有手机所有权限了,这时也无所谓脚本会不会被篡改了。若有需要,可以加个简单的对称加密,或者按上述流程每次都验证一遍MD5值。

2.执行安全:下发的 JS 脚本灵活度大,相当于一次小型更新,若未进行充分测试,可能会出现 crash 等情况对 APP 稳定性造成影响。

方案:

对于中大型 APP,下发 JS 脚本需要谨慎,有可能因为疏忽下发了有问题的代码,导致大量 APP crash,或一些其他异常情况,需要有一些机制避免这种情况。若要做得完整,可以分为:事发前(灰度),事发中(监控),事发后(回退)。

灰度

首先需要在事发前把出现问题的影响面降到最低,对于中大型 APP,不能一次把脚本下发给所有用户,需要有灰度机制,也就是一开始只下发给其中一部分用户,看看会不会出现异常情况,再逐步覆盖到所有用户。有条件的话灰度的用户最好按机型/系统/地域等属性随机分配,尽量让最少的人覆盖到大部分情况。

监控

接着是事发了我们需要知道脚本有问题,需要对 APP 有一些监控机制,像 crash 监控,这个一般所有 APP 都有接入,再按需求自行加入其他监控指标。

回退

最后是事发后回退代码。一般为了避免不可预料的情况出现,JSPatch 脚本建议在启动时执行,APP 运行过程中不去除,所以这个回退建议的实现方式是后台下发命令,让 APP 在下次启动时不执行 JSPatch 脚本即可。

但这里能回退的前提是 APP 可以接收到后台下发的回退命令,若因为下发的脚本导致 APP 启动即时 crash,这个回退命令也会接收不到。所以建议再加一层防启动 crash 的机制,APP 在连续启动即 crash 后,下次启动不再执行脚本文件。

灰度和监控中小型 APP 可以考虑不用,回退机制是每个使用 JSPatch 都建议加上的。目前JSPatch 平台实现了上述回退方案。

额外功能:

1:建议用JSPatch动态打补丁,不建议开发模块.

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

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

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

JSPatch没有IDE支持,开发效率低。

若想动态为APP添加模块:

目前React Native给出了很好的方案,解决了上述三个问题:

JS/OC不会频繁通信,会在事件触发时批量传递,提高效率。(详见React Native通信机制详解

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

React Native连IDE都准备好了。

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

2:有条件的选择用户范围

Plan A:灰度

在后台发布补丁脚本时可以选择灰度下发,并选择灰度用户百分比,这个补丁就会按选定的百分比只对这个比例的用户起作用。例如选择灰度 30%,那这个补丁脚本只会在所有接入的设备中随机挑选 30% 的设备生效。

灰度下发无需 SDK 额外设置,只需接入的 SDK 版本在 1.2 以上。

灰度发布后后续可以修改这个灰度值,便于逐渐增加灰度数量,直到全量发布。

Plan B: 条件下发

在后台发布补丁脚本时可以选择条件下发,然后填入条件语句,只有满足条件的设备才会执行这个补丁脚本,条件语句由 key/value/运算符组成,示例:userId==10000876,iOS>9.0&&isMale==1。

条件语句里用到的 key/value 需要事先在 APP 里通过 +setupUserData: 设置,支持设置多个字段,用 NSDictionary 表示,例如可以设置当前登录的用户ID以及性别:

//_userId = @"1000876" //_isMale = @(1)

[JSPatch setupUserData:@{@"userId": _userId, @"isMale": _isMale}];

这样在下发脚本时填入条件 userId==1000876 后,这个脚本就只对这个用户生效,如果填入 isMale==0 则对这个用户不生效,对其他在 SDK 设置了 @"isMale": @"0" 的用户生效。


参考资料:

bang的博客

JSPatch的Github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 点进来的同学应该是对JSPatch有初步的了解了,主要在此介绍一下我的学习总结: 首先要了解OC代码如何转换为JS...
    ericze阅读 559评论 2 16
  • JSPatch是什么 JSPatch是一个开源项目,只需要在项目里引入极小的引擎文件,就可以使用 JavaScri...
    ImmortalSummer阅读 2,527评论 7 11
  • 一、背景需求介绍 为什么我们需要一个热修复(hot-fix)技术? 工作中容易犯错、bug难以避免。 开发和测试人...
    上官soyo阅读 54,971评论 27 186
  • JSPatch简介 JSPatch 是一个开源项目(Github链接),只需要在项目里引入极小的引擎文件,就可以使...
    zyl04401阅读 2,160评论 0 6
  • 今天五点下班,去幼儿园接了女儿,然后去学校操场跑步。 我告诉她,妈妈要去跑步啦,你就在这里看着我们的包包,在这里玩...
    皋辜格琢阅读 256评论 2 0