热修复系列——AndFix使用教程基础篇

一、前言

      最近研究阿里的开源热修复框架AndFix,本文参考AndFix官方教程,给出我所使用详细小白demo教程,包括在构建测试demo过程中所遇到对问题也列出来。阿里github链接:https://github.com/alibaba/AndFix

      限制:

      1、支持的Android版本为2.3-7.0(即:Android API 9 ~ Android API 24),本文在7.1版本的真机中测试失败。

       2、无法添加删除类和字段,只能修改。

       3、如构造函数等静态函数可能会有问题。

二、生成带bug的APK

     1、用AndroidStudio新建项目。

       踩坑说明:

       在使用AS创建项目时候,不管你选择的是那个Target版本,在gradle中默认的SDK都是最高版本。而我一开始用最高版本时,项目/build/outputs文件夹下没有apk文件夹,使用如下步骤生成apk文件:

           此时output目录下生成apk文件夹,但最后生成补丁包时报错如下:

      因此最后我选择手动修改gradle配置文件,降低SDK版本,同时由于本文为demo测试,删除了一些不需要的依赖项。

      本文使用Gradle将sdk编译版本设置为23,并且将最低目标版本为21(这个大家可以根据官网支持的版本修改),同时删除了所有dependencies依赖项,只添加AndFix依赖,具体对应位置修改如下:

compileSdkVersion 23
minSdkVersion 21
dependencies {
    compile 'com.alipay.euler:andfix:0.5.0@aar'
}

       此时,当我们修改完成后,gradle sync发现会报许多资源错误。这是因为创建的项目资源文件中使用了高版本SDK和一些依赖包中的东西,因此需要将不必要的资源文件或里面引用的标签删除,大致包括AndroidManifest.xml中的标签,res文件夹下的资源文件。如果是生成的BasicActivity,那么在这个Activity中,也可以将其他东西删除。

本文最终的使用的MainActivity.java关键代码如下:

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends Activity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Example of a call to a native method
        Log.d("euler", "test");
        TextView tv = (TextView) findViewById(R.id.text);
        tv.setText(change());
    }


    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public String change(){
        return "old";
    }

布局文件activity_main.xml代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/change_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Change Text" />
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello world"/>
</RelativeLayout>

补丁框架所需要的类MainApplication.java,直接放在与启动类MainActivity同一目录下,具体代码如下:

import java.io.IOException;

import android.app.Application;
import android.os.Environment;
import android.util.Log;

import com.alipay.euler.andfix.patch.PatchManager;

/**
 * sample application
 * 
 * @author [email protected]
 * 
 */
public class MainApplication extends Application {
	private static final String TAG = "euler";

	private static final String APATCH_PATH = "/out.apatch";
	/**
	 * patch manager
	 */
	private PatchManager mPatchManager;

	@Override
	public void onCreate() {
		super.onCreate();
		// initialize
		mPatchManager = new PatchManager(this);
		mPatchManager.init("1.0");
		Log.d(TAG, "inited.");

		// load patch
		mPatchManager.loadPatch();
		Log.d(TAG, "apatch loaded.");

		// add patch at runtime
		try {
			// .apatch file path
			String patchFileString = Environment.getExternalStorageDirectory()
					.getAbsolutePath() + APATCH_PATH;
			mPatchManager.addPatch(patchFileString);
			Log.d(TAG, "apatch:" + patchFileString + " added.");
		} catch (IOException e) {
			Log.e(TAG, "", e);
		}

	}
}

由于本文代码需要对sdcard进行读写,且实现MainApplication类,因此需要修改AndroidManifest.xml文件,本文具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.andfixdemo1">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <application
        android:name="com.example.andfixdemo1.MainApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

此时项目生成基本完成,gradle能够build成功。如果还有什么错误,只需要根据提示安装即可。

2、生成keystore文件

AndFix在使用补丁工具生成补丁包时,需要keystore文件和密钥等,如果你已经有自己的keystore文件,则可跳过这步。具体步骤如下:







finish后软件会自动在指定目录下生成jks文件,并提示生成成功。

3、生成签名apk

建立好keystore后,需要配置用该文件作为apk的签名文件,具体步骤如下:





配置完成后,选择本次编译版本,因为签名配置使用签名文件的版本为release版,因此编译选项选择release版。具体步骤如下:



      然后运行安装app即可,在项目路径/app/build/outputs/apk/release/app-release.apk即为带Bug的apk。

     本文保存该apk并更名为old.apk,解压源码AndFix-master/tools/apkpatch-1.0.3.zip,将old.apk放在解压后的apkpatch-1.0.3文件夹下。

      需要注意的是,本文demo使用了存储设备读取权限,因此安装后需要手动在应用管理中开启存储权限

三、生成修复APK

       本文更新的apk文件,只是将MainActivity中change函数的返回字符串更改为new,重新编译得到更新后的apk文件,并重命名为new.apk,同样复制到apkpatch-1.0.3文件夹下,此时手机里运行的仍然是带bug的old.apk。

四、生成补丁文件

        进入apkpatch-1.0.3文件夹文件夹,使用如下命令生成补丁.apatch文件。

./apkpatch.sh -o /Users/xxx/Desktop/ -k /Users/xxx/xxx.jks -p ******** -a xxx -e ******** -t ./old.apk -f ./new.apk

        命令参数说明:

         此时,Desktop目录下将生成了两个文件,关注.patch文件,重命名为MainApplication中用到的常量名称out.patch。

五、修复测试

         将补丁文件放入指定位置,本文所用测试机对应位置为/sdcard,因此使用命令如下:

adb push /Users/xxx/Desktop/out.apatch /sdcard/out.apatch

          对于其他机型,本文代码对应可能使用的命令如下:

adb push /Users/xxx/Desktop/out.apatch /storage/emulated/0/out.apatch

           重新启动应用,发现bug已经被修复。


猜你喜欢

转载自blog.csdn.net/u012195899/article/details/81008638