javascript
JSPatch使用小记
hotfix的作用眾所周知,Android和iOS都有各自的技術(shù),但是相比Android的當(dāng)天發(fā)布來說(如果你們的項(xiàng)目不需要灰度),iOS熱更新的意義更加重大。因?yàn)閕OS審核周期長不說,而且運(yùn)氣不好會(huì)遇到各種被拒,即使申請(qǐng)快速審核,也必須滿足二者之一:能夠準(zhǔn)確的告訴蘋果復(fù)現(xiàn)crash的步驟,或者在特殊節(jié)日附近。 可能你費(fèi)勁周折的提心吊膽和那么多天其實(shí)也就是在某個(gè)類中加三行代碼。
1.簡單介紹
在沒有JSPatch之前,可能有人會(huì)使用過JSCocoa。但是有著一系列復(fù)雜問題,比如源碼已經(jīng)多年沒有維護(hù),代碼規(guī)模巨大,不支持ARM64。如果想使用還需要升級(jí)libffi,并且嘗試兼容ARM64,想編譯通過都很困難。
JSPatch的出現(xiàn)基本解決了上述所有問題。在一個(gè)項(xiàng)目中接入JSPatch的成本很低,需要?jiǎng)狱c(diǎn)腦筋的可能就是如何合理的提交和下載。
關(guān)于JSPatch的原理作者的博客已經(jīng)說的很清楚,本文不再說明,本文主要說的時(shí)一些接入操作相關(guān)。
如果你不是在董鉑然博客園看到本文可點(diǎn)擊查看原文。
2.倉庫設(shè)置
js文件肯定不能隨便往后臺(tái)某個(gè)文件夾一放就讓前端去下載了,雖然使用方便但是在App或者版本較多時(shí)容易混亂。建議專門搭建一個(gè)遠(yuǎn)端倉庫,倉庫里主要就是文件夾和js文件,當(dāng)需要提交js文件時(shí),從主干遷出一個(gè)分支,在合適的地方新建文件夾并添加js文件,然后給主干提Pull Request, 這應(yīng)該是一個(gè)麻煩但是規(guī)范的流程。文件夾結(jié)構(gòu)參考下圖:
第三層文件夾里,可以用版本名稱也可以使用build號(hào)。之后在發(fā)請(qǐng)求下載的時(shí)候應(yīng)該是需要拼上項(xiàng)目appname,version等參數(shù)。
3.安全策略
安全相關(guān)工作如果沒有做好,最慘的情況是人家可以通過js文件調(diào)用你的任何OC方法,我們肯定不能允許此類事情發(fā)生。一般在js文件提交到倉庫以后后端應(yīng)該對(duì)這一段js代碼進(jìn)行 md5或者更高手段的編碼,并將這段編碼與文件存在一起,上圖中得meta.json里存的就是這一段編碼。 之后在發(fā)請(qǐng)求的返回值的結(jié)構(gòu)應(yīng)該是大致如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { data: { isUpdate:?true, content: "require('MTPoiFeedbackM') ????defineClass('MTFeedbackRankCell',{ ????????????setPoiFeedback:function(poiFeedback){ ????????????????self.ORIGsetPoiFeedback(poiFeedback) ????????????????var temColor = require('UIColor').lightGrayColor(); ????????????????self.detailLbl().setTextColor(temColor); ????????????} })", code:?"9c944f39e57f2e50bdb85deb878cc0f798efb9b0" } } |
就是首先有個(gè)字段告訴我們較上次下載的js文件是否有更新。如果為true再檢測下方返回的code與內(nèi)容編碼后得到的code是否相同。當(dāng)然這個(gè)內(nèi)容也可以不直接返回而是返回一個(gè)下載的url也是完全可以的。
4.更新頻率
我之前看到很多人把使用js和下載js的代碼都放在了didFinishLaunchingWithOptions:這個(gè)方法。我覺得有所不妥,因?yàn)槿绻@個(gè)app用戶一直放在手機(jī)的后臺(tái)(比如微信),并且也沒出現(xiàn)內(nèi)存警告的話,這個(gè)方法應(yīng)該一直不會(huì)調(diào)用。我建議的是:使用js文件的代碼放在didFinishLaunchingWithOptions: 而下載js文件的代碼放在applicationDidBecomeActive: 因?yàn)檫@個(gè)方法在程序啟動(dòng)和后臺(tái)回到前臺(tái)時(shí)都會(huì)調(diào)用。并且我建議設(shè)置一個(gè)間隔時(shí)間,根據(jù)一些數(shù)據(jù)和權(quán)衡之后我們采用的是間隔時(shí)間設(shè)為1小時(shí)。 也就是說每次來到這個(gè)方法時(shí),先要檢測是距離上次發(fā)請(qǐng)求的時(shí)間間隔是否超過1小時(shí),超過則發(fā)請(qǐng)求,否則跳過。
5.接入流程
接入的方式很簡單,作者也提供了Demo程序,大致就分為幾步:
①在General 的 LinkFrameworks and Libraries里面 添加javascriptcore.framework
這個(gè)庫里主要用于js與oc語言的橋接,比如一些數(shù)據(jù)類型間的相互轉(zhuǎn)化。
②podfile添加?pod?'JSPatch' 并pod install
③在代碼中添加使用js和下載js的代碼
這里作者也給出了示例,使用和下載
| 1 2 3 4 | [JPEngine startEngine]; NSString?*sourcePath = [[NSBundle?mainBundle] pathForResource:@"demo"?ofType:@"js"]; NSString?*script = [NSString?stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding?error:nil]; [JPEngine evaluateScript:script]; |
?
| 1 2 3 4 | [NSURLConnection?sendAsynchronousRequest:[NSURLRequest?requestWithURL:[NSURL?URLWithString:@"http://cnbang.net/test.js"]] queue:[NSOperationQueue?mainQueue] completionHandler:^(NSURLResponse?*response,?NSData?*data,?NSError?*connectionError) { ????NSString?*script = [[NSString?alloc] initWithData:data encoding:NSUTF8StringEncoding]; ????[JPEngine evaluateScript:script]; }]; |
但是如果你是企業(yè)級(jí)app,肯定不能直接使用這么樸素的方式,肯定至少也要封裝一個(gè)manager之類的。我們公司的源碼不會(huì)在這里貼出來,但是提供一個(gè)建立這個(gè)manager大概的思路:
??
6.JSPatch語法
這里是作者列出的語法總結(jié):作者原文? 不用刻意去看,在寫的過程中逐漸就熟悉了。
下面給出一段示例代碼解決兩個(gè)簡單的bug。
①假設(shè)有一個(gè)按鈕我們默認(rèn)應(yīng)該是讓他不可點(diǎn)擊的,但是之前忘了設(shè)置。
OC代碼
| 1 2 3 4 5 | - (void)viewWillAppear:(BOOL)animated { ????[super?viewWillAppear:animated]; ????self.confirm.enabled =?NO; } |
jspatch?
| 1 2 3 4 5 6 | defineClass('MTBRegisterPage',{ ????????????viewWillAppear: function(animated) { ????????????self.super().viewWillAppear(animated); ????????????self.confirm().setEnabled(NO); ????????????} }) |
②假設(shè)有一個(gè)列表頁有特殊情況臨時(shí)想叫我們由黑色改成灰色,并展示一個(gè)彈窗
OC代碼
| 1 2 3 4 5 6 7 8 | - (void)setDealFeedback:(MTDealFeedbackM *)dealFeedback { ????// ------先調(diào)用原來的方法,舊代碼保留 ????self.detailLbl.textColor = [UIColor lightGrayColor]; ????UIAlertView *temAlertView = [[UIAlertView alloc]initWithTitle:@"提示"?message:@"已購物品用灰色展示"?delegate:self?cancelButtonTitle:@"OK"?otherButtonTitles:nil,?nil]; ????[temAlertView show]; ?? } |
jsPatch
| 1 2 3 4 5 6 7 8 9 10 11 | require('MTPoiFeedbackM') defineClass('MTFeedbackRankCell',{ ????????????setPoiFeedback:function(poiFeedback){ ????????????self.ORIGsetPoiFeedback(poiFeedback) ????????????var temColor = require('UIColor').lightGrayColor(); ????????????self.detailLbl().setTextColor(temColor); ????????????var temAlertView = require('UIAlertView').alloc(). initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles("提示","已購物品用灰色展示",?self,?"OK", null); ????????????temAlertView.show() ????????????} }) |
諸如此類的代碼,覺得在使用的過程中出現(xiàn)頻率最高的bug,就是調(diào)用原方法然后加一個(gè)判斷用來容錯(cuò)或return。
也許作者也覺得畢竟這個(gè)JSPatch語法 并不是一個(gè)正式的語種,大家不會(huì)投入太大的精力來仔細(xì)學(xué)習(xí),所以作者本人也提供了一個(gè)簡單粗暴的OC到JS直接轉(zhuǎn)換地址:http://bang590.github.io/JSPatchConvertor/
這個(gè)地址親測一些簡單的寫法是正確轉(zhuǎn)換的,但是比較復(fù)雜的語法還是不能讓機(jī)器直接搞定,還是需要人工修改的。作者也在不斷完善這個(gè)工具。 這個(gè)轉(zhuǎn)換器的實(shí)現(xiàn)原理:http://blog.cnbang.net/tech/2915/
7.更多思考
①.接入了JSPatch之后,iOS的線上BUG 看上去就不向以前那樣“猛如虎”了,但是這僅僅是一個(gè)緊急預(yù)案措施,以前規(guī)范的流程還是需要遵守。
②.每一次本版本用JSPatch解決的線上Bug,下個(gè)版本必須用OC代碼寫入項(xiàng)目中,不能允許補(bǔ)丁代碼的存留超過一個(gè)版本。
③.倡導(dǎo)使用敏捷開發(fā)的思想,類似于主邏輯或者是功能模塊入口的方法可以抽的更細(xì),這樣即使需要修改,成本也不會(huì)太大,作者本人也提到,如果有一行代碼必須要在一個(gè)大方法的中間進(jìn)行修改,那我也沒辦法了,你只能把這整個(gè)方法都用js寫一遍了,所以才設(shè)置了JSPatchConvertor。
④.每次用JSPatch解決掉的線上BUG 應(yīng)當(dāng)有一個(gè)專門的文檔記錄,遇到重復(fù)錯(cuò)誤必須寫casestudy。
?
暫時(shí)想到這些,希望本文能對(duì)準(zhǔn)備接入JSPatch的開發(fā)人員有所幫助。
如果你不是在董鉑然博客園看到本文可點(diǎn)擊查看原文。?
總結(jié)
以上是生活随笔為你收集整理的JSPatch使用小记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 资料整理:mac机械键盘设置(Karab
- 下一篇: jenkins依赖的android sd