[JSPatch] 初尝JSPatch快速集成


JSPatch作为热更新技术的黑科技,已经不是什么前沿的新闻了,像腾讯、美团等大公司也在使用JSPatch。前段时间苹果对使用这些像JSPatch,weex等热更新技术下发警告通知或强制下架的事,技术圈里让很多小伙伴们坐不住了,闹的沸沸扬扬,这个15年就问世的框架具备很多之前的类似框架所不具备的优点,更加的小巧便捷,并且处于持续维护中,不仅如此,还由此成为了一个生态圈,bang神还为此开发了oc转js的代码转换器、可以自动提示的JSPatchX插件、以及基于这个技术的JSPatchPlatform平台。总之让大伙可以很方便的进行patch。作为技术方面的一个小探索,抱着学习的态度,初次测试一下效果。

如何混淆JSPatch热修复框架以绕过苹果的机器检测

  • HotFix概述
  • 集成JSPatch

HotFix概述

iOS中的HotFix方案总结详解

对于iOS,这种HotFix方案大致可以分为四种:

  • WaxPatch(Alibaba)
  • Dynamic Framework(Apple)
  • React Native(Facebook)
  • JSPatch(Tencent)

WaxPatch
WaxPatch是一个通过Lua语言编写的iOS框架,不仅允许用户使用 Lua 调用 iOS SDK和应用程序内部的 API, 而且使用了 OC runtime 特性调用替换应用程序内部由 OC 编写的类方法,从而达到HotFix的目的。

WaxPatch的优点在于它支持iOS6.0,同时性能上比较的优秀,但是缺点也是非常的明显,不符合Apple3.2.2的审核规则即不可动态下发可执行代码,但通过苹果JavaScriptCore.framework或WebKit执行的代码除外;同时Wax已经长期没有人维护了,导致很多OC方法不能用Lua实现,比如Wax不支持block;最后就是必须要内嵌一个Lua脚本的执行引擎才能运行Lua脚本;Wax并不支持arm64框架。


Dynamic Framework
动态的Framework,其实就是动态库;首先我介绍一下关于动态库和静态库的一些特性以及区别。

不管是静态库还是动态库,本质上都是一种可执行的二进制格式,可以被载入内存中执行。
iOS上的静态库可以分为.a文件和.framework,动态库可以分为.dylib(xcode7以后变成了.tdb)和.framework。

  • 静态库: 链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
  • 动态库: 链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要改静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。

  • 总结:同一个静态库在不同程序中使用时,每一个程序中都得导入一次,打包时也被打包进去,形成一个程序。而动态库在不同程序中,打包时并没有被打包进去,只在程序运行使用时,才链接载入(如系统的框架如UIKit、Foundation等),所以程序体积会小很多。

好,所以Dynamic Framework其实就是我们可以通过更新App所依赖的Framework方式,来实现对于Bug的HotFix,但是这个方案的缺点也是显而易见的它不符合Apple3.2.2的审核规则,使用了这种方式是上不了Apple Store的,它只能适用于一些越狱市场或者公司内部的一些项目使用,同时这种方案其实并不适用于BugFix,更适合App线上的大更新。所以其实我们项目中的引入的那些第三方的Framework都是静态库,我们可以通过file这个命令来查看我们的framework到底是属于static还是dynamic。


React Native
React Native支持用JavaScript进行开发,所以可以通过更改JS文件实现App的HotFix,但是这种方案的明显的缺点在于它只适合用于使用了React Native这种方案的应用。


JSPatch
JSPatch是只需要在项目中引入极小的JSPatch引擎,就可以使用JavaScript语言调用Objective-C的原生接口,获得脚本语言的能力:动态更新iOS APP,替换项目原生代码、快速修复bug。但是JSPatch也有它的自己的缺点,主要在由于它要依赖javascriptcore,framework,而这个framework是在iOS7.0以后才引入进来,所以JSPatch是不支持iOS6.0的,同时由于使用的是JS的脚本技术,所以在内存以及性能上面是要低于Wax的。


集成JSPatch

JSPatch 需要使用者有一个后台可以下发和管理脚本,并且需要处理传输安全等部署工作,JSPatch 平台帮你做了这些事,提供了脚本后台托管,版本管理,保证传输安全等功能,让你无需搭建一个后台,无需关心部署操作,只需引入一个 SDK 即可立即使用 JSPatch。

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

官方接入文档
注册JSPatch平台账号

1.从官网上下载提供的SDK API包来后,导入工程,在TARGETS -> Build Phases -> Link Binary With Libraries -> + 添加 libz.dylib 和 JavaScriptCore.framework
2.生成和配置RSA密钥
自定义 RSA 密钥对 RSA 密钥的作用详见安全问题。目前为了更高的安全性,平台强制要求所有补丁下发都使用自定义 RSA 密钥,生成 RSA 密钥,在 Mac 终端上执行 openssl,再执行以下三句命令,生成 PKCS8 格式的 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 -pubout -out rsa_public_key.pem

