目录

Android黑科技动态加载(一)之Java中的ClassLoader
Android黑科技动态加载(二)之Android中的ClassLoader
Android黑科技动态加载(三)之动态加载资源
Android黑科技动态加载(四)之插件化开发

项目地址

Android黑科技动态加载(四)之动态启动插件Activity_第1张图片 android_plugin_activity.gif

如果做插件化

Android动态加载技术三个关键问题详解一文中指出插件化需要解决的三个问题. 其中两个问题已经在前面博客中解决了. 现在剩下的问题就是如何去启动Activity.

启动已经安装的插件的Activity很简单, 只需要使用隐式启动就可以了

那对于未安装的插件的Activity, 我们使用一种思想叫做代理Activity

代理Activity

代理Activity的思想就是通过代理Activity占坑, 然后我们资源或者业务逻辑之类的都是加载插件Activity的. 这样我们就能把插件Activity加"启动起来".

编码

首先我们需要新建一个Bean来存放已经加载的插件APK信息

/** * 用来存放已经加载的插件APK信息 */public class PluginApk {    public PackageInfo packageInfo;    public Resources resources;    public ClassLoader classLoader;    public PluginApk(Resources resources) {        this.resources = resources;    }}

然后我们根据之前加载资源的方式去加载插件APK的信息

