android SDK热修复机制简析以实现

关于android 热修复,网上资料林林总总,比如AndFix、HotFix、DroidFix、Tinker等,这些都是从apk层面来实现怎么对线上app进行热修复的;但是有时候我们不仅仅需要热修复apk,当接入第三方SDK(jar)的话,获取也对需要SDK进行热修复,毕竟如果SDK有bug的话,APK替换修复好的SDK,然后发布新的版本代价太大。目前正好手头有这个需求,就查看资料捣鼓了一下,以博客的形式记录下来,供以后查看翻阅

SDK的热修复原理比App的热修复简单的多,核心原理或者步骤简单来说就两条:
1)下载服务器的jar
2)通过反射机制加载jar,创建相关对象并且操作之。

原理很简单,但是真正实现起来也有好几点需要注意:
1)宿主Apk配置上网以及SDK读写权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2)提供的jar包需要处理成dex格式的jar包,处理的步骤如下:
2.1)把打包好的jar放入android安装目录的platform-tools文件目录下(当然其他盘的任何目录都可以)。
2.2)cd 到android安装目录的build-tools文件如图:
android SDK热修复机制简析以实现_第1张图片
在此我选择23.0.0版本的文件夹:在该文件夹下有dx.bat和\lib\dx.jar两个文件,这两个文件正式转成dex格式的jar文件所需的工具。打开cmd,切换到23.0.0目录执行如下命令即可:dx - -dex - -output=转换后.jar,转换前.jar
这里写图片描述
如此就把jar转换成DexClassLoader可以加载的dex格式的jar了(hotfix.jar)。然后就可以交给宿主APK使用了。

3) 宿主Apk通过DexClassLoader加载hotfix.jar,通过反射创建对象并使用之。
为了方便说明,在此不实现jar的下载逻辑了,直接把hotfix.jar放在sdk卡根目录测试。
3.1)通过反射机制创建对象并使用之,代码如下:

private Object instance;// 反射形式创建的全局变量
private File file;//获取jar文件
private File dexOutputDir;
private DexClassLoader classLoader;
private Class sdkClass;
public void method1() {
            file = new File(Environment
                    .getExternalStorageDirectory().toString()
                    + File.separator
                    + "hotfix.jar");
            dexOutputDir = getDir("dex", 0);
            classLoader = new DexClassLoader(file.getAbsolutePath(),
                    dexOutputDir.getAbsolutePath(), null, getClassLoader());
           //加载sdk中提供的一个接口实现类
            sdkClass = classLoader.loadClass("cn.com.hotfix.intefimpl.HotFixImpl");

           //通过反射创建对象
            instance = sdkClass.newInstance();
           //通过反射获取hotFix方法
            Method method = sdkClass.getMethod("hotFix", null);
           //调用hotFix方法,并且获取hotFix方法返回的字符串;
            String src = (String) method.invoke(instance, null);
            Toast.makeText(MainActivity.this, src,
                    Toast.LENGTH_SHORT).show();
        } catch (Exception exception) {
            // Handle exception gracefully here.
            exception.printStackTrace();
        }
    }

此种方式通过反射机制创建一个对象,并且通过反射机制创建对象,然后通过反射机制获取Method方法来完成业务逻辑。当然这种方法很麻烦,你得告诉宿主apk的方法的名称(比如上面的,参数的类型),主要是代码维护起来麻烦!所以也可以采用第二种方式:插件化方式给宿主提供jar!

3.2)反射机制+插件化的方式
这种方式仍然离不开反射机制,这个暂且不提;先说说插件化的要求:
宿主定制好所需接口,SDK实现该接口;这样当宿主apk引入第三方SDK的时候,结合反射机制,能很好的来对接SDK.下面以一个简单的demo来作说明。
第一步:宿主定制接口:
android SDK热修复机制简析以实现_第2张图片
如图所示,HotFixSuZhu创建了cn.com.hotfix.interf.IHotFix的接口,该接口很简单:

public interface IHotFix {
  public String hotFix();
}

现在宿主Apk已经定制好接口,那么SDK实现这个接口,然后打包成dex格式的jar提供给宿主使用就可以了!SDK结构如下:
android SDK热修复机制简析以实现_第3张图片
SDK同样需要创建一个cn.com.hotfix.interf包,该包下面同样需要创建跟宿主一模一样的IHotFix接口,这点从接入方式来看有点像AIDL客户端的使用方式:在使用AIDL的时候同样需要在客户端引入AIDL接口的全限定名以及接口文件。同时SDK的HotFixImpl实现了IHotFix接口:

public class HotFixImpl implements IHotFix {
    @Override
    public String hotFix() {
        return "hotFix test";
    }
}

到此为止,宿主接口创建好了,SDK也实现了宿主创建的接口;那么就看看宿主怎么使用SDK(注意SDK在打包成jar并转换成dex格式的时候:切记不要把SDK项目下的cn.com.hotfix.interf.IHotFix也打包):

private IHotFix hotFixImpl;//创建对象
private File file;//获取jar文件
private File dexOutputDir;
private DexClassLoader classLoader;
private Class sdkClass;
public void method1() {
            file = new File(Environment
                    .getExternalStorageDirectory().toString()
                    + File.separator
                    + "hotfix.jar");
            dexOutputDir = getDir("dex", 0);
            classLoader = new DexClassLoader(file.getAbsolutePath(),
                    dexOutputDir.getAbsolutePath(), null, getClassLoader());
           //加载sdk中提供的一个接口实现类
            sdkClass = classLoader.loadClass("cn.com.hotfix.intefimpl.HotFixImpl");
           //创建对象
           hotFixImpl = (IHotFix) sdkClass.newInstance();
            Toast.makeText(MainActivity.this, hotFixImpl.hotFix(),
                    Toast.LENGTH_SHORT).show();     
    }

到此位置,SDK的热更新机制使用完毕,无非就是远程加载sdk,利用反射机制来创建一个SDK的对象来完成工作。这种更新机制可用于于及时解决线上app第三方SDK出现的bug,避免apk重新发布让用户下载安装的这种不好的体验。
相对于SDK热修复的原理来说,此篇博文倒是显得啰嗦了,希望对大家有所帮助。不当之处或者有什么别的实现方式,欢迎交流。(点此下载demo)
今天闲着没事翻阅《android内核剖析这本书》的时候才发现原来此书也有关于android插件化开发的说明,详见该书第二章《java基础》篇的DexClassLoader的介绍。

你可能感兴趣的:(android SDK热修复机制简析以实现)