Android熱修復與外掛化(四)AndFix
阿新 • • 發佈:2019-01-08
一、熱修復技術種類
技術對比
二、AndFix的基本介紹
整合階段:
1、在gradle中新增依賴
2、在程式碼中完成初始化builde.gradle
MyApplication
AndFixPatchManager
準備階段:
1、首先我們先builde一個有bug的old.apk安裝到手機
2、分析bug並解決bug,builde一個new的apk(需要簽名打包的apk不要debug,自行解決)
有bug的程式碼:
public class MainActivity extends AppCompatActivity {
private static final String FILE_END = ".apatch";
private String patchDir;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//建立檔案路徑
patchDir = getExternalCacheDir().getAbsolutePath() + "/apatch/";
//建立資料夾
File file = new File(patchDir);
//判斷資料夾是否存在
if (file == null || !file.exists()) {
//不存在就建立
file.mkdir();
}
}
public void createBug(View view) {
//列印log資訊為null,應用閃退
Utils.printLog();
}
public void fixBug(View view) {
AndFixPatchManager.getInstance().addPatch(getPathName());
}
//構建Patch檔名
private String getPathName() {
return patchDir.concat("smile").concat(FILE_END);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.smile.mydemotwo.activity.MainActivity">
<Button
android:layout_width="88dp"
android:layout_height="50dp"
android:text="產生bug"
android:onClick="createBug"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="8dp"
android:layout_margin="10dp"/>
<Button
android:layout_width="88dp"
android:layout_height="50dp"
android:text="修復bug"
android:onClick="fixBug"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="8dp"
android:layout_margin="10dp"/>
</LinearLayout>
Patch生成階段:
1、apkpatch命令及引數詳解
1、先下載apkpatch工具工具
解壓
-f:new.apk的檔案路徑
-t:是有bug的apk檔案的路徑
-o:是輸出補丁包檔案的目錄
-k:是簽名檔案的路徑
-p:是簽名檔案的密碼
-a :是簽名檔案的別名
-e:是簽名檔案別名的密碼2、使用apkpatch命令生成apkpatch包
Patch安裝階段:
將補丁檔案通過adb push放入到指定目錄(開發中都是下載到指定目錄)
點選修復bug按鈕,載入補丁檔案
再次啟動應用,點選建立bug按鈕,此時應用不會閃退,並彈出Toast到這基本就完成了更新
總結階段:
1、實際中不可能用adb push匯入補丁,應該是下載
2、能否將AndFix模組元件化,為以後複用將AndFix元件化
AndFixPatchManager :
public class AndFixPatchManager {
private static AndFixPatchManager mInstance = null;
private static PatchManager mPatchManager = null;
private AndFixPatchManager() {
}
public static AndFixPatchManager getInstance() {
if (mInstance == null) {
synchronized (AndFixPatchManager.class) {
if (mInstance == null) {
mInstance = new AndFixPatchManager();
}
}
}
return mInstance;
}
//初始化AndFix方法
public void initPatch(Context context) {
mPatchManager = new PatchManager(context);
mPatchManager.init(Utils.getVersionName(context));
mPatchManager.loadPatch();
}
//載入我們的patch檔案,引數patch檔案的路徑
public void addPatch(String path) {
try {
if (mPatchManager != null) {
mPatchManager.addPatch(path);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
AndFixService
public class AndFixService extends Service {
private static final int UPDATE_PATCH = 0x02;
private static final int DOWNLOAD_PATCH = 0x01;
private static final String FILE_END = ".apatch";
//存放Patch檔案的目錄
private String mPatchFileDir;
//存放Patch檔案
private String mPatchFile;
//訊息轉發
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_PATCH:
checkPatchUpdate();
break;
case DOWNLOAD_PATCH:
downloadPatch();
break;
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//初始化
init();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mHandler.sendEmptyMessage(UPDATE_PATCH);
//這個返回值如果被系統回收之後不會被系統重啟
return START_NOT_STICKY;
}
//完成檔案目錄的構造
private void init() {
mPatchFileDir = getExternalCacheDir().getAbsolutePath() + "/apatch/";
File file = new File(mPatchFileDir);
try {
if (file == null || !file.exists()) {
file.mkdir();
}
} catch (Exception e) {
e.printStackTrace();
stopSelf();
}
}
//檢查是否有新的patch檔案
private void checkPatchUpdate() {
//網路請求,失敗停止服務
}
private void downloadPatch() {
//網路請求,失敗停止服務
mPatchFile = mPatchFileDir.concat(System.currentTimeMillis() + "").concat(FILE_END);
}
}