一、热修复实现思路:
1.引入Andfix依赖
2.生成有bug的安装包
3.生成修复bug后的apk
4.通过工具apkpatch-1.0.3生成.apatch文件
5.安装存在bug的apk,
6.通过文件传输工具把4中的文件导入指定文件夹(实际项目中可以放在服务器,通过网络下载)
7.在安装好的app中加载.apatch文件修复bug
二、具体实现
1.使用gradle添加依赖
// 引入AndFix热修复模块
implementation 'com.alipay.euler:andfix:0.5.0@aar'
由于本项目中用到sd卡存取,所以添加权限申请框架
//权限申请
implementation 'pub.devrel:easypermissions:1.1.1'
2.打包有bug的apk这里就不说了。人为的bug为打印一个没有初始化的字符串
public static void printString()
{
String error=null;
Log.e("Utils",error);
}
3.把字符串初始化后再打包(修复bug)
public static String printString()
{
String error="修复bug,初始化数据";
Log.e("Utils",error);
return error;
}
4.通过命令进入apkpatch-1.0.3文件夹
执行apkpatch.bat(window系统)可以看到如下:
命令主要有两个:第一个为生成补丁文件,第一个为合并补丁文件。
用第一个命令之前先把afixkey.jks,old.apk,new.apk放入apkpatch-1.0.3文件夹下,并创建存放补丁文件夹output
apkpatch -f new.apk -t old.apk -o output/ -k afixkey.jks -p 123456 -a rongyao -e 123456
new.apk:修复后的apk ;
old.apk:存在bug的apk;
output/:补丁文件存放路径
afixkey.jks:密钥
-p后123456:密钥密码
rongyao:别名
-e后 123456:别名密码
执行成功后,output文件夹下生成3个文件,我们只需要用到.apatch
5.自行安装old.apk
6.运行app后,项目中通过代码创建加载补丁的文件夹
修改补丁前运行,点击效果如图
点击后再点击
,效果如图
主要代码如下:
MyApplication代码如下:
package com.andfixdemo;
import android.app.Application;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//完成andFix模块的初始化
initAndFix();
}
private void initAndFix() {
AndFixPatchManager.getInstance().initPatch(this);
}
}
AndFixPatchManager代码:
package com.andfixdemo;
import android.content.Context;
import com.alipay.euler.andfix.patch.PatchManager;
public class AndFixPatchManager {
private static AndFixPatchManager mInstance = null;
private static PatchManager mPatchManager = null;
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文件
public void addPatch(String path) {
try {
if (mPatchManager != null) {
mPatchManager.addPatch(path);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MainActivity代码:
package com.andfixdemo;
import android.Manifest;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.io.File;
import java.util.List;
import pub.devrel.easypermissions.AppSettingsDialog;
import pub.devrel.easypermissions.EasyPermissions;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {
private static String filepath = ".apatch";
private String dir = "/mnt/sdcard/andfix/apatch/";//根据自己的情况设置
private Button button;
private Button button2;
private RelativeLayout activity_main;
private boolean orExistsDir;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (EasyPermissions.hasPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE})) {
createFolder();
} else {
// Ask for one permission
EasyPermissions.requestPermissions(this, "We require this permission to select photo from gallery and camera.",
100, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE});
}
}else
{
createFolder();
}
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
createFolder();
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this).build().show();
}
}
private void createFolder() {
//新建一个File,传入文件夹目录
File file = new File(dir);
//判断文件夹是否存在,如果不存在就创建,否则不创建
if (!file.exists()) {
//通过file的mkdirs()方法创建目录中包含却不存在的文件夹
file.mkdirs();
}
}
private void initView() {
button = (Button) findViewById(R.id.button);
text = (TextView) findViewById(R.id.text);
button.setOnClickListener(this);
button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.button:
String str= Utils.printString();
text.setText(str);
break;
case R.id.button2:
AndFixPatchManager.getInstance().addPatch(getPath());
break;
}
}
private String getPath() {
return dir.concat("fix").concat(filepath);
}
}
Utils代码:
package com.andfixdemo;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
/**
* Created by renzhiqiang on 17/4/22.
*/
public class Utils {
/**
* 获取应用程序versionname
*
* @param context
* @return
*/
public static String getVersionName(Context context) {
String versionName = "1.0.0";
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
versionName = pi.versionName;
} catch (Exception e) {
e.printStackTrace();
}
return versionName;
}
public static String printString()
{
// String error=null;//修复前
String error="修复bug,初始化数据";//修复后
Log.e("Utils",error);
return error;
}
}
最核心代码是:
初始化
mPatchManager = new PatchManager(context); mPatchManager.init(Utils.getVersionName(context));
mPatchManager.loadPatch();
加载补丁:
mPatchManager.addPatch(path);
CSDN地址:https://download.csdn.net/download/u010350891/10732393