17/03/08更新
有不少小伙伴反應蘋果發(fā)送了郵件要求去除項目中用于動態(tài)改變應用的代碼 ,看來 JSPatch 要被禁止使用了
Your app, extension, and/or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval, which is not in compliance with section 3.3.2 of the Apple Developer Program License Agreement and App Store Review Guideline 2.5.2. This code, combined with a remote resource, can facilitate significant changes to your app’s behavior compared to when it was initially reviewed for the App Store. While you may not be using this functionality currently, it has the potential to load private frameworks, private methods, and enable future feature changes.
This includes any code which passes arbitrary parameters to dynamic methods such as dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(), and running remote scripts in order to change app behavior or call SPI, based on the contents of the downloaded script. Even if the remote resource is not intentionally malicious, it could easily be hijacked via a Man In The Middle (MiTM) attack, which can pose a serious security vulnerability to users of your app.
Please perform an in-depth review of your app and remove any code, frameworks, or SDKs that fall in line with the functionality described above before submitting the next update for your app for review.
Best regards,
App Store Review
JSPatch 平臺關于蘋果警告的解決方案 --bang
前言
App 上線后可能存在測試時未發(fā)現(xiàn)的 bug,影響用戶使用送悔,利用 JSPatch 在 App 不進行版本迭代的情況下進行 bug 修復。
什么是 JSPatch 持际?
JSPatch 是一個開源項目(Github鏈接),只需要在項目里引入極小的引擎文件哗咆,就可以使用 JavaScript 調用任何 Objective-C 的原生接口蜘欲,替換任意 Objective-C 原生方法。目前主要用于下發(fā) JS 腳本替換原生 Objective-C 代碼晌柬,實時修復線上 bug姥份。
除了修復 bug,JSPatch 也可以用于動態(tài)運營年碘,實時修改線上 APP 行為澈歉,或動態(tài)添加功能。
什么是 JSPatch 平臺屿衅?
JSPatch 需要使用者有一個后臺可以下發(fā)和管理腳本埃难,并且需要處理傳輸安全等部署工作,JSPatch 平臺幫你做了這些事傲诵,提供了腳本后臺托管凯砍,版本管理箱硕,保證傳輸安全等功能拴竹,讓你無需搭建一個后臺,無需關心部署操作剧罩,只需引入一個 SDK 即可立即使用 JSPatch栓拜。
引用自 JSPatch 的官方文檔(文檔鏈接),下面講一下 JSPatch 的使用。
JSPatch 使用
新建一個項目
然后在 ViewController.m 中寫一段會造成崩潰的代碼(這里只是參考)
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic , strong) NSArray *arr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@" , self.arr[2]);
}
- (NSArray *)arr {
if (!_arr) {
_arr = [NSArray array];
}
return _arr;
}
集成 SDK
1幕与、通過 cocoapods 導入
在 podfile 中添加命令:
pod 'JSPatchPlatform', :git => 'https://github.com/bang590/JSPatchPlatform.git'
再執(zhí)行 pod install
即可挑势。
2、手動導入
下載 SDK 后解壓啦鸣,將** JSPatchPlatform.framework** 拖入項目中潮饱,勾選 "Copy items if needed",并確保 "Add to targets" 勾選了相應的 target诫给。
pods 導入或手動導入SDK后添加依賴框架:TARGETS -> Build Phases -> Link Binary With Libraries -> + 添加libz.dylib(Xcode7之后是libz.tbd)和 JavaScriptCore.framework香拉。
測試使用
1、測試本地腳本
本地測試 AppDelegate.m 按如下寫法即可中狂,SDK 提供了+testScriptInBundle
方法用于開發(fā)狀態(tài)下測試凫碌。
#import "AppDelegate.h"
// 引入頭文件
#import <JSPatchPlatform/JSPatch.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/*
用于發(fā)布前測試腳本。先把腳本放入項目中胃榕,調用后盛险,會在當前項目的 bundle 里尋找 main.js 文件執(zhí)行
測試完成后請刪除,改為調用 +startWithAppKey: 和 +sync
*/
[JSPatch testScriptInBundle];
return YES;
}
然后在我們的 demo 中新建一個 empty 文件勋又,叫 main.js苦掘,注意這是 JSPatch 平臺規(guī)范,js 腳本文件名必須是 main.js赐写。
完成之后是這樣
現(xiàn)在我們就可以通過在 main.js 寫 js 修復 demo 中的 bug鸟蜡,代碼如下:
require('NSArray');
defineClass('ViewController', {
viewDidLoad: function() {
self.super().viewDidLoad();
self.setArr(["1","2","阿西吧","3"]);
var str = self.arr().objectAtIndex(2);
console.log("JSPatch調用" , str);
},
});
運行,OK
2挺邀、線上版本測試
熱修復針對的是線上版本揉忘,所以本地測試只是驗證可行性,重要的還是線上 bug 的修復端铛。下面我們進行線上測試泣矛。
到 JSPatch官網(wǎng) 注冊,登錄禾蚕,我的 App您朽,添加 App,獲取 app key换淆,添加 App 版本哗总,發(fā)布補丁
提交之后點進去就可以進行補丁發(fā)布:
注:有關開發(fā)預覽、灰度下發(fā)倍试、條件下發(fā)請查看官方文檔開發(fā)預覽和灰度與條件下發(fā)了解讯屈。補丁發(fā)布之后,對應版本的 APP 會請求下載這個腳本保存在本地县习,以后每次啟動都會執(zhí)行這個腳本涮母。至此線上 bug 修復完成谆趾。
現(xiàn)在只是發(fā)布了補丁,而我們的測試 demo 里的代碼還沒有修改叛本,所以還不能進行線上測試沪蓬。下面修改我們的測試代碼。
-application:didFinishLaunchingWithOptions:
調用+startWithAppKey:
方法来候,參數(shù)為之前獲得的 appKey跷叉。接著調用+sync
方法檢查更新。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//[JSPatch testScriptInBundle]; // 用于發(fā)布前測試腳本营搅,測試完成后請刪除性芬,改為調用 +startWithAppKey: 和 +sync
[JSPatch startWithAppKey:@"210a38abb83a9689"];
[JSPatch sync];
return YES;
}
注意:+testScriptInBundle
不能與+startWithAppKey:
一起調用,+testScriptInBundle
只用于本地測試剧防,測試完畢后需要去除植锉,項目中的 main.js 文件也要刪除(可拷貝一份至桌面留作上傳的補丁使用)。另外峭拘,通過 JSPatch 平臺上傳的腳本文件都會保存在七牛云存儲上俊庇,而七牛云存儲的下載使用的是 http 協(xié)議,因此需要在項目的 info.plist 文件中添加如下字段(這個應該都知道的...忽略)
OK鸡挠,現(xiàn)在我們來運行 demo
和本地測試一樣線上測試bug也修復成功辉饱。
修改/刪除 js 腳本
若后續(xù)需要對這個腳本進行修改,可以重新上傳新的腳本拣展,APP 客戶端會在請求時發(fā)現(xiàn)腳本已更新彭沼,下載最新腳本覆蓋原來的,下次啟動時執(zhí)行备埃。
若想直接取消某個 APP 版本的 JS 腳本補丁姓惑,可以直接在 APP 版本界面刪除此 APP 版本,APP 客戶端會在請求時發(fā)現(xiàn)腳本已被刪除按脚,即刻刪除本地 JS 腳本文件于毙,下次啟動時不再加載。
補充
JSPatch 作者@bang提供了一個轉換工具 JSPatch Converto辅搬,可以將 OC 轉換為 js 唯沮。
此外,@bang 大神還給我們準備了JSPatch XCode代碼自動補全插件堪遂,讓我們使用 JSPatch 更得心應手介蛉。
結語
對 JSPatch 研究有限,這里只是介紹了 JSPatch 的基礎用法溶褪,有錯誤或不當?shù)牡胤綒g迎指正币旧、交流。如果你想學習更多 JSPatch 的用法可以到 JSPatch 平臺使用文檔了解竿滨。如果你想知道 JSPatch 實現(xiàn)原理佳恬,看這里:JSPatch 實現(xiàn)原理詳解。
本文 demo 后續(xù)會上傳 GitHub于游,鏈接留在留言中毁葱。