Android 插件化“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 插件化“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )相关的知识,希望对你有一定的参考价值。
【Android 插件化】系列博客 :
- 【Android 插件化】插件化简介 ( 组件化与插件化 )
- 【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )
- 【Android 插件化】插件化原理 ( 类加载器 )
- 【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )
- 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
参考 【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 ) 中给出的实现思路 , 逐步实现 “ 插桩式 “ 插件化框架 ;
在 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 ) 博客中 , 开发了 DexClassLoader 类加载器加载插件包 , 并使用 AssetManager 加载插件包资源的模块 ;
本博客中开发开发本地的 Activity 桩 , 即空壳 Activity , 用于持有插件界面组件 , 并在生命周期中回调插件界面 Activity 组件的对应生命周期方法 ;
一、加载插件包 dex 的类加载器
在 插件化框架 中定义一个代理 Activity , ProxyActivity , 该 Activity 只是个空壳 , 持有从 apk 加载的 PluginActivity 类对象 , 在 ProxyActivity 声明周期方法中调用对应 PluginActivity 类的生命周期方法
将 ProxyActivity 中要加载的全类名 , 设置在成员属性中 ;
/**
* 被代理的目标 Activity 组件的全类名
*/
private String className = "";
如果要使用类加载器加载 插件包 apk 中的 ProxyActivity , 则不能使用应用本身的类加载器 , 插件管理器 PluginManager 中的类加载器已经加载了插件包 apk 中的 dex 文件 , 因此可以获取到 PluginActivity 字节码对象 ;
// 创建 DexClassLoader
mDexClassLoader = new DexClassLoader(
loadPath, // 加载路径
optimizedDirectory.getAbsolutePath(), // apk 解压缓存目录
null,
context.getClassLoader() // DexClassLoader 加载器的父类加载器
);
在支持 插件化的工程中 , " 宿主 " 模块 和 " 插件 " 模块 都要依赖该 " 插件化框架 " ;
调用插件化框架中的 PluginManager 单例对象中的类加载器 , 加载插件包 apk 中的 PluginActivity 类对象 ;
/**
* 插件化框架核心类
*/
public class PluginManager {
/**
* 类加载器
* 用于加载插件包 apk 中的 classes.dex 文件中的字节码对象
*/
private DexClassLoader mDexClassLoader;
/**
* 获取类加载器
* @return
*/
public DexClassLoader getmDexClassLoader() {
return mDexClassLoader;
}
}
设置 代理界面组件 ProxyActivity 中的类加载器为 插件化框中 中的 插件管理器 PluginManager 中的类加载器 ;
public class ProxyActivity extends AppCompatActivity {
/**
* 被代理的目标 Activity 组件的全类名
*/
private String className = "";
@Override
public ClassLoader getClassLoader() {
return PluginManager.getInstance().getmDexClassLoader();
}
}
这样就可以在 ProxyActivity 中调用 getClassLoader() 方法获取插件管理器中的 DexClassLoader , 用于加载插件中的字节码类对象 ;
二、生命周期回调方法
定义一个接口 , 接口中定义 Activity 组件的生命周期 ;
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 方法 , 不能直接调用 , 否则每个方法调用时 , 还要先反射修改访问性 , 才能调用 ;
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 中 ,
维护两个成员属性 ,
/**
* 被代理的目标 Activity 组件的全类名
*/
private String className = "";
插件包类的 全类名 , 需要通过反射获取该类的字节码对象 ;
/**
* 插件包中的 Activity 界面组件
*/
private PluginActivityInterface pluginActivity;
插件包中的 Activity 组件类 , 借助反射获取该类 , 在 Activity 的各个声明周期函数中 , 需要调用该 PluginActivityInterface 的各个对应接口 ;
在 onCreate 方法中 , 先获取类加载器 , 并反射 插件 Activity 字节码对象 ; 并使用反射创建 Activity 类对象 ;
// 使用类加载器加载插件中的界面组件
Class<?> clazz = getClassLoader().loadClass(className);
// 使用反射创建插件界面组件 Activity
Activity activity = (Activity) clazz.newInstance();
判断插件 Activity 是否是 PluginActivityInterface 类型的 , 如果是强转为 PluginActivityInterface 类型对象 , 并开始注入上下文 Activity , 在插件类中凡是涉及到调用上下文的地方 , 一律调用该注入的上下文对象 , 也就是代理 ProxyActivity 的上下文 ;
// 判断 Activity 组件是否是 PluginActivityInterface 接口类型的
if (activity instanceof PluginActivityInterface){
// 如果是 PluginActivityInterface 类型 , 则强转为该类型
this.pluginActivity = (PluginActivityInterface) activity;
// 上下文注入
// 将该 ProxyActivity 绑定注入到 插件包的 PluginActivity 类中
// 该 PluginActivity 具有运行的上下文
// 一旦绑定注入成功 , 则被代理的 PluginActivity 也具有了上下文
pluginActivity.attach(this);
// 调用
pluginActivity.onCreate(savedInstanceState);
}
ProxyActivity 完整代码示例 :
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
以上是关于Android 插件化“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 插件化“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
Android 插件化“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )
Android 插件化“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
Android 插件化“ 插桩式 “ 插件化框架 ( 原理与实现思路 )