/** * 创建一个Entity保存APK的信息 * * @param apkPath * @return */private PluginApk createApk(String apkPath) {    PluginApk pluginApk = null;    try {        // 事实就是跟前面那样动态加载资源的原理是一样的        AssetManager assetManager = AssetManager.class.newInstance();        Method addAssetPathMethod = assetManager.getClass().getMethod("addAssetPath", String.class);        addAssetPathMethod.invoke(assetManager, apkPath);        Resources resources = new Resources(assetManager, mContext.getResources().getDisplayMetrics(),                mContext.getResources().getConfiguration());        pluginApk = new PluginApk(resources);        pluginApk.classLoader = createDexClassLoader(apkPath);    } catch (Exception e) {        e.printStackTrace();    }    return pluginApk;}/** * 查询APK的包信息 * * @param apkPath * @return */private PackageInfo queryPackageInfo(String apkPath) {    PackageManager packageManager = mContext.getPackageManager();    PackageInfo packageInfo = packageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);    return packageInfo;}/** * 加载并创建APK的信息 * * @param apkPath * @return */public PluginApk loadApk(String apkPath) {    PackageInfo packageInfo = queryPackageInfo(apkPath);    // 获取未安装的插件APK包信息    if (packageInfo == null || TextUtils.isEmpty(packageInfo.packageName)) {        return null;    }    PluginApk pluginApk = sMap.get(packageInfo.packageName);    // 从缓存中获取    if (pluginApk == null) {        pluginApk = createApk(apkPath); // 缓存中不存在, 则开始创建APK信息        if (pluginApk != null) {            // 缓存            pluginApk.packageInfo = packageInfo;            sMap.put(packageInfo.packageName, pluginApk);        } else {            throw new NullPointerException("plugin apk is null");        }    }    return pluginApk;}

至此, 我们的插件APK资源就已经获取完毕了. 下面我们就开始编写代理Activity的逻辑吧.

/** * 代理Activity, 真正启动的Activity是这个, 但是加载的资源是插件Activity的 */public class ProxyActivity extends Activity {    LifeCircleController mPluginController = new LifeCircleController(this);    //  用于管理代理Activity生命周倩和资源的类    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mPluginController.onCreate(getIntent().getExtras());    }    @Override    public Resources getResources() {        Resources resources = mPluginController.getResources();        return null != resources ? resources : super.getResources();    }    @Override    public AssetManager getAssets() {        AssetManager assets = mPluginController.getAssets();        return null != assets ? mPluginController.getAssets() : super.getAssets();    }    @Override    public ClassLoader getClassLoader() {        ClassLoader loader = mPluginController.getClassLoader();        return null != loader ? loader : super.getClassLoader();    }}

说白, 代理Activity的逻辑不多, 就是一个空壳. 重要的逻辑都写在LifeCircleController中.

/** * 代理Activity生命周期以及资源管理类 */public class LifeCircleController implements Pluginable {    public static final String KEY_PLUGIN_CLASS_NAME = "plugin_class_name"; // 用来传递需要需要启动的Activity的类名    public static final String KEY_PACKAGE_NAME = "package_name";   // Activity所在插件APK的包名    Activity mActivityProxy;    PluginActivity mPluginActivity;    PluginApk mPluginApk;    public LifeCircleController(ProxyActivity activityProxy) {        this.mActivityProxy = activityProxy;    }    /**     * 加载插件Activity     *     * @param classLoader     * @param pluginName     * @return     */    private PluginActivity loadPluginActivity(ClassLoader classLoader, String pluginName) {        PluginActivity activity = null;        try {            Class cls = classLoader.loadClass(pluginName);            activity = (PluginActivity) cls.newInstance();        } catch (Exception e) {            e.printStackTrace();        }        return activity;    }    /**     * 代理获取资源     *     * @return     */    public Resources getResources() {        return null != mPluginApk ? mPluginApk.resources : null;    }    /**     * 代理获取资源     *     * @return     */    public AssetManager getAssets() {        return mPluginApk.resources.getAssets();    }    /**     * 解析需要启动的Activity     *     * @param extras     */    @Override    public void onCreate(Bundle extras) {        String pluginName = extras.getString(KEY_PLUGIN_CLASS_NAME);        String packageName = extras.getString(LifeCircleController.KEY_PACKAGE_NAME);        mPluginApk = ActivityManager.getInstance().getPluginApk(packageName);   //  获取加载的插件APK信息        mPluginActivity = loadPluginActivity(mPluginApk.classLoader, pluginName);   // 加载插件Activity        mPluginActivity.attach(mActivityProxy); //  绑定代理Activity到插件Activity中, 使其能够调用代理Activity对应的应用资源等方法        mPluginActivity.onCreate(null); //  代理生命周期    }    // 代理生命周期    @Override    public void onRestart() {        mPluginActivity.onRestart();    }    @Override    public void onStart() {        mPluginActivity.onStart();    }    @Override    public void onResume() {        mPluginActivity.onResume();    }    @Override    public void onPause() {        mPluginActivity.onPause();    }    @Override    public void onStop() {        mPluginActivity.onStop();    }    @Override    public void onDestroy() {        mPluginActivity.onDestroy();    }    public ClassLoader getClassLoader() {        return mPluginApk.classLoader;    }}

其中我们提供一个专门同步生命周期的接口

public interface Pluginable {    void onCreate(Bundle var1);    void onRestart();    void onStart();    void onResume();    void onPause();    void onStop();    void onDestroy();}

还有一个Attachable接口

public interface Attachable {    void attach(T data);}

下面的就是所有插件Activity都必须继承的父类

/** * 所有插件Activity都必须继承的基类 */public class PluginActivity extends Activity implements Pluginable, Attachable {    private Activity mProxyActivity;    @Override    public Window getWindow() {        return mProxyActivity.getWindow();    }    @Override    public View findViewById(int id) {        return mProxyActivity.findViewById(id);    }    /**     * 使用代理Activity去设置加载到的资源, 因为代理Activity本身就是优先使用插件APK的ClassLoader和Resource, 所以该方法会加载到插件APK的布局     *     * @param layoutResID     */    @Override    public void setContentView(int layoutResID) {        mProxyActivity.setContentView(layoutResID);    }    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {    }    @Override    public void onRestart() {    }    @Override    public void onStart() {    }    @Override    public void onResume() {    }    @Override    public void onPause() {    }    @Override    public void onStop() {    }    @Override    public void onDestroy() {    }    @Override    public void attach(Activity data) {        this.mProxyActivity = data;    }}

然后Plugin相关类需要导出Jar包, 这样主包跟插件包才能使用同样的类

更多相关文章

  1. 巧解Android时区加载过慢的问题
  2. android的异步加载与UI
  3. 【Gradle】Android Gradle 插件
  4. Android工程手动增加插件包方法
  5. Android 加载模型
  6. Android加载Gif和ImageView的通用解决方案:android-gif-drawable(1
  7. Android 资源(resource)学习小结

随机推荐

  1. android轮播图Banner的使用及详解
  2. 获取设备上所有系统app信息
  3. android实现滑动解锁
  4. Android(安卓)Bitmap 保存图片透明背景变
  5. Android(安卓)开机默认横竖屏
  6. Android指南针之加速度传感器地磁传感器-
  7. Android(安卓)中文 API 文档 (45) —— Abs
  8. Android设备双屏异显
  9. android scheme
  10. android 使用Google地图步骤要点