ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JSPatch defineClass实战教程:4种方式动态替换Objective-C方法,不发版修复线上Bug

JSPatch defineClass实战教程:4种方式动态替换Objective-C方法,不发版修复线上Bug JSPatch defineClass实战教程4种方式动态替换Objective-C方法不发版修复线上Bug【免费下载链接】JSPatchJSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.项目地址: https://gitcode.com/gh_mirrors/js/JSPatchJSPatch是一款轻量级的 iOS 热修复Hotfix框架它通过 Objective-C Runtime 桥接 Objective-C 与 JavaScript让你只用一个很小的引擎就能在 JS 里调用任意 OC 类与方法。其中defineClass是 JSPatch 修复线上 Bug 的核心 API无需重新打包发版只需下发一段 JS 脚本就能动态替换 Objective-C 的实例方法、类方法甚至调用原实现和父类实现当天修复线上崩溃。本教程带你从加载引擎到掌握 4 种方法替换技巧全部基于 JSPatch.js 的defineClass源码实现并配合 iOSDemo 示例 讲解。一、为什么需要 JSPatch 热修复App 上线后才发现 Crash 是 iOS 开发者的噩梦——App Store 审核周期动辄 1~2 天用户无法立刻受益。JSPatch 的思路是在 App 中集成一个极小的 JS 引擎线上通过接口下发 JS 脚本脚本利用 OC Runtime 直接改写类的 IMP方法实现相当于运行时打了一个补丁。整个机制的核心实现在引擎侧的 JPEngine.m 中JS 侧的 API 包装则在 JSPatch.js 里。二、快速上手3 步接入 JSPatch 引擎只需拷贝JSPatch/目录下的JPEngine.h、JPEngine.m、JSPatch.js三个文件到项目即可。Objective-C 侧使用步骤#import JPEngine.h // 1. 启动引擎 [JPEngine startEngine]; // 2. 执行 JS本地、Bundle 或网络下发均可 [JPEngine evaluateScript:defineClass(AppDelegate, { ... })];更多启动方式含从网络拉取脚本、执行 Bundle 内 js 文件见 README-CN.md。三、defineClass 基本语法4 个参数各代表什么JSPatch.js 第 213 行 定义了完整签名defineClass(类名:父类名, [属性数组], { 实例方法 }, { 类方法 })参数说明declaration类名支持子类 : 父类写法声明继承还可附协议properties可选以数组声明新属性自动生成 getter/setterinstMethods实例方法定义方法替换的主战场clsMethods类方法定义 注意如果只传两个参数引擎会自动把第 2 个参数当作实例方法、类方法置空见 JSPatch.js 第 215-219 行。调用 OC 类前记得先用require引入例如require(UIView, UIColor, UILabel)。四、4 种动态替换 Objective-C 方法的方式方式 1直接替换实例方法在instMethods里用方法名重写实现JSPatch 会通过class_addMethod把新 IMP 挂到类上实现见 JPEngine.m 第 1530 行。以官方 demo 为例完整代码见 demo.jsdefineClass(JPViewController, { // 用 JS 版本完全顶替 OC 中的 -handleBtn: handleBtn: function(sender) { var tableViewCtrl JPTableViewController.alloc().init() self.navigationController().pushViewController_animated(tableViewCtrl, YES) } })多参数方法用_分隔参数名如tableView_didSelectRowAtIndexPath对应 OC 的tableView:didSelectRowAtIndexPath:。方式 2ORIG 前缀调用原实现最常用JSPatch 替换方法前会先把原 IMP 复制一份、重命名为ORIG方法名见 JPEngine.m 第 1001-1004 行。因此在 JS 里就能增强式补丁先执行老逻辑再追加新逻辑。README 中的经典例子——修复 tableView 点击越界 CrashdefineClass(JPTableViewController, { tableView_didSelectRowAtIndexPath: function(tableView, indexPath) { var row indexPath.row() // 加越界判断线上 Bug 修复完成 if (self.dataSource().count() row) { var content self.dataSource().objectAtIndex(row); var ctrl JPViewController.alloc().initWithContent(content); self.navigationController().pushViewController(ctrl); } } })方式 3self.super() 调用父类实现给declaration加上父类后就能用self.super()显式调用父类方法非常适合在继承链中间插入逻辑defineClass(JPJSSuperTestA2 : JPJSSuperTestA1, { method: function() { // 先拿父类 A1 的结果再追加自己的逻辑 return self.super().method() 2 } })OC 类与 JS 类混写的继承链测试可参考 superTest.js 与 jsClassTest.js。方式 4新增属性、协议与类方法第二个参数声明属性后JSPatch 会自动为属性生成getX/setX方法见 JSPatch.js 第 221-231 行等价于给老类热插了一个属性同时可在第 3 参写协议、第 4 参写类方法。// 给 JPTableViewController 新增 data 属性并替换 dataSource defineClass(JPTableViewController : UITableViewController UIAlertViewDelegate, [data], { dataSource: function() { var data self.data(); if (data) return data; var data []; for (var i 0; i 20; i) data.push(cell from js i); self.setData(data); return data; } })以上完整示例同样来自 demo.js。五、实战一条 JS 修复越界 Crash 的全流程假设线上收到dataSource[row]数组越界崩溃定位崩溃堆栈指向JPTableViewController的didSelectRowAtIndexPath写补丁用上面方式 2重写该方法加count row判断下发服务端把脚本交给[JPEngine evaluateScript:]执行生效App 下次启动或按需重启后用户已不再崩溃——全程无发版。六、使用建议与注意事项⚠️只做增强和修复不要整类重写避免绕过原类的内存与状态逻辑需要原实现时优先用ORIG前缀而不是把老代码整段抄进 JS脚本建议做版本号校验与开关控制确保只在问题版本上生效更多 APIblock、GCD、toJS 转换等见 README-CN.md想深入机制可阅读引擎源码 JPEngine.m 与 JS 桥接层 JSPatch.js。掌握defineClass的这 4 种姿势——直接替换、ORIG 增强、super 继承、属性/协议扩展你就具备了用 JSPatch 不发版修复线上 Bug 的完整能力 【免费下载链接】JSPatchJSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.项目地址: https://gitcode.com/gh_mirrors/js/JSPatch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表