在手淘工做期間,內部有一套解決方案,給線上apk打補丁,直接修復bug,不用客戶端升級,有嚴重線上bug,找到問題,寫個patch,推上線就把問題解決了,用過的都說好。前段時間,他們終於把這套東西的Android端開源了,Dexposed,具體能夠看詳細的項目介紹。其功能就是能夠加載類,替換原先apk裏面某個類的方法,或者在方法以前,方法以後作些什麼,好比在方法執行以前,修改傳入方法的參數了,方法執行之後,修改方法的返回值,或者就是徹底替換掉原先的方法。
java
項目裏面有一個sample,介紹瞭如何加載一個外部apk包,而後替換宿主apk裏面類的方法。其實這就已經完成了80%的工做了,我作的工做只是將Patch獲取從本地加載改爲了去服務器獲取,以及添加了Patch apk的校驗(md5和簽名信息)。git
Hotpatch的工做流程是:github
1.實現一個從服務器端獲取Patch信息的接口(上傳本地客戶端版本等信息,服務器好根據這些信息來判斷是否有對應的Patch包),並將這個信息注入給HotpatchManager。
tomcat
2.檢測客戶端是否能夠支持。(Android L和Android M)目前都不支持,最低支持2.3服務器
3.若是客戶端支持,那就調用第一步注入的Patch包獲取類,獲取到對應的Patch信息。下載Patch apk文件。app
4.校驗。獲取下載好的Patch apk md5簽名信息和服務器給的Patch信息的md5值是否同樣,而後還要校驗Patch apk和宿主apk簽名是否一致。加校驗是爲了防止Patch apk被篡改,若是load進去了一個第三方的Patch,那就是引狼入室了。必定不能去掉校驗,不能去掉,不能去掉,重要的事情說三遍!!!ide
5.校驗成功,就load Patch apk。ui
下面是貼代碼時間:url
public class HotpatchManager { private static HotpatchManager INSTANCE=new HotpatchManager(); private HotpatchManager() { } public static HotpatchManager getInstance(IPatchInfoRequest request){ RequestManager.getInstance().setIPatchInfoRequest(request); return INSTANCE; } public boolean init(final Context ctx) { boolean isSupport = DexposedBridge.canDexposed(ctx); if (isSupport) { new Thread(new Runnable() { @Override public void run() { check(ctx); } }).start(); } return isSupport; } private void check(final Context ctx) { RequestManager manager = RequestManager.getInstance(); manager.setIPatchInfoRequest(RequestManager.getInstance().getIPatchInfoRequest()); manager.reqeust(new RequestManager.OnRequestCallBackListener() { @Override public void onRequest(final PatchInfo info) { if (null != info) { String apkPath = Utils.getCacheApkFilePath(ctx, info.apkFileUrl); File file = new File(apkPath); if (file.exists()) { loadPath(info, ctx, apkPath); } else { DownLoadManager.getInstance().downloadFile(ctx, info.apkFileUrl, new DownLoadManager.OnFileDownload() { @Override public void fileDownload(String apkFilePath) { loadPath(info, ctx, apkFilePath); } }); } } } }); } private void loadPath(PatchInfo info, Context ctx, String apkFilePath) { if (Utils.isSignEqual(ctx, apkFilePath) && TextUtils.equals(info.apkMd5, Utils.getMd5ByFile(new File(apkFilePath)))) { PatchMain.load(ctx, apkFilePath, null); } } }
已經提供了實現好的客戶端和服務器例子。網址分別是:spa
客戶端例子實現:https://github.com/fengcunhan/Hotpatch-Sample
服務器簡易實現:https://github.com/fengcunhan/Hotpatch-SimpleServer
運行例子步驟:
1.修改 DefaultPatch類中的info.patchApkUrl 的url中的IP替換成你的服務器的IP,將代碼部署到tomcat中。
2.導入Hotpatch-Sample中的工程到Android Studio中。
3.打開網址 http://服務器IP:服務器端口/PathServer,將patchsample下build/outputs/apk/app-debug.apk上傳到服務器上面,必定不要更名字。
4.修改DefaultPatchInfoRequest 中的hostUrl的IP和端口爲你的服務器端IP和端口。
5.運行dexposedexamples項目,點擊 Check Hotpatch,若是出現 「The dialog is shown from patch apk」,恭喜你,成功運行了Demo。
Demo中的Patch只是很簡單的一個例子,後續會碰到混淆的類怎麼怎麼寫Patch之類的問題,這些都將在之後一一敘述。請你們關注這個Hotpatch系列。
Demo中服務器實現很渣渣。請服務器端大神不要噴,能夠fork,不要fuck。