Android 熱修復框架AndFix

導論:
在這裏插入圖片描述
上篇博客提到增量更新,這篇就要說說熱修復,那麼到底什麼區別呢?通俗的理解:
1:你軟件有新的功能或者升級一下一些更改,但是下載完整的APK又比較大,這時爲了省流量纔會用到增量更新,這個叫增量包,格式爲.patch文件
2:用戶使用你的應用某個地方老是出現bug,那麼怎麼辦,不會還是發佈完整APK下載使用吧,當然不會,這時就需要修補bug的補丁了,類似windows 漏洞更新,這個叫補丁包,格式爲.apatch

爲了學習更多的知識,我找到某個大牛的demo,裏面介紹的是阿里百川的熱修復框架Andfix,當然你也可以自己寫框架,除非你強過阿里的技術大牛,在這裏還會了解一點第三方服務器存儲,友盟統計,極光消息推送Jpush,多線程下載等知識,也是爲了讓大家學到更多的知識,若有疑問,還請海涵.

原理:
1:啓動應用獲取友盟在線參數來判斷當前應用是否有補丁下載,有則下載到SDcard裏並且通過阿里熱修復框架AndFix自動修補補丁
2:使用極光Jpush推送消息到應用,若收到消息,就有補丁需要下載,若沒有收到消息,就通過友盟在線參數來判斷有無補丁

步驟
1:在app/module build.gradle中添加依賴,有多線程下載,Jpush,友盟,阿里andfix

dependencies {
    ....
    compile 'com.mani:thindownloadmanager:1.0.0'
    compile files('libs/jpush-android-2.1.0.jar')
    compile files('libs/umeng-onlineconfig_v1.0.0.jar')
    compile 'com.alipay.euler:andfix:0.3.1@aar'
}

2:導入AndFix的so庫文件以及極光推送的so庫文件到jniLibs目錄裏,具體地址自己自行百度
這裏寫圖片描述

3:配置友盟在線參數以及極光推送自定義消息的內容在這裏忽略,官方有開發文檔可以參考

4:製作補丁包放在第三方服務器上
A:下載apkpatch工具:
https://github.com/alibaba/AndFix/raw/master/tools/apkpatch-1.0.3.zip

B:將old.apk,new.apk,Jks簽名文件拷貝到解壓apkpatch工具的目錄下,打開命令行輸入命令生成補丁包,格式如下

生成差異文件命令 : apkpatch.bat -f new.apk -t old.apk -o output1 -k debug.keystore -p android -a androiddebugkey -e android  
-f <new.apk> :新版本  
-t <old.apk> : 舊版本  
-o <output> : 輸出目錄  
-k <keystore>: 打包所用的keystore  
-p <password>: keystore的密碼  
-a <alias>: keystore 用戶別名  
-e <alias password>: keystore 用戶別名密碼  

C:將生成的補丁.apach放到服務器上

D:根據服務器存儲信息去配置友盟後臺和定義極光推送消息路徑

5:在自定義Application類進行初始化andfix PatchManager和Jpush JPushInterface

public class BaseApplication extends Application {
    public static String VERSION_NAME;
    public static PatchManager mPatchManager;

    @Override
    public void onCreate() {
        super.onCreate();
        try {
            VERSION_NAME = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
            mPatchManager = new PatchManager(this);
            mPatchManager.init(VERSION_NAME);
            mPatchManager.loadPatch();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        JPushInterface.init(this);
    }
}

6:比對本地應用版本和遠程服務器的版本及補丁版本,若有更新,就下載到本地SDcard,最後調用andfix PatchManager自動修補補丁

private static final int THREAD_COUNT = 3;  //下載的線程數
    private ThinDownloadManager mDownloadManager;
    private LocalPreferencesHelper mLocalPreferencesHelper;

    private static class SingletonHolder {
        public static final RepairBugUtil INSTANCE = new RepairBugUtil();
    }

