Android 插件化原理 实现雏形

166 阅读1分钟

为了应付面试,简单了解一下,顺便记录

原理

利用 DexClassLoader loadClass 加载 Apk dex中的 class文件 拿到目标Class,再通过反射执行目标Class的方法

简单实现

plugin App

package com.zy.plugin.utils
class Utils {
    private Utils() {

    }

    private void hello(Context context) {
        Toast.makeText(context, "Plugin --> Utils --> hello", Toast.LENGTH_SHORT).show();
        System.out.println("Plugin --> Utils --> hello");
    }
}

宿主 App

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File pluginApk = new File(getExternalFilesDir("pluginApks"), "plugin-debug.apk");
        try (Source source = Okio.source(getAssets().open("plugin-debug.apk"));
             BufferedSink bufferedSink = Okio.buffer(Okio.sink(pluginApk))
        ) {
            bufferedSink.writeAll(source);
        } catch (IOException e) {
            e.printStackTrace();
        }
        DexClassLoader classLoader = new DexClassLoader(pluginApk.getAbsolutePath(), pluginApk.getAbsolutePath(), null, null);
        try {
            Class<?> utilsClass = classLoader.loadClass("com.zy.plugin.utils.Utils");
            Constructor<?> constructor = utilsClass.getDeclaredConstructors()[0];
            constructor.setAccessible(true);
            Object utils = constructor.newInstance();
            Method helloMethod = utilsClass.getDeclaredMethod("hello", Context.class);
            helloMethod.setAccessible(true);
            helloMethod.invoke(utils, this);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 将插件apk保存到手机存储中
  2. 通过DexClassLoader.loadClass()加载目标class文件,得到目标Class对象
  3. 反射执行具体操作

参考了凯哥扔物线课堂的Demo

本文Demo