当前位置: 首页 > 科技观察

JSPatch–动态更新iOSAPP

时间:2023-03-18 19:51:20 科技观察

JSPatch是最近的一个业余项目。只需在项目中引入一个非常小的引擎,就可以使用JavaScript调用任意Objective-C原生接口,获得脚本语言的能力:动态更新APP,替换项目原生代码修复bug。你是否有过这样的经历:新版本上线后,发现一个严重的bug,可能导致崩溃率急剧上升,并且可能无法发送网络请求。这时候,你能做的就是快速修复bug提交等待AppStore漫长的审核,然后希望用户快速升级,付出巨大的人力和时间成本来完成这个bug的修复.使用JSPatch可以解决此类问题。只需在项目中引入JSPatch,当发现bug时,可以下发JS脚本补丁替换native方法,无需更新APP即可立即修复bug。示例12345678910@implementationJPTableViewController...-(void)tableView:(UITableView*)tableViewdidSelectRowAtIndexPath:(NSIndexPath*)indexPath{NSString*content=self.dataSource[[indexPathrow]];//可能会超出数组范围导致crashJPViewController*ctrl=[[JPViewControlleralloc]initWithContent:content];[self.navigationControllerpushViewController:ctrl];}...@end上面的代码可能会超出数组的范围而导致崩溃。如果项目中引用了JSPatch,可以发送JS脚本修复此bug:123456789101112131415#import“JPEngine.m”@implementationAppDelegate-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{[JPEnginestartEngine];[NSURLConnectionsendAsynchronousRequest:[NSURLRequestrequestWithURL:[NSURURRLWithString:@"http://cnbang.net/bugfix.JS"]]queue:[NSOperationQueuemainQueue]completionNSHandler:^(response,NSData*data,NSError*connectionError){NSString*script=[[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];如果(脚本){[JPEngineevaluateScript:脚本];}}];....返回是;}@end123456789101112//JSdefineClass("JPTableViewController",{//instancemethoddefinitionstableView_didSelectRowAtIndexPath:function(tableView,indexPath){varrow=indexPath.row()if(self.dataSource(.length>row){//增加判断越界的逻辑varcontent=self.dataArr()[row];varctrl=JPViewController.alloc().initWithContent(content);self.navigationController().pushViewController(ctrl);}}},{})这样JPTableViewController中的-tableView:didSelectRowAtIndexPath:就被这个JS替换了脚本中的实现在用户不知情的情况下修复了这个错误。更多文档和demo请参考github项目主页。#p#原理JSPatch使用iOS内置的JavaScriptCore.framework作为JS引擎,但没有使用其JSExport特性进行JS-OC函数互调,而是通过Objective-C传递JS要调用的类名和函数名RuntimeObjective-C,然后使用NSInvocation动态调用对应的OC方法。详细的实现原理和实现过程中遇到的各种坑hack方法会在另一篇文章中介绍。方案对比目前有一些方案可以实现动态补丁,比如WaxPatch,可以使用Lua调用OC方法。与WaxPatch相比,JSPatch的优势在于:1.JS语言JS在应用程序开发领域比Lua具有更广泛的应用范围。目前前端开发和终端开发趋于融合。JS作为一种扩展的脚本语言,是最好的选择。2.遵守Apple的规则JSPatch更符合Apple的规则。iOSDeveloperProgramLicenseAgreement3.3.2提到不能动态交付可执行代码,除了通过Apple的JavaScriptCore.framework或WebKit执行的代码,JS是通过JavaScriptCore.framework执行的。3.小巧玲珑使用系统内置的JavaScriptCore.framework,无需嵌入脚本引擎,体积小巧。4.支持块蜡。blockwax的开发和维护几年前就停止了,不支持Objective-C和Lua程序中block之间的相互传递。虽然有一些第三方实现了block,但是在使用的时候对参数的限制比较多。与WaxPatch相比,JSPatch的缺点是不支持iOS6,因为需要引入JavaScriptCore.framework。另外,目前内存占用会比wax高,持续改进中。RiskJSPatch允许脚本语言获得调用所有原生OC方法的能力。不像web前端限制浏览器的能力,在使用中会存在一些安全隐患:1.如果在网络传输过程中下载文本JS,可能会被中间人抓到篡改JS脚本,执行任意方法,并窃取APP内的相关信息。传输过程可以加密,也可以直接使用https解决。2、如果下载的JS没有加密保存在本地,用户也可以在未越狱的机器上手动替换或篡改脚本。这一点危害没有黑客大,因为运营商是手机的主人,不存在APP内相关信息被窃取的风险。为防止用户修改代码影响APP运行,可以选择简单加密存储。对于其他用途,JSPatch可以动态打补丁,可以自由修改APP中的代码。理论上一个业务模块甚至整个APP完全可以用JSPatch来实现,就像wax一样,但是不推荐这样做,因为:JSPatch和wax都是通过Objective-CRuntime的接口使用字符串反射找到对应的类和调用方法。中间的字符串处理会消耗一定的性能,另外两种语言之间的类型转换也有性能损耗。如果用来做一个完整的业务模块,大量频繁的来回互调,可能会有性能问题。在开发过程中,需要用OC的思维来写JS/Lua,这样就失去了脚本语言本身的特性。JSPatch和wax都没有IDE支持,开发效率低。如果要给APP动态添加模块,ReactNative目前提供了很好的解决方案来解决以上三个问题:JS/OC不会频繁通信,事件触发时会批量调用,提高效率。(详见ReactNative通信机制详解)开发过程无需考虑OC的感受,只需要按照React框架的思路进行纯JS开发,剩下的交给ReactNative来处理。ReactNative甚至有一个IDE就绪。所以动态添加业务模块还是推荐尝试ReactNative,但是ReactNative不提供原生OC接口的反射调用和方法替换,无法修改原生代码。JSPatch以紧凑的引擎填补了这一空白,并与ReactNative配合使用。先进的JS语言,让原生APP时刻处于可扩展、可修改的状态。目前JSPatch处于开发阶段,在稳定性和功能上还存在一些问题。我们欢迎您的建议/错误/PR共同致力于这个项目。版权声明:本文微信公众平台发布权已由指定公众号:iOSDevelopment(iOSDevTips)“独家代理”。