    //單例模式
    public static RepairBugUtil getInstance() {
        return SingletonHolder.INSTANCE;
    }
    //使用ThinDownloadManager多線程下載和PatchManager修補補丁
    public void downloadAndLoad(Context context, final PatchBean bean, String downloadUrl) {
        if (mLocalPreferencesHelper == null) {
            mLocalPreferencesHelper = new LocalPreferencesHelper(context, SPConst.SP_NAME);
        }
        Uri downloadUri = Uri.parse(downloadUrl);
        Uri destinationUri = Uri.parse(Environment.getExternalStorageDirectory()
                .getAbsolutePath() + bean.url);
        //下載方法
        DownloadRequest downloadRequest = new DownloadRequest(downloadUri)
                .setDestinationURI(destinationUri)
                .setPriority(DownloadRequest.Priority.HIGH)
                .setDownloadListener(new DownloadStatusListener() {
                    public void onDownloadComplete(int id) {
                        try {
                            String patchFileString = Environment.getExternalStorageDirectory()
                                    .getAbsolutePath() + bean.url;
                            //修補補丁
                            BaseApplication.mPatchManager.addPatch(patchFileString);
                            File f = new File(patchFileString);
                            if (f.exists()) {
                                boolean result = new File(patchFileString).delete();
                            }
                        } catch (IOException e) {

                        } catch (Throwable throwable) {

                        }
                    }

                    public void onDownloadFailed(int id, int errorCode, String errorMessage) {
                    }

                    public void onProgress(int id, long totalBytes, int progress) {
                    }
                });
        //多線程下載
        mDownloadManager = new ThinDownloadManager(THREAD_COUNT);
        mDownloadManager.add(downloadRequest);
    }
    //比對遠程服務器應用和補丁版本和本地的區別,若版本相同,但是補丁不一樣,那麼就下載新的補丁
    public void comparePath(Context context, PatchBean RemoteBean) throws Exception {
        String pathInfo = mLocalPreferencesHelper.getString(SPConst.PATH_INFO);
        final PatchBean localBean = GsonUtils.getInstance().parseIfNull(PatchBean.class, pathInfo);
        if (BaseApplication.VERSION_NAME.equals(RemoteBean.app_v)) {
            if (localBean == null && !TextUtils.isEmpty(RemoteBean.path_v)
                    || localBean.app_v.equals(RemoteBean.app_v) &&
                    !localBean.path_v.equals(RemoteBean.path_v)) {
                downloadAndLoad(context, RemoteBean,
                        SPConst.URL_PREFIX + RemoteBean.url);
                String json = GsonUtils.getInstance().parse(RemoteBean);
                mLocalPreferencesHelper.saveOrUpdate(SPConst.PATH_INFO, json);
            }
        }
    }
    //釋放線程
    public void release() {
        if (mDownloadManager != null) {
            mDownloadManager.release();
        }
    }

7:在MainActivity中進行友盟補丁檢測和極光推送的自定義消息的處理

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        registerMessageReceiver();  
        initUmeng(); 
        getUmengParamAndFix();
    }
	//獲取友盟後臺定義鍵對應的值並下載補丁後修補
    private void getUmengParamAndFix() {
        //獲取友盟在線參數對應key的values
        String pathInfo = OnlineConfigAgent.getInstance().getConfigParams(this, UMENG_ONLINE_PARAM);
        if (!TextUtils.isEmpty(pathInfo)) {
            PatchBean onLineBean = GsonUtils.getInstance().parseIfNull(PatchBean.class, pathInfo);
            try {
                RepairBugUtil.getInstance().comparePath(this, onLineBean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //初始化友盟
    private void initUmeng() {
        OnlineConfigAgent.getInstance().updateOnlineConfig(this);
        OnlineConfigAgent.getInstance().setDebugMode(true);
    }
    //註銷Jpush廣播
    protected void onDestroy() {
        unregisterReceiver(mMessageReceiver);
        RepairBugUtil.getInstance().release();
        super.onDestroy();
    }
    private WeakHandler mHandler = new WeakHandler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == MSG_WHAT_DOWNLOAD) {
                String message = (String) msg.obj;
                if (TextUtils.isEmpty(message)) return false;
                try {
	                //處理Jpush推送消息,下載補丁完成修補
                    PatchBean bean = GsonUtils.getInstance().parse(PatchBean.class, message);
                    RepairBugUtil.getInstance().comparePath(MainActivity.this, bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    });
    private MessageReceiver mMessageReceiver;
    public static final String MESSAGE_RECEIVED_ACTION = "com.aile.andfix.MESSAGE_RECEIVED_ACTION";
    public static final String KEY_MESSAGE = "message";
	//註冊Jpush廣播
    public void registerMessageReceiver() {
        mMessageReceiver = new MessageReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(MESSAGE_RECEIVED_ACTION);
        registerReceiver(mMessageReceiver, filter);
    }
	//創建Jpush廣播處理器,接收Jpush推送消息內容
    public class MessageReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {
                String message = intent.getStringExtra(KEY_MESSAGE);
                Message msg = new Message();
                msg.what = MSG_WHAT_DOWNLOAD;
                msg.obj = message;
                mHandler.sendMessage(msg);
            }
        }
    }

8:關於極光Jpush廣播的的創建及註冊AndroidManifest.xml相關問題和友盟統計後臺設置可以自行進入相關官網學習開發文檔

好了,結束.

發佈了63 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章