1.首先去官网注册并登录账号,并进入控制台创建应用,获得相关的AppId,AppSecret,RSA密钥
2.然后按着接口文档,走流程配置相关信息就行,这个不细说,官网文档写的很清楚
3.代码主要有两部分组成,
第一步初始化SophixManager的initialize()方法,写在自己的Application中的attachBaseContext()或者onCreate()方法中就行。
第二步调用SophixManager.getInstance().queryAndLoadNewPatch();查找是否有新补丁,我把这个方法放在MainActivity中,因为Android6.0以上需要判断权限,如果没有开通权限,补丁是不可能更新成功的。
4.如果一切信息配置成功,会在控制台打出相关的日志信息
我用的是华为手机测试,华为手机可能会没有debug信息,请看链接如何开启debug模式
解决华为手机无法输出Debug级别log的问题http://blog.csdn.net/seafishyls/article/details/52198814
5.然后从官网下载补丁生成工具和调试工具,其中调试工具是一个apk文件
我用的是Windows版本
6.生成补丁
刚开始学习Sophix修复结束的时候,测试时建议不要签名,直接生成apk文件(后面讲原因)
首先生成一个老的apk文件(有bug),再生成一个新的apk文件(无bug),然后用工具就会生成一个补丁文件
之后会生成一个叫 sophix-patch.jar的补丁文件
7.调试补丁
回到阿里云控制台,上传补丁并进行调试
添加的版本号就是初始化时设置的版本号
可以在发布前用下载的测试工具apk,安装在测试机上,然后扫码查看补丁情况,如果有相关信息,证明补丁可以使用,然后点击发布就行
8.判断补丁是否成功应用
如果补丁成功加载了,会触发回调,虽然官网说可以不重启的情况下进行热修复,不过我在测试的时候,每次都需要冷启动。
9.一些可能遇到的坑,
千万不要使用Android Studio的 InstantRun功能,否则会出现ClassNotFoundException错误!!!
我使用华为Nova手机7.0系统出现这种情况,一直找不到原因,最后在网上看到不能使用InstantRun功能,后来直接将老的apk文件放在手机里安装,触发补丁修复功能成功了。
10.下面放上自己测试的源码,只是做了很小的改动,主要是监听触发冷启动的回调,销毁app进程,从而成功加载补丁
public class MyApplication extends Application {
/**用来判断是否要使用冷启动(重启App)的方式使补丁生效*/
public static boolean isRelaunch = false;
private final String TAG = this.getClass().getSimpleName();
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// initialize最好放在attachBaseContext最前面
initHotFix();
}
/**
code: 0 准备开始
code: 1 补丁加载成功
code: 6 服务端没有最新可用的补丁
code: 9 路径下载成功
code: 11 RSASECRET错误,官网中的密钥是否正确请检查
code: 12 当前应用已经存在一个旧补丁, 应用重启尝试加载新补丁
code: 13 补丁加载失败, 导致的原因很多种, 比如UnsatisfiedLinkError等异常, 此时应该严格检查logcat异常日志
code: 16 APPSECRET错误,官网中的密钥是否正确请检查
code: 18 一键清除补丁
code: 19 连续两次queryAndLoadNewPatch()方法调用不能短于3s
*/
private void initHotFix() {
String appVersion;
try {
appVersion = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
} catch (Exception e) {
appVersion = "1.0.0";
}
// initialize最好放在attachBaseContext最前面
SophixManager.getInstance().setContext(this)
.setAppVersion(appVersion)
.setAesKey(null)
.setEnableDebug(true)
.setPatchLoadStatusStub(new PatchLoadStatusListener() {
@Override
public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
Log.i(TAG, "mode:" + mode+",code:"+code+",info:"+info+",handlePatchVersion:"+handlePatchVersion);
// 补丁加载回调通知
if (code == PatchStatus.CODE_LOAD_SUCCESS) {
// 表明补丁加载成功
Log.i(TAG, "表明补丁加载成功:" );
} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
// 表明新补丁生效需要重启. 开发者可提示用户或者强制重启;
// 建议: 用户可以监听进入后台事件, 然后应用自杀
Log.i(TAG, "表明新补丁生效需要重启. 开发者可提示用户或者强制重启:" );
isRelaunch = true;
} else if (code == PatchStatus.CODE_LOAD_FAIL) {
// 内部引擎异常, 推荐此时清空本地补丁, 防止失败补丁重复加载
SophixManager.getInstance().cleanPatches();
Log.i(TAG, "内部引擎异常, 推荐此时清空本地补丁, 防止失败补丁重复加载:" );
} else {
// 其它错误信息, 查看PatchStatus类说明
// Log.i(TAG, "其它错误信息, 查看PatchStatus类说明:" );
}
}
}).initialize();
}
}
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 0;
private final String TAG = this.getClass().getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initPermissions();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (MyApplication.isRelaunch) {
Log.i(TAG, "如果是冷启动,则杀死App进程,从而加载补丁:" );
MyApplication.isRelaunch = false;
SophixManager.getInstance().killProcessSafely();
}
}
/**
* 配置Android 6.0 以上额外的权限
*/
private void initPermissions() {
//配置微信登录和6.0权限
if (Build.VERSION.SDK_INT >= 23) {
String[] mPermissionList = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,//读取储存权限
Manifest.permission.WRITE_EXTERNAL_STORAGE,//写入储存权限
};
if (checkPermissionAllGranted(mPermissionList)) {
/*查询是否有新补丁需要载入*/
SophixManager.getInstance().queryAndLoadNewPatch();
} else {
ActivityCompat.requestPermissions(this, mPermissionList, REQUEST_EXTERNAL_STORAGE_PERMISSION);
}
} else {
/*查询是否有新补丁需要载入*/
SophixManager.getInstance().queryAndLoadNewPatch();
}
}
private void test() {
String versionName = null;
try {
versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Toast.makeText(getBaseContext(), "当前版本" + versionName, Toast.LENGTH_SHORT).show();
}
/**
* 检查是否拥有指定的所有权限
*/
private boolean checkPermissionAllGranted(String[] permissions) {
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
// 只要有一个权限没有被授予, 则直接返回 false
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "成功获得权限");
/*查询是否有新补丁需要载入*/
SophixManager.getInstance().queryAndLoadNewPatch();
} else {
new AlertDialog.Builder(this)
.setMessage("未获得权限,无法获得补丁升级功能")
.setPositiveButton("设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
}).setNegativeButton("取消", null).show();
}
default:
break;
}
}
}