前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )

作者头像
韩曙亮
发布2023-03-29 13:26:21
6190
发布2023-03-29 13:26:21
举报
文章被收录于专栏:韩曙亮的移动开发专栏

Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )

【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )

【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )


文章目录

参考 【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 ) 中给出的实现思路 , 逐步实现 “ 插桩式 “ 插件化框架 ;

【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 ) 博客中 , 开发了 DexClassLoader 类加载器加载插件包 , 并使用 AssetManager 加载插件包资源的模块 ;

本博客中开发开发本地的 Activity 桩 , 即空壳 Activity , 用于持有插件界面组件 , 并在生命周期中回调插件界面 Activity 组件的对应生命周期方法 ;

一、加载插件包 dex 的类加载器


在 插件化框架 中定义一个代理 Activity , ProxyActivity , 该 Activity 只是个空壳 , 持有从 apk 加载的 PluginActivity 类对象 , 在 ProxyActivity 声明周期方法中调用对应 PluginActivity 类的生命周期方法

将 ProxyActivity 中要加载的全类名 , 设置在成员属性中 ;

代码语言:javascript
复制
/**
 * 被代理的目标 Activity 组件的全类名
 */
private String className = "";

如果要使用类加载器加载 插件包 apk 中的 ProxyActivity , 则不能使用应用本身的类加载器 , 插件管理器 PluginManager 中的类加载器已经加载了插件包 apk 中的 dex 文件 , 因此可以获取到 PluginActivity 字节码对象 ;

代码语言:javascript
复制
// 创建 DexClassLoader
mDexClassLoader = new DexClassLoader(
        loadPath, // 加载路径
        optimizedDirectory.getAbsolutePath(), // apk 解压缓存目录
        null,
        context.getClassLoader() // DexClassLoader 加载器的父类加载器
);

在支持 插件化的工程中 , " 宿主 " 模块 和 " 插件 " 模块 都要依赖该 " 插件化框架 " ;

调用插件化框架中的 PluginManager 单例对象中的类加载器 , 加载插件包 apk 中的 PluginActivity 类对象 ;

代码语言:javascript
复制
/**
 * 插件化框架核心类
 */
public class PluginManager {
	/**
	 * 类加载器
	 * 用于加载插件包 apk 中的 classes.dex 文件中的字节码对象
	 */
	private DexClassLoader mDexClassLoader;
	
    /**
     * 获取类加载器
     * @return
     */
    public DexClassLoader getmDexClassLoader() {
        return mDexClassLoader;
    }
}

设置 代理界面组件 ProxyActivity 中的类加载器为 插件化框中 中的 插件管理器 PluginManager 中的类加载器 ;

代码语言:javascript
复制
public class ProxyActivity extends AppCompatActivity {

    /**
     * 被代理的目标 Activity 组件的全类名
     */
    private String className = "";

    @Override
    public ClassLoader getClassLoader() {
        return PluginManager.getInstance().getmDexClassLoader();
    }
}

这样就可以在 ProxyActivity 中调用 getClassLoader() 方法获取插件管理器中的 DexClassLoader , 用于加载插件中的字节码类对象 ;

二、生命周期回调方法


定义一个接口 , 接口中定义 Activity 组件的生命周期 ;

代码语言:javascript
复制
package com.example.plugin_core;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;

import androidx.annotation.NonNull;

public interface PluginActivityInterface {

    /**
     * 绑定代理 Activity
     * @param proxyActivity
     */
    void attach(Activity proxyActivity);

    void onCreate(Bundle savedInstanceState);
    void onStart();
    void onResume();
    void onPause();
    void onStop();
    void onDestroy();
    void onSaveInstanceState(Bundle outState);
    boolean onTouchEvent(MotionEvent event);
    void onBackPressed();

}

定义一个 Activity 基类 BaseActivity , 继承 AppCompatActivity , 实现了 PluginActivityInterface , 其中涉及到的生命周期函数重复了 , 如 AppCompatActivity 中的 public void onCreate(Bundle savedInstanceState) 方法与 PluginActivityInterface 接口中的 public void onCreate(Bundle savedInstanceState) 方法是重复的 , 这里在每个方法前面加上 @SuppressLint("MissingSuperCall") 注解 , 忽略该报错 ;

所有的插件包中的 Activity 都要集继承该 BaseActivity ;

这样写的目的是为了方便在代理 Activity 中可以随意调用插件包中的 Activity 类的生命周期函数 , 这些生命周期函数都是 protected 方法 , 不能直接调用 , 否则每个方法调用时 , 还要先反射修改访问性 , 才能调用 ;

