iOS开发之——JSPatch使用教程

(一)什么是 JSPatch

JSPatch 是一个开源项目(Github链接),只需要在项目里引入极小的引擎文件,就可以使用 JavaScript 调用任何 Objective-C 的原生接口,替换任意 Objective-C 原生方法。目前主要用于下发 JS 脚本替换原生 Objective-C 代码,实时修复线上 bug。
例如线上 APP 有一段代码出现 bug 导致 crash:

(二)SDK 接入

  • 使用 Cocoapods 方法,直接集成
target :'GSJSPatchDemo'do 

pod 'JSPatchPlatform'

end
  • 添加依赖框架:TARGETS -> Build Phases -> Link Binary With Libraries -> + 添加 libz.dylib 和 JavaScriptCore.framework。

    《iOS开发之——JSPatch使用教程》 Snip20180808_44.png

(三)生成和配置RSA秘钥

在 Mac 终端上执行 openssl,再执行以下三句命令,生成 PKCS8 格式的 RSA 公私钥,执行过程中提示输入密码,密码为空(直接回车)就行。

1.生成RSA秘钥

openssl
genrsa -out rsa_private_key.pem 1024
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM –nocrypt
rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

2.集成代码中

把 rsa_public_key.pem 的内容换行手动改成 \n,并放入 [JSPatch setupRSAPublicKey:@””] 里:

[JSPatch startWithAppKey:@"7f1cf281ed7e0480"];
[JSPatch setupRSAPublicKey:@"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAFQPfhYbUoUFldY8DlXs9U+IA\nacxYuXtM7jmzP016AoDcK1l4c5aC42Zo41yrdF64T2b6ubedjCw15WNgneVrD0Mj\nkAm7Sj3sxvb7t+SFVK016IB8oa7kmxYCcTYNT9BIoAPeREFuvBk8IC0x6Kn4tZnY\ntw8zm4/5ubYEvvE/IQIDAQAB\n-----END PUBLIC KEY-----"];
[JSPatch sync];
    

注意应该在 +sync 之前调用,因为 +sync 可能会下载到脚本,这时已经要用 RSA key 去验证了。

3.上传脚本

使用私钥下发补丁下发脚本时,选择本地的 rsa_private_key.pem 文件,与脚本一同上传,JSPatch 平台会使用这个上传的 Private Key 对脚本 MD5 值进行加密,再下发给客户端。若客户端经过上述第二步设置了对应的 Public Key,就会用设置的 Public Key 对脚本进行验证,验证通过后运行脚本,否则不会运行。

这里上传的 rsa_private_key.pem 只是一次性使用,不会保存在服务端,所以只有通过用户自己保存的 rsa_private_key.pem 文件才可以针对 APP 下发脚本,即使 JSPatch 平台或者七牛云被黑,第三方也无法对你的 APP 下发恶意脚本(可以下发,但验证不过,不会执行),保证安全性。rsa_private_key.pem 请妥善保管,避免泄露。
若担心此处私钥在网络传输中暴露,可以使用JSPatch 补丁打包加密工具,在本地进行加密打包,无需上传私钥即可下发脚本。

3.1 添加版本

《iOS开发之——JSPatch使用教程》 Snip20180809_45.png

App版本号在项目 TARGETS -> General -> version 上可以找到:

《iOS开发之——JSPatch使用教程》 Snip20180809_46.png

注意这里版本号必须一致,JSPatch 平台会只针对这个版本号下发对应的 JS 脚本,若版本号对应不上,客户端也就请求不到相应的 JS 脚本。

《iOS开发之——JSPatch使用教程》 Snip20180809_47.png

补丁文件:上传 main.js(注意在 JSPatch 平台的规范里,JS脚本的文件名必须是 main.js)

补丁描述:填不填都可以

RSA秘钥:选择本地的 rsa_private_key.pem 文件

上传完成后,对应版本的 APP 会请求下载这个脚本保存在本地,以后每次启动都会执行这个脚本,至此脚本下发完成。

3.2 删除、修改JS脚本,后方法同3.1类似

3.3 补丁测试

本地测试分两个步骤:

  • 1.把补丁 main.js 拖入项目。

  • 2.注释掉所有 JSPatch 相关方法,调用 +testScriptInBundle 方法:

