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

2023-03-29 13:26:21 浏览数 (1)

Android 插件化系列文章目录

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

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

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

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

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

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

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

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


文章目录

  • Android 插件化系列文章目录
  • 一、加载插件包 dex 的类加载器
  • 二、生命周期回调方法
  • 三、代理 Activity 组件
  • 四、博客资源

参考 【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();
    }
}

四、博客资源


博客资源 :

  • GitHub : https://github.com/han1202012/Plugin

0 人点赞