JSPatch 可以讓你用 JavaScript 書寫原生 iOS APP删铃。只需在項(xiàng)目引入極小的引擎诫隅,就可以使用 JavaScript 調(diào)用任何 Objective-C 的原生接口削樊,替換項(xiàng)目原生代碼動(dòng)態(tài)修復(fù) bug甸箱。
1.接入流程
JSPatch github地址:https://github.com/bang590/JSPatch
- 拷貝
JSPatch/
目錄下的三個(gè)文件JSEngine.m
/JSEngine.h
/JSPatch.js
到項(xiàng)目。// JSpatch 核心類 - 拷貝
Loader
文件夾到項(xiàng)目肯适。// JSpatch 安全管理類 - 拷貝
Extensions/
目錄下的JPCleaner.h
/JPCleaner.m
文件到項(xiàng)目框舔。// JSpatch 擴(kuò)展的清除js的類 - 在
General
的LinkFrameworks and Libraries
里面 添加javascriptcore.framework
//這個(gè)庫里主要用于js與oc語言的橋接停士,比如一些數(shù)據(jù)類型間的相互轉(zhuǎn)化。
2.本地測試
編寫main.js文件
- 用原生代碼編寫修復(fù)bug的代碼薄辅,之后可以使用
JSPatch Convertor
自動(dòng)把 Objective-C 代碼轉(zhuǎn)為 JavaScript 代碼要拂,然后把生成代碼寫入main.js
文件中,根據(jù)作者給的js語法進(jìn)行一行行review长搀。
- 導(dǎo)入
JSPactch X
插件手寫js
代碼宇弛。
測試main.js文件
- 把
main.js
文件導(dǎo)入項(xiàng)目Resource/
目錄下。 - 在
didFinishLaunchingWithOptions:
方法中調(diào)用[JPLoader runTestScriptInBundle];
方法源请。 - 如果bug未修復(fù)需要在
main.js
中進(jìn)行斷點(diǎn)調(diào)試或者使用console.log("xxx");
進(jìn)行調(diào)試直到bug修復(fù)完成枪芒。
斷點(diǎn)調(diào)試說明
- 首先需要開啟
Safari
調(diào)試菜單:Safari
->偏好設(shè)置
->高級
-> 勾選在菜單欄中顯示“開發(fā)”菜單
- 接著啟動(dòng)APP ->
Safari
->開發(fā)
-> 選擇你的機(jī)器 ->JSContext
即可開始調(diào)試。 - 連接真機(jī)調(diào)試時(shí)谁尸,需要打開真機(jī)的web檢查器:
設(shè)置
->Safari
->高級
->Web檢查器
舅踪。
3.生成RSA密鑰
命令行依次寫入
openssl genrsa -out rsatest_private_key.pem 1024
pkcs8 -topk8 -inform PEM -in rsatest_private_key.pem -outform PEM –nocrypt
rsa -in rsatest_private_key.pem -pubout -out rsatest_public_key.pem
會(huì)在本地當(dāng)前用戶的目錄下生成連個(gè)文件如下:
配置
- 文本形式打開
rsatest_public_key.pem
替換JPLoader.h
里的publicKey
。 - 打開
rsatest_private_key.pem
替換tools/pack.php
里的privateKey
良蛮。 - 設(shè)
JPLoader.h
的rootUrl
為你的服務(wù)器地址抽碌。
腳本打包
- 取出
tools
內(nèi)含pack.php
的文件夾放在桌面(其他地方也行)。 - 把測試成功的
main.js
文件放入tools
文件夾决瞳。 - 通過命令行
cd
命令到此文件夾货徙。 - 敲入命令
packer.php main.js
,文件夾下會(huì)生成一個(gè)v1.zip
的包皮胡。 - 腳本打包后的文件存放在服務(wù)器的路徑:
${rootUrl}/${appVersion}/${patchFile}
痴颊。
4.后臺(tái)請求測試
- 在
didFinishLaunchingWithOptions:
方法中調(diào)用[JPLoader run];
方法。 - 在
applicationDidBecomeActive:
方法中調(diào)用[JPLoader updateToVersion:1 callback:nil];
方法屡贺。
5.添加容錯(cuò)
崩潰x次 清除本地js文件 取消加載
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSInteger crashInteger = [[NSUserDefaults standardUserDefaults] integerForKey:@"loadPatchCrash"];
if (crashInteger < 2) { // 加載patch 崩潰2次 取消加載
crashInteger++;
[[NSUserDefaults standardUserDefaults] setInteger:crashInteger forKey:@"loadPatchCrash"];
[[NSUserDefaults standardUserDefaults] synchronize];
[JPLoader run];
crashInteger--;
[[NSUserDefaults standardUserDefaults] setInteger:crashInteger forKey:@"loadPatchCrash"];
[[NSUserDefaults standardUserDefaults] synchronize];
}else {
// 2次 刪除本地 patch 文件
[JPCleaner cleanAll];
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"loadPatchCrash"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
間隔xxx秒去請求腳步(或者后臺(tái)返回腳本的版本號判斷緩存)
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// JSPatch請求時(shí)間間隔的判斷
NSDate *lastRequestTime = [[NSUserDefaults standardUserDefaults] objectForKey:@"jp_request_time"];
//下載補(bǔ)丁包得請求
void(^timeInterval)() = ^ {
[JPLoader updateToVersion:1 callback:nil];
// 將當(dāng)前時(shí)間寫入沙盒
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"jp_request_time"];
[[NSUserDefaults standardUserDefaults] synchronize];
};
// 判斷
if (lastRequestTime) {
NSTimeInterval between = [lastRequestTime timeIntervalSinceNow];
if (between > 3600) {
timeInterval();
}else return;
}else {
timeInterval();
}
}