代码语言:javascript
复制
package com.example.plugin_core;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity implements PluginActivityInterface {

    /**
     * 注入的 Activity
     */
    private Activity that;

    /**
     * 注入代理 Activity
     * 在 ProxyActivity 中将代理 Activity 组件注入进来
     * @param proxyActivity
     */
    @Override
    public void attach(Activity proxyActivity) {
        that = proxyActivity;
    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onCreate(Bundle savedInstanceState) {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onStart() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onResume() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onPause() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onStop() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onDestroy() {

    }

    @SuppressLint("MissingSuperCall")
    @Override
    public void onSaveInstanceState(Bundle outState) {

    }
}

三、代理 Activity 组件


在代理 Activity 组件 ProxyActivity 中 ,

维护两个成员属性 ,

代码语言:javascript
复制
/**
 * 被代理的目标 Activity 组件的全类名
 */
private String className = "";

插件包类的 全类名 , 需要通过反射获取该类的字节码对象 ;

代码语言:javascript
复制
/**
 * 插件包中的 Activity 界面组件
 */
private PluginActivityInterface pluginActivity;

插件包中的 Activity 组件类 , 借助反射获取该类 , 在 Activity 的各个声明周期函数中 , 需要调用该 PluginActivityInterface 的各个对应接口 ;

在 onCreate 方法中 , 先获取类加载器 , 并反射 插件 Activity 字节码对象 ; 并使用反射创建 Activity 类对象 ;

代码语言:javascript
复制
// 使用类加载器加载插件中的界面组件
Class<?> clazz = getClassLoader().loadClass(className);
// 使用反射创建插件界面组件 Activity
Activity activity = (Activity) clazz.newInstance();

判断插件 Activity 是否是 PluginActivityInterface 类型的 , 如果是强转为 PluginActivityInterface 类型对象 , 并开始注入上下文 Activity , 在插件类中凡是涉及到调用上下文的地方 , 一律调用该注入的上下文对象 , 也就是代理 ProxyActivity 的上下文 ;

代码语言:javascript
复制
// 判断 Activity 组件是否是 PluginActivityInterface 接口类型的
if (activity instanceof PluginActivityInterface){
    // 如果是 PluginActivityInterface 类型 , 则强转为该类型
    this.pluginActivity = (PluginActivityInterface) activity;
    // 上下文注入
    // 将该 ProxyActivity 绑定注入到 插件包的 PluginActivity 类中
    // 该 PluginActivity 具有运行的上下文
    // 一旦绑定注入成功 , 则被代理的 PluginActivity 也具有了上下文
    pluginActivity.attach(this);
    // 调用
    pluginActivity.onCreate(savedInstanceState);
}

ProxyActivity 完整代码示例 :

代码语言:javascript
复制
package com.example.plugin_core;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;

/**
 * 该 Activity 只是个空壳 ;
 * 主要用于持有从 apk 加载的 Activity 类
 * 并在 ProxyActivity  声明周期方法中调用对应 PluginActivity 类的生命周期方法
 */
public class ProxyActivity extends AppCompatActivity {

    /**
     * 被代理的目标 Activity 组件的全类名
     */
    private String className = "";

    /**
     * 插件包中的 Activity 界面组件
     */
    private PluginActivityInterface pluginActivity;

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

        // 注意此处的 ClassLoader 类加载器必须是插件管理器中的类加载器
        try {
            // 使用类加载器加载插件中的界面组件
            Class<?> clazz = getClassLoader().loadClass(className);
            // 使用反射创建插件界面组件 Activity
            Activity activity = (Activity) clazz.newInstance();

            // 判断 Activity 组件是否是 PluginActivityInterface 接口类型的
            if (activity instanceof PluginActivityInterface){
                // 如果是 PluginActivityInterface 类型 , 则强转为该类型
                this.pluginActivity = (PluginActivityInterface) activity;

                // 上下文注入
                // 将该 ProxyActivity 绑定注入到 插件包的 PluginActivity 类中
                // 该 PluginActivity 具有运行的上下文
                // 一旦绑定注入成功 , 则被代理的 PluginActivity 也具有了上下文
                pluginActivity.attach(this);

                // 调用
                pluginActivity.onCreate(savedInstanceState);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void onStart() {
        super.onStart();
        pluginActivity.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        pluginActivity.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        pluginActivity.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
        pluginActivity.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        pluginActivity.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        pluginActivity.onSaveInstanceState(outState);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        return pluginActivity.onTouchEvent(event);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        pluginActivity.onBackPressed();
    }

    @Override
    public ClassLoader getClassLoader() {
        return PluginManager.getInstance().getmDexClassLoader();
    }
}

四、博客资源


博客资源 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-06-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Android 插件化系列文章目录
    • 文章目录
    • 一、加载插件包 dex 的类加载器
    • 二、生命周期回调方法
    • 三、代理 Activity 组件
    • 四、博客资源
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档