JSPatch

上架后的 应用 可能会遇到的一些突发状况 , 未测出的Crash、临时改点小需求 , 等等 , 我们总不能每次因为一点小改动就重新提交一次 App Store , 先不说 App Store 的审核时间 , 频繁的让用户去更新应用 , 用户也会烦的 。使用这篇文章所讲的来实现动态更新是再合适不过了

动态更新方案

  • JSPatch (代码量少,强大持续有人维护,js语言,appstore审核可通过)
  • alibaba/wax(阿里巴巴主推)
  • WaxPatch
  • 脚本
  • ….

基础原理

JSPatch用iOS内置的JavaScriptCore.framework作为JS引擎,但没有用它JSExport的特性进行JS-OC函数互调,而是通过Objective-C Runtime,从JS传递要调用的类名函数名到Objective-C,再使用NSInvocation动态调用对应的OC方法。

使用

方式一

按照JSPatch Platform进行下载SDK,按照指示接入SDK。简单方便无需要考虑后台搭建,安全等问题,达到一定的用户日活量需要收费。

方式二

JSPatch下载代码,或者通过pod管理方式引入JSPatch文件。如果只是在本地调用测试js代码是否作用,只需要调用如代码,并在jsPatchTest.js中加入测试代码:

1
2
3
4
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"jsPatchTest" ofType:@"js"];
NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
[JPEngine startEngine];
[JPEngine evaluateScript:script];

如上仅仅是本地js代码测试,发布线上我们需要有自己的后台下发脚本,每次客户端启动app非实时或者becomeActivity实时检测最新的hotfix的脚本,根据当前的用户app的版本和hotfix的版本,用户自动请求下载脚本后保存在本地。在这一过程中可能会被劫持造成不可控的安全问题,为此我们需要在后台进行MD5或者RSA等加密,移动端进行解密操作,确保安全问题。

比较

Github 开源的是 JSPatch 核心代码,使用完全免费自由,若打算自己搭建后台下发 JSPatch 脚本,可以直接使用 github 上的核心代码,与 JSPatch 平台上的 SDK 无关。JSPatch 平台的 SDK 在核心代码的基础上增加了向平台请求脚本/传输解密/版本管理等功能,只用于这个平台。

问题

1.定义为ivar的成员,无法获取,特别注意。属性的访问都是通过方法调用的形式。所以代码中不要使用ivar定义成员。

2.注意写代码的时候能够拆分的代码,尽量简洁干净。避免hotfix的时候,需要重写大量的内容。

3.JSPatch获取OC class名称的方法,用于OC判读是否属于某一个类

1
2
obj.__clsDeclaration //返回的是一个字符串,通过比较改字符串与类名的字符串是否相等可以判断obj的类型。 应用于新版的JSPatch
obj.__clsName //对于使用老版本的JSPatch需要使用该字段来获取class名称

hotfix代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
defineClass("BBNewMainView", {
// instance method definitions
reloadDynamicBanners:function() {
require('BBSquareAdsView,BBAdsCollectionView');
var adsCollectionViewJS = self.adsCollectionView();
var squareAdsView = self.squareAdsView();//定义为ivar的成员,无法获取,特别注意。属性的访问都是通过方法调用的形式
var adsTop = adsCollectionViewJS.frame().y;//注意该地方获取origin.y的方式,相关文档上面存在错误
var adsHeight = adsCollectionViewJS.frame().height;
var adsBottom = adsTop + adsHeight;
squareAdsView.setFrame({x:0, y:parseInt(adsBottom), width:0, height:0});//注意这里parseInt(adsBottom),转换为int类型的
self.ORIGreloadDynamicBanners(); //添加ORIG前缀表示调用oc中的原始方法
}
})

参考

1.JSPatch官网

2.JSPatch的Github链接

3.OC转换为JSPatch(不是万能的)

4.JSPatch实现原理详解

5.iOS应用架构谈 动态部署方案