阿里云热修复技术Sophix的快速接入

1.首先去官网注册并登录账号,并进入控制台创建应用,获得相关的AppId,AppSecret,RSA密钥
阿里云热修复技术Sophix的快速接入_第1张图片

2.然后按着接口文档,走流程配置相关信息就行,这个不细说,官网文档写的很清楚

3.代码主要有两部分组成,
第一步初始化SophixManager的initialize()方法,写在自己的Application中的attachBaseContext()或者onCreate()方法中就行。
第二步调用SophixManager.getInstance().queryAndLoadNewPatch();查找是否有新补丁,我把这个方法放在MainActivity中,因为Android6.0以上需要判断权限,如果没有开通权限,补丁是不可能更新成功的。

4.如果一切信息配置成功,会在控制台打出相关的日志信息

阿里云热修复技术Sophix的快速接入_第2张图片

我用的是华为手机测试,华为手机可能会没有debug信息,请看链接如何开启debug模式
解决华为手机无法输出Debug级别log的问题http://blog.csdn.net/seafishyls/article/details/52198814

5.然后从官网下载补丁生成工具和调试工具,其中调试工具是一个apk文件

阿里云热修复技术Sophix的快速接入_第3张图片

我用的是Windows版本

6.生成补丁

刚开始学习Sophix修复结束的时候,测试时建议不要签名,直接生成apk文件(后面讲原因)
阿里云热修复技术Sophix的快速接入_第4张图片

首先生成一个老的apk文件(有bug),再生成一个新的apk文件(无bug),然后用工具就会生成一个补丁文件

阿里云热修复技术Sophix的快速接入_第5张图片

要设置输出路径,否则会报错!!!
阿里云热修复技术Sophix的快速接入_第6张图片

之后会生成一个叫 sophix-patch.jar的补丁文件

7.调试补丁

回到阿里云控制台,上传补丁并进行调试

添加的版本号就是初始化时设置的版本号

阿里云热修复技术Sophix的快速接入_第7张图片

阿里云热修复技术Sophix的快速接入_第8张图片

然后上传之前生成的补丁文件sophix-patch.jar
这里写图片描述

阿里云热修复技术Sophix的快速接入_第9张图片

可以在发布前用下载的测试工具apk,安装在测试机上,然后扫码查看补丁情况,如果有相关信息,证明补丁可以使用,然后点击发布就行

阿里云热修复技术Sophix的快速接入_第10张图片

8.判断补丁是否成功应用

如果补丁成功加载了,会触发回调,虽然官网说可以不重启的情况下进行热修复,不过我在测试的时候,每次都需要冷启动。
阿里云热修复技术Sophix的快速接入_第11张图片

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;
        }
    }
}

你可能感兴趣的:(热修复)