#import <JSPatchPlatform/JSPatch.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [JSPatch testScriptInBundle];
    
}

测试无误后,删除[JSPatch testScriptInBundle]代码即可

(四)使用方法

1、错误排查

1.1 JS脚本问题

如果 JS 脚本执行出错,XCode 控制台会打出错误日志,但仅靠错误日志可能难以发现,建议在 +startWithAppKey: 之前加入以下代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [JSPatch setupCallback:^(JPCallbackType type, NSDictionary *data, NSError *error) {
        if (type == JPCallbackTypeJSException) {
            NSAssert(NO, data[@"msg"]);
        }
    }];
    [JSPatch startWithAppKey:@"7f1cf281ed7e0480"];
    
}

这样在 debug 阶段 JS 脚本执行错误时会中 assert,马上可以看到错误信息。

附几个常犯的错误:

  • 1.不能用 NSLog(‘xx’),应该用 console.log(‘xx’)
  • 2.get property 记得加括号,例如 self.navigationItem(),而不是 self.navigationItem
  • 3.私有成员变量要用 self.valueForKey() 和 self.setValue_forKey() 接口存取。
  • 4.block 里不能直接使用 self

1.2 配置问题

  • 1.先确保 SDK 接入时 appKey 填写正确(SDK接入文档),以及发布补丁时 版本号 没有错误。

  • 2.分清 开发预览 模式和 正式下发 的区别,详见 开发预览。

  • 3.根据 log 排查问题:

2018-08-09 11:01:20.860914+0800 GSJSPatchDemo[11192:7056572] JSPatch: 尝试加载补丁
2018-08-09 11:01:21.016938+0800 GSJSPatchDemo[11192:7056572] JSPatch.log: run success
2018-08-09 11:01:21.021863+0800 GSJSPatchDemo[11192:7056572] JSPatch: 补丁已加载, 文件大小: 146

打印上面log表示执行了脚本

2018-08-09 11:01:21.077655+0800 GSJSPatchDemo[11192:7056572] JSPatch: sync请求:https://dn-jspatch.qbox.me/7f1cf281ed7e0480/1.0.1?d=E9B55FD4-FCFC-4B0A-8D63-3645C4E6D3F4&sv=1.6.6&v=1533783681.077580
2018-08-09 11:01:21.109747+0800 GSJSPatchDemo[11192:7056572]  INFO: Reveal Server started (Protocol Version 32).
2018-08-09 11:01:21.431226+0800 GSJSPatchDemo[11192:7056796] JSPatch: sync请求成功:{
    v = 3;
}

上面的日志表示请求到了版本号,url里的7f1cf281ed7e0480就是我们的appkey,1.0.1就是我们APP版本号,项目要和JSPatch平台保存一致。若 url 不正确或者脚本没有正确上传,这里会返回 error = “Document not found”。

2018-08-09 11:01:21.431733+0800 GSJSPatchDemo[11192:7056796] JSPatch: 补丁版本没有更新

执行到这里,表示检测到的补丁版本号比本地版本更新,去下载补丁文件,下载后会立即执行,到这一步应该就没问题了。若这个版本的补丁之前已经下载过,就不会再下载。

    1. 查看更多日志信息

在代码里面加入[JSPatch showDebugView]; 这句代码,就会在自己的APP界面上出现一个debug面板

《iOS开发之——JSPatch使用教程》 Snip20180809_49.png

点击可以查看详细信息

《iOS开发之——JSPatch使用教程》 Snip20180809_50.png

上图的红框就是我们的mian.js脚本,和JSPatch平台上传的一致

2.执行测试:

#import "GPViewController.h"

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor yellowColor];
    _redBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    _redBtn.backgroundColor = [UIColor redColor];
    [_redBtn addTarget:self action:@selector(redBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_redBtn];
}

- (void)redBtnClick:(id)sender {
    
}

看到我们的代码redBtnClick这个方法并没有执行任何代码

现在点击红色View看到Xcode控制台输出

2018-08-09 11:15:19.541670+0800 GSJSPatchDemo[11192:7056572] JSPatch.log: 我进来了

也就是上面的main.js 里面的代码执行了。。。

3. 后续API的使用

    原文作者:天空像天空一样蓝
    原文地址: https://www.jianshu.com/p/0fdf8506d6e0
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