生成的公私钥,在上传布丁时要用:


[JSPatch] 初尝JSPatch快速集成_第1张图片
RSA 公私钥

用JSPatch�官网工具中提供的RSA配置工具,拖入公钥文件直接生成配置代码


[JSPatch] 初尝JSPatch快速集成_第2张图片
RSA生成配置代码

注册账号成功后,在我的App中添加新应用,应用的图标生成是填写了已上架应用的Appkey,这里只是测试,就没必要了,确定之后会生成平台应用的AppKey

[JSPatch] 初尝JSPatch快速集成_第3张图片
添加新APP

3.在 AppDelegate.m中按顺序调用 startWithAppKeysetupRSAPublicKeysync方法,可以把 [JSPatch sync] 放在 -applicationDidBecomeActive: 里,每次唤醒都能同步更新 JSPatch 补丁,不需要等用户下次启动

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    /**
     *AppKey:JSPatch添加应用时生成的AppKey
     *RSAPublicKey:刚才生成的公钥RSA字符串
     */
    [JSPatch startWithAppKey:@"834abc498b14c64b"];
    [JSPatch setupRSAPublicKey:@"-----BEGIN PUBLIC KEY-----RSABLABLABLA45/44DJFJJNKSDLKS-----END PUBLIC KEY-----"];

    //用来检测回调的状态,是更新或者是执行脚本之类的,相关信息,会打印在你的控制台
    [JSPatch setupCallback:^(JPCallbackType type, NSDictionary *data, NSError *error) {
        NSLog(@"error-->%@",error);
        switch (type) {
            case JPCallbackTypeUpdate: {
                NSLog(@"更新脚本 %@ %@", data, error);
                break;
            }
            case JPCallbackTypeRunScript: {
                NSLog(@"执行脚本 %@ %@", data, error);
                break;
            }
            case JPCallbackTypeCondition: {
                NSLog(@"条件下发 %@ %@", data, error);
                break;
            }
            case JPCallbackTypeGray: {
                NSLog(@"灰度下发 %@ %@", data, error);
                break;
            }
            default:
                break;
        }    }];
    
    [JSPatch setupDevelopment];
    [JSPatch sync];
    
    return YES;
}

4.在ViewController中创建一个laber,声明一个test方法用来给laber赋值


#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) UILabel *textLaber;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    self.textLaber = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, 60)];
    _textLaber.textAlignment = NSTextAlignmentCenter;
    _textLaber.backgroundColor = [UIColor cyanColor];
    [self.view addSubview:_textLaber];
    
    [self test];
}

- (void)test{
    self.textLaber.text = @"像疯了一样";
}

@end

5.创建main.js, 保存

console.log('run success')
defineClass("ViewController", {
            test: function() {
            self.textLaber().setText("内容就这样改变了");
            },
})

6.就是发布布丁了,布丁文件就是上面的main.js文件,RSA密钥就是生成的,**rsa_public_key.pem **公钥文件,因为只是测试,所以勾选开发预览选项,

  • 开发预览:是用来测试开发用的
  • �全量下发:给所有安装布丁的人下发
  • �条件下发:可以根据JSPatch设定的userId设定筛选条件下发
  • 灰度下发:按人数灰度可以指定补丁对多少个用户生效,超过设置的人数后不会再生效。灰度人数可以修改增加,但不能减少,可以逐渐增加灰度人数,直到全量发布。
[JSPatch] 初尝JSPatch快速集成_第4张图片
发布布丁

点击提交之后,显示发布成功


[JSPatch] 初尝JSPatch快速集成_第5张图片
布丁详情

7.再看看我们的demo,�打印台收到如下消息就说明布丁更新加载成功

[JSPatch] 初尝JSPatch快速集成_第6张图片
success

即使这样,你还会发现,laber的值并没有改变啊,好吧,因为补丁是先下载再生效的,所以下一次运行你才能看到效果,后续我会不断去踩坑,这是我们在main.js 中设的值

[JSPatch] 初尝JSPatch快速集成_第7张图片
屏幕快照 2017-04-22 21.48.26.png

可坑能踩的坑

  • 布丁脚本加载成功,却出错MD5加密之类的,当然就是你的�RSA公私钥有问题喽,重新生成一份
  • JSPatch网站上的版本要一定要和工程里的一样
  • label的名字别写错了
  • Swift一定要在方法和属性前加dynamic,如果不是继承自NSObject的Swift类不能被动态替换
  • Swift替换类和方法要比OC在类/方法名之前添加工程名
  • 如果项目跑起来控制台输出没有找到文档就是网站上配置错了

相关连接:
JSPatch 基础用法
JSPatch实现原理详解:让JS调用/替换任意OC方法

你可能感兴趣的:([JSPatch] 初尝JSPatch快速集成)