引言
關于熱修復,可以看看下面幾篇文章。里面說了熱修復的一些原理,這篇文章僅僅是工具的使用。
關于熱修復還是有很多坑的,例如跨平臺支持不太好。而且AndFix而言好像只是支持2.3-6.0的Android版本。我在6.0上面嘗試就失敗了。
環境
- OS X EI Capitan 10.11.6 (15G31)
- Android Studio 2.1.1
- JRE 1.6.0
步驟
- 生成APK簽名
- 編寫APP
- 生成有BUG的APK并且簽名
- 安裝有BUG的APK
- 修復BUG,生成修復后的APK并且簽名
- 找出兩份APK之間的差異,生成補丁
- 打補丁
- 測試
生成APK簽名
這一步我們留到生成APK的時候再弄。
編寫APP
添加依賴包
compile 'com.alipay.euler:andfix:0.5.0@aar'
初始化PatchManager
這一步我們放到Application初始化里面。
所以MyApplication.java
的源碼就這么簡單。
public class MyApplication extends Application {
static final String APP_VERSION = "version";
PatchManager mManager;
@Override
public void onCreate() {
super.onCreate();
mManager = new PatchManager(this);
mManager.init(APP_VERSION);
}
public PatchManager getPatchManager() {
return mManager;
}
}
最后別忘了修改AndroidManifest.xml
去指定Application
布局文件
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="test"
android:text="test" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="fix"
android:text="fix" />
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
代碼
包結構
Hello.java
public class Hello {
public String getString() {
return "I am a bug!!!!";
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
}
public void test(View v) {
Hello hello = new Hello();
tv.setText(hello.getString());
}
public void fix(View v) {
PatchManager patchManager = ((MyApplication) getApplication()).getPatchManager();
patchManager.loadPatch();
try {
patchManager.addPatch("/sdcard/patch.apatch");
} catch (IOException e) {
e.printStackTrace();
}
}
}
其中假設我們出現Bug的地方就是
Hello.java
的getString
方法。
因為我們在MyApplication
中初始化了PatchManager
并且保存了實例。所以我們修復的時候只需要通過addPatch
方法指定路徑就能去加載補丁了。
生成有BUG的APK并且簽名
直接在Android Studio里面的菜單生成
Build
->Generate Signed APK
->app
->next
->create new(填寫信息,生成一個簽名文件)
->OK
->next
->Finish
安裝有BUG的APK
生成的APK在
AndFixDemo/app/build/outputs/apk
目錄下
我們先把現在有bug的apk放到一個文件夾里并重命名(我這里命名為bug.apk
)吧,方便等下和修復后的apk作對比。
安裝的方法很多,這里我們使用adb install bug.apk
安裝
安裝后我們點擊TEST按鈕
,顯示了I am a bug!!!!
。
修復BUG,生成修復后的APK并且簽名
這里就不再多說了,就修改我們上面假設的BUG
public class Hello {
public String getString() {
return "I had fucked the bug,23333333!!!!";
}
}
重復上面的方法找到修復后的apk重新命名
fix.apk
,然后扔到與bug.apk
同一個目錄。
找出兩份APK之間的差異,生成補丁
這里AndFix給我們提供了工具apkpatch。下載,然后解壓。這里提供mac下任意目錄運行文件。
Windows下的參考這里win7系統環境變量path的兩種設置方法
mac下任意目錄運行文件
給需要運行的文件建立軟鏈接
- 進入apkpatch解壓后的目錄
sudo ln apkpatch.sh /usr/local/bin/apkpatch
這樣就能在任意目錄運行apkpatch了
生成補丁
切換到
bug.apk
和fix.apk
的目錄-
apkpatch -f fix.apk -t bug.apk -k key.jks -o . -p 123456789 -a test -e 12345678
參數
- -f 修復后的文件
- -t 存在bug的文件
- -k 簽名文件,就是上面通過
Create new
創建的 - -o 補丁導出位置,
.
代表當前目錄 - -p 簽名文件的密碼
- -a 簽名文件的別名
Alias
- -e 簽名文件別名對應的密碼
這樣之后我們就可以在導出位置看到生成了一個
.apatch
的文件,修改文件名為patch.apatch
目錄結構
打補丁
- 把補丁放到指定位置,這個位置就是我們程序寫死的
/sdcard/patch.apatch
。文件傳送方法也很多,這里使用adb push傳送文件到手機上
adb push patch.apatch /sdcard/
測試
- 要知道我們只是傳送了一個補丁包,并沒有把整個程序傳送過去。
- 現在我們打開原來存在bug的程序,然后點擊TEST,bug依舊存在
- 然后我們通過點擊FIX,再點擊TEST,上面就顯示了I had fucked the bug,23333333!!!!了。