[JSPatch] 初尝JSPatch快速集成


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

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

  • HotFix概述
  • 集成JSPatch

<h3>HotFix概述</h3>

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的。


<h3>集成JSPatch</h3>

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

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


RSA 公私钥

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


RSA生成配置代码

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

添加新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设定筛选条件下发
  • 灰度下发:按人数灰度可以指定补丁对多少个用户生效,超过设置的人数后不会再生效。灰度人数可以修改增加,但不能减少,可以逐渐增加灰度人数,直到全量发布。
发布布丁

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


布丁详情

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

success

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

屏幕快照 2017-04-22 21.48.26.png

可坑能踩的坑

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

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

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,266评论 7 249
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 晚上在灯光是昏暗的,可这一点也不影响孩子去发现自然里的小生命。 在小区外围的栏杆落的枯叶上,他发现了一只蜗牛。 他...
    平平无奇小个子阅读 259评论 0 0