登陆官网申请权限,开通HotFix支持。
一、进入HotFix后台,配置好后台数据。
二、找到iOS的SDK,下载两个framework拖进项目:
AliHotFix.framework
AliHotFixDebug.framework
注意: 在上线之前的Release模式下要把AliHotFixDebug.framework移除,此framework仅用于调试扫码的时候使用,本文接下来会讲解。
记得打开Capabilities里面的keychain sharing
经阿里技术团队解答知道:若使用 XCode8 接入,需要在项目 Capabilities 打开 Keychain Sharing 开关,否则在模拟器下载脚本后会出现 decompress error, md5 didn't match 错误(真机无论是否打开都没问题)这个选项是为了在模拟器下对patch的验签能通过。
iOS的keychain提供一种安全保存信息的方式,可以保存密码等数据,而且keychain中的数据不会因为你删除app而丢失,你可以在重新安装后继续读取keychain中的数据。
三、必须要使用CocoaPods 集成 SDK 所需依赖,安装完成之后在项目目录下执行pod init命令,然后在项目文件夹下创建的podfile文件中添加如下内容:
source 'https://github.com/CocoaPods/Specs.git'
source 'http://repo.baichuan-ios.taobao.com/baichuanSDK/AliBCSpecs.git'
platform :ios, '7.0'
inhibit_all_warnings!
target ‘项目名称***’ do
pod 'BCUserTrack'
pod 'ZipArchive', '~> 1.4.0'
pod 'wax', :git => 'https://github.com/alibaba/wax.git'
end
(关于集成pod如果遇到坑,可留言咨询)
后台配置成功之后,你已经获得了三个参数App ID、App Secret和RSA密钥,接下来我们看代码:
#import
//代码取自官方demo,最好都写在AppDelegate里的这个方法中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//加解密补丁文件的密钥(该密钥已加密)
char aesEncryptKeyBytes[] = {-106,0,-127,-95,-109,-44,-87,84,110,6,-108,-74,-58,-115,37,1,-52,-96,-102,70,-112,73,126,113,-82,120,-72,75,31,-87,-126,75};
NSData *aesEncryptKeyData = [NSData dataWithBytes:aesEncryptKeyBytes length:sizeof(aesEncryptKeyBytes)];
//本地自签名证书RSA公钥
char rsaPublicDerBytes[]={48,-126,2,1,48,-126,1,106,2,9,0,-79,22,-42,-112,86,-37,19,-31,48,13,6,9,42,-122,72,-122,-9,13,1,1,5,5,0,48,69,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,19,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,19,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,48,30,23,13,49,54,49,48,51,49,48,56,51,53,48,51,90,23,13,50,54,49,48,50,57,48,56,51,53,48,51,90,48,69,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,19,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,19,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,48,-127,-97,48,13,6,9,42,-122,72,-122,-9,13,1,1,1,5,0,3,-127,-115,0,48,-127,-119,2,-127,-127,0,-42,18,-126,-97,-3,105,-91,72,24,-128,-121,-53,-39,-111,-65,-128,114,101,109,52,-26,-65,-18,-42,-88,13,77,-86,-118,77,-12,42,5,-14,-100,43,-104,-74,-84,39,-51,-81,-48,16,-28,25,-66,66,29,60,-17,-115,-62,30,-19,-120,-127,72,115,59,126,-83,90,87,119,-125,24,75,-65,-85,-118,-59,89,37,51,-121,4,-95,88,-77,-108,-7,5,-32,115,61,-119,14,44,-90,-40,98,-123,96,-53,-38,-101,-128,-72,78,3,-122,-14,-40,-107,-77,-45,12,81,-78,99,-86,-3,22,-97,95,-54,-24,-96,0,14,-2,-57,-25,-2,-81,51,79,2,3,1,0,1,48,13,6,9,42,-122,72,-122,-9,13,1,1,5,5,0,3,-127,-127,0,-64,-63,-100,-76,-35,115,73,-28,40,-63,126,39,-91,109,48,47,19,113,11,60,85,24,75,123,-81,-41,90,37,-59,-82,-3,115,122,-95,-98,-84,-60,8,-12,36,124,-25,14,105,-108,-108,96,-44,-40,-126,-118,7,57,114,-53,-125,5,-125,111,53,-38,-57,80,-19,14,126,-76,-42,64,-31,52,-21,-121,-100,-109,-53,42,-9,-92,18,-94,-19,-49,55,62,-106,127,23,-23,68,-67,26,-1,39,-29,78,-63,-14,118,-11,-94,61,-67,62,-89,-107,-54,-24,31,86,-47,-63,-28,59,-116,62,48,-112,47,101,-3,114,-13,79,13,4,79,11};
NSData *rsaPublicDerData = [NSData dataWithBytes:rsaPublicDerBytes length:sizeof(rsaPublicDerBytes)];
//App Secret
NSString * secret = @"0826092cd0903caf20815f69578856be";
//RSA密钥
NSString * privateKey = @"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCR5mTRZibau72o0SKBmQisFJ98kZwbAT7XbgfMEU4iIKvzRK/87R220or5LtARnKL7XExBMte6GKHI5PSY0gB6tES8Gp155jf7vWGAls2yXfrKxz2AIiwy2jplCBzCH0GlFbhiFbAkW8OwHlHi9rdpQN3lxmq+1qRDjZGN0heED1npg9BObVHf+7ygEAwyrFvDSnBTfzONZUxZwyz9HynLCbhHWqi8vZacJNS+CVTuymHEa7hbSQyUbOb+QTvJyoovP+L9IkpVhdG1mMRFJf9ex9dV9OTOmZXR29MJVsyZmS3YgHoXtphvClXJ8uaXX6ngfFLQgV/6nss2buxz2O6ZAgMBAAECggEAIZCUXwwWIjoQrta2DoSLVzNDYaAJ/rhxoZQBnTPZ+sXzaPrDVfei311edWcMnRCg+hzIujMdKAXkqlfp4YJmc9Qm//NLiTCqbnKqDLAk0EUInj/p6SFzc5t61aVhIFOagYUWrxH4PNUTlt/SzNkfZspyghr8kbzFe3kFJFBR8qJP+YN+EDunDc/ihb7Z6vmApi7vbNlebKoZZnMs0LhlNxm5xmrOUvezScQ8wjT2bNlAO6nAGPj84fAARmZndeS8D0m7tv3jwKZNlkYt+MKUEdKSaeEx6FBAseBVhavBs9LwRWwekY+SvgN/jRXq0BCuPkUVcD9qDuDFLCaXInN+BQKBgQDYc1ffbuMpAtXCznMG+XCwbSHbQ5s6UFKoaUaymnCinxAvH6Zvw2K6BwqkWmwao4QvJcnfkhlsErc46Xc6fqgF0ywc60wE0XHA7HcCtzJO5DP/6NybAFOaRzq2vwfdqFSuTVelrQAbeAkngnbA8K4XSqYP6Qz81V3Wr7jUF8G7zwKBgQCsjvzdKicHRUAvwII3Kcqkoo5ulxW4CWUxkrc0pwVLXI3alhyiSOdLd7gFhnpS9+1kvp8zu5nabM9VGg7krY/MRHqvurRz5RB6l5bxxv5jrHgpMRiQR2+30zda+n/7FwTkMST+FwkSQXSmF/w+AAOyfZoF5CEQTCx1xoqSZAbBFwKBgQCnzSvHfNjAd4EuiAxm0MRLEh/YM15I4/Jgu1Tiq5Y8jGHolnnaVTfZjhHy/mKmeDPGtV3+Y+4veYbvqRcUkxJBice+F7AUYCb28JsG0O1AeevSLj2wMJ2fki7zc79uWMxlYHJdb3QQ14sJRTw5MZ1VUzrQRNUbwXIBOLNqQYygwwKBgFOiagR3rbrkYZvDXlmGM+VftFD9gVVVmGpSheFLIlHIZiiPoQk29IOrXtGuwBL+f1zY1yinwIYRPtwsaROE27FRb3VEtLmHSFlip5I/tIRyzzqHxTQIq6kZAjdiOi1klsZS228bkxX6C6OE9IjIUQJtxf0c+LmBcfsTY45YVL25AoGAM3leDbpcITvQpqanctpVybhkUUgrhXDFYjx/w+QmNuu8eQ9jR8lDsUtihyu3ssPu2g+ieYaoeybPXAC26kb5Y0j+t5A4JINxisNXdJtrplbJgaC7QgN0FmEDnPmTXY0tvRGwX2zL9kOMvogfyvF9DR2CaUyq1JkcJFGhhrM5mdw=";
// 百川平台申请的appid,secret,rsaKey.以及本地打包自签证书的RSA公钥&本地加密patch密钥
[AliHotFix startWithAppID:@"76547-2" secret:secret privateKey:privateKey publicKey:rsaPublicDerData encryptAESKey:aesEncryptKeyData];
return YES;
}
//在程序每一次重新进入前台激活时,同步补丁。
- (void)applicationDidBecomeActive:(UIApplication *)application {
[AliHotFix sync];
}
还差rsaPublicDerData(本地自签名证书RSA公钥)和aesEncryptKeyData(加解密补丁文件的密钥)两个参数。
接下来要特别谨慎对待了,下载打包工具到桌面,现在你的桌面有个tools文件夹,里面有三个文件
打开终端
第一步:1、cd到tools文件夹;2、终端输入AliHotFixCommand的路径你会得到:
第二步:我们首先进行上图中的第2步,即:
终端输入AliHotFixCommand的路径 -generateRSAKey
会得到
这是让你输入各种信息,可以直接一直回车,直到输入密码阶段,连续输入两个自定义的密码( 想一个复杂点的密码,一定要记住你输入的密码,不要泄露,在此阶段的第3步会用到这个密码,以后的补丁文件也会持续用到,先规定为“密码一”)
你的tools文件夹也会变成这样:
意思就是生成了本地自签名证书.p12和.der
然后,我们进行图片(AliHotFixCommand.png)中的第1步(对建立的Patch目录进行加密打包):
在tools文件夹中创建如图的目录结构
( 备注:在src目录下的lua补丁文件支持多目录多文件,patch/lib(非必须目录) 存放src目录下lua代码所需的公共类或工具类代码)
( 备注:js补丁文件必须放在patch/src目录下,只支持单个js补丁文件且文件必须命名为main.js)
不管是lua还是js,src文件夹里面存放的都是补丁代码,测试的时候可以什么都不放。也可以在放一个弹窗方法调用,这里有个lua的代码,方便大家用来测试
//测试代码
- (void) showHotFix{
UIAlertView *ceshiview = [[UIAlertView alloc]initWithTitle:@"HotFix" message:@"测试HotFix" delegate:nil cancelButtonTitle:@"OK " otherButtonTitles:nil, nil];
[ceshiview show];
}
//lua代码
waxClass{"AViewController"}
function showHotFix(self)
local ceshiview = UIAlertView:initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles("HotFix","测试HotFix修复后的detail是否改变",nil,"OK ",nil)
ceshiview:show()
end
解释一下:waxClass{"AViewController"}指的是AViewController里面的方法,起到定位修改内容的作用,官方文档有个转换工具,可以把OC代码转换为js或者lua的代码点我查看,个人觉得很坑,转换后一定要仔细检查一遍,转换的语法往往会有错误,一定要仔细检查。
这里我改变了UIAlertView里message内容,如果message内容改变,也就证明HotFix是work的。还有一点,如果HotFix是work的,也不会走showHotFix方法,可打断点测试。所以我们应该知道,如果修改一个方法中的某一点内容,需要把整个方法的代码都打包成补丁上传后台。
可见写代码的时候分块创建是很有必要的。
打开终端,输入命令格式:
COMMAND-PATH –pack PATCH-DIRECTORY APP-VERSION ENCRYPT-KEY PRIVATE-P12-FILE-PASSWORD
参数说明:
COMMAND-PATH: AliHotFixCommand所在路径
PATCH-DIRECTORY:patch包所在路径
APP-VERSION:patch绑定的app版本
ENCRYPT-KEY:加密patch文件的密钥(备注:长度不超过32位字符串,自定义的密码,我们这里成为“密码二”)
PRIVATE-P12-FILE-PASSWORD:生成RSA密钥时输入的密码(刚才的“密码一”)
你会得到如图的patch.zip的补丁包。
在阿里HotFix后台点击上传补丁。
问题:上传了但还没发布的补丁怎么删啊?
答:补丁不允许删除的,只允许上传新补丁去覆盖,永远加载同一个版本中最新的补丁。
上传成功后点击“查看详情”,会看到一个二维码,就是我们开始提到的
AliHotFixDebug.framework的作用,真机打开项目会打开摄像头,扫面这个二维码就可以测试patch包是否是work的。
别急着测试,还有第3步(获取运行patch需要的密钥参数):
打开终端
命令格式: COMMAND-PATH –encryptKey ENCRYPT-KEY
参数说明:
COMMAND-PATH: AliHotFixCommand所在路径
ENCRYPT-KEY:加密文件密钥(备注:要与打包命令输入的相一致,也就是我们之前的“密码二”)
那么在终端中会获得如下代码:
char aesEncryptKeyBytes[] = {xxxx};
//加密过后的aesKey二进制流格式
NSData *aesEncryptKeyData = [NSData dataWithBytes:aesEncryptKeyBytes length:sizeof(aesEncryptKeyBytes)];
char rsaPublicDerBytes[]={xxxx};
// 本地自签名公钥二进制流格式
NSData *rsaPublicDerData = [NSData dataWithBytes:rsaPublicDerBytes length:sizeof(rsaPublicDerBytes)];
就是在AppDelegate里还缺少的两个参数:rsaPublicDerData(本地自签名证书RSA公钥)和aesEncryptKeyData(加解密补丁文件的密钥)。
最后确认一下你要测试的是哪个view或者哪个controller的代码,在那个view或者controller里
#import
[AliHotFixDebug showDebug:self];
当进入的时候就会立刻打开摄像头,就可以扫码测试了。
扫码错误:Patch run error: 未能完成操作。(“”错误 -9809。).
答:打包用的自签名证书和集成到app的自签名证书不匹配,建议重新走一遍流程,细心点。
如果patch补丁包成功,扫码会提示:Load patch success.
如果提示Load patch success. 但补丁未生效,个人经验有两个原因:
1、你的lua代码或者js代码语法有问题。
2、可能是你前后用的自定义签名证书不一致,建议重新走一遍流程。
相关说明(此说明参考自梁炯幸)
1、所修改的目标方法,必须在方法调用之前已把补丁加载完毕,然后在方法调用时才会生效。
2、补丁的下载是异步的,不会阻塞当前线程。补丁的下载受网络环境影响。
3、加载过的补丁将会存在于App沙盒,App每一次启动都会加载它,即使断网。App在同步补丁时发现没有更高版本的补丁时,会继续使用本地存放的补丁。所以在百川控制台停用了所有补丁后,App再去同步补丁,依然等同于没有更高版本补丁,并不会删除本地补丁。
OK,整个阿里HotFix的流程就结束了。
目前阿里HotFix是免费的,内部说今天想实行一元购的活动,但为了用户体验还是放弃了,等到几个版本的迭代之后阿里HotFix就会收费,现在尝试学习一下阿里HotFix的接入还是比较好的。
另外,整个过程要多谢陈老板的帮助。
个人对于js(具体的编写方法参考JSPatch基础用法)和lua的语法不是很熟悉,还需要继续深入学习才能准确的使用HotFix线上修复bug。个人比较倾向于lua,不知此观点是否正确,有关于lua的书籍和文章,还请大家不吝赐教,积极分享,共同学习。