更新完毕
iOS App审核是所有iOS开发者心中的一座山,漫长的等待时间如果在正常的版本更新时还好,但是在线上出现严重BUG时,没一分每一秒对我们来说都是一种煎熬,面对这样的问题,难道腾讯,阿里都跟我们一样吗?
当然不是
看看他们的解决方案:
1、微信为代表的JSPatch:https://github.com/bang590/JSPatch
2、阿里为代表的Wax:https://github.com/alibaba/wax
好几次App刚刚审核通过,却发现其中有致命的BUG,修改的话可能就是一两行代码就能搞定,但是苹果的审核时间让你起码几天面对这个BUG提心吊胆,对于饱受这份折磨的我来说,JSPatch简直就是救世主,话不多说,看都有谁在用这个:图片源自http://using.jspatch.org/ 【JSPatch使用统计社区】
这些大厂都在用着一套可以实现hit code push的解决方案
让我们来认识一下JSPatch吧,原作者博客地址:
http://blog.cnbang.net/
JSPatch原理
JSPatch的基本原理就是通过JS代码,利用OC运行时的特性,已达到修改程序代码,让App具备hit code push的能力,更详细的原理可以去看上面原作者的博客,里面非常详细的讲解了JSPatch的底层实现。
JS文件通过从服务器下载到本地,所有使用时需要服务器的一定配合。
JSPatch的两个安全问题
1、传输安全:JS 脚本可以调用任意 OC 方法,权限非常大,若被中间人攻击替换代码,会造成较大的危害。
2、执行安全:下发的 JS 脚本灵活度大,相当于一次小型更新,若未进行充分测试,可能会出现 crash 等情况对 APP 稳定性造成影响。
所以,使用时对js文件的内容进行加密是必须的
JSPatch的使用
先去GitHub上下载源码,加入到工程中
JSPatch经过作者的多次优化,在不断完善的过程中还是保持了极小的代码量,只有一千多行 OC 和接近两百行 JS(PS:再次膜拜一下大神)
这里使用到了JavaScriptcore核心库,所以还需要在General的Linded Framework and Libraries添加JavaScriptcore.framework
首先在AppDelegate中添加JPEngine.h
的头文件
然后添加下面两个方法:
// Library/Caches
define FilePath ([[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil])
/**
- 下载JSPatch
*/
-(void)loadJSPatch
{
//使用AFNetWork下载在服务器的js文件
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:@"http://blog.methodname.com/content/test.js"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response)
{
NSURL *documentsDirectoryURL = FilePath;
//保存到本地 Library/Caches目录下
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
}
completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error)
{
NSLog(@"File downloaded to: %@", filePath);
}];
[downloadTask resume];
}
/**
-
运行下载的JS文件
*/
-(void)HSDevaluateScript
{
//从本地获取下载的JS文件
NSURL *p = FilePath;
//获取内容
NSString *js = [NSString stringWithContentsOfFile:[p.path stringByAppendingString:@"/test.js"] encoding:NSUTF8StringEncoding error:nil];
//如果有内容
if (js.length > 0)
{
//-------
//在此处解密js内容
//----
//运行
[JPEngine startEngine];
[JPEngine evaluateScript:js];
}
}
//还是在AppDelegate中下面的两个方法内,进行下载服务器的js文件和运行下载后的js文件
//加载配置
-
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//可以在这里设置一个条件,比如隔多久才去请求一次服务器看看有没有可以下载的文件
//以防止频繁请求
[self loadJSPatch];
return YES;
}
//应用程序进入活动状态时
(void)applicationDidBecomeActive:(UIApplication *)application
{
[self HSDevaluateScript];
}
以上在客户端的配置就完成了
然后就是最关键的,如何使用js来完成调用,替换,覆盖原来的代码
JSPatch OC-JS自动转换工具:https://github.com/bang590/JSPatchConvertor
如果不想去记它的语法,完全可以用这个工具来进行OC,JS的转换,工具也是原作者写的(PS:再次膜拜大神,虽然有些语法上的瑕疵,具体请看github上的wiki)
//在MainViewController的viewDidLoad方法中将self.view的背景颜色改为橙色
//-------OC代码
@implementation MainViewController
-(void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor orangeColor]];
}
//------转换后的JS代码require('UIColor,UIViewController');//这里少了个UIViewController加上就好
defineClass('MainViewController', {
viewDidLoad: function() {
super.viewDidLoad();
self.view().setBackgroundColor(UIColor.orangeColor());
},
});
将这个文件,放在服务器上面,最好进行版本分类,这样在App下载的时候,就能根据当前的版本号来进行对应目录下的文件的下载例如:
AppName-->2.1-->jspatch.js
AppName-->2.2-->jspatch.js
AppName-->2.3-->jspatch.js
这样就能在App上根据目录:AppName(当前App版本号)\jspatch.js 这样的方式去下载对应版本的js文件了
注意事项:
引用某位使用过JSPatch大神博客里最后的话 http://www.cnblogs.com/dsxniubility/p/5080875.html
1、接入了JSPatch之后,iOS的线上BUG 看上去就不向以前那样“猛如虎”了,但是这仅仅是一个紧急预案措施,以前规范的流程还是需要遵守。
2、每一次本版本用JSPatch解决的线上Bug,下个版本必须用OC代码写入项目中,不能允许补丁代码的存留超过一个版本。
3、倡导使用敏捷开发的思想,类似于主逻辑或者是功能模块入口的方法可以抽的更细,这样即使需要修改,成本也不会太大,作者本人也提到,如果有一行代码必须要在一个大方法的中间进行修改,那我也没办法了,你只能把这整个方法都用js写一遍了,所以才设置了JSPatchConvertor。
4、每次用JSPatch解决掉的线上BUG 应当有一个专门的文档记录,遇到重复错误必须写casestudy。
5、具体的使用请查看github上的wiki JSPatch wiki
最后:放上JSPatch的官网
目前jspatch的作者已经将jspatch商业化,并提供了完善的版本控制,脚本下发SDK,集成到APP中也只需要一行代码。
JSPatch