【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )
Android 插件化系列文章目錄
【Android 插件化】插件化簡介 ( 組件化與插件化 )
【Android 插件化】插件化原理 ( JVM 內(nèi)存數(shù)據(jù) | 類加載流程 )
【Android 插件化】插件化原理 ( 類加載器 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 原理與實現(xiàn)思路 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 類加載器創(chuàng)建 | 資源加載 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 獲取插件入口 Activity 組件 | 加載插件 Resources 資源 )
【Android 插件化】“ 插樁式 “ 插件化框架 ( 運行應(yīng)用 | 代碼整理 )
文章目錄
- Android 插件化系列文章目錄
- 一、加載插件包 dex 的類加載器
- 二、生命周期回調(diào)方法
- 三、代理 Activity 組件
- 四、博客資源
參考 【Android 插件化】“ 插樁式 “ 插件化框架 ( 原理與實現(xiàn)思路 ) 中給出的實現(xiàn)思路 , 逐步實現(xiàn) “ 插樁式 “ 插件化框架 ;
在 【Android 插件化】“ 插樁式 “ 插件化框架 ( 類加載器創(chuàng)建 | 資源加載 ) 博客中 , 開發(fā)了 DexClassLoader 類加載器加載插件包 , 并使用 AssetManager 加載插件包資源的模塊 ;
本博客中開發(fā)開發(fā)本地的 Activity 樁 , 即空殼 Activity , 用于持有插件界面組件 , 并在生命周期中回調(diào)插件界面 Activity 組件的對應(yīng)生命周期方法 ;
一、加載插件包 dex 的類加載器
在 插件化框架 中定義一個代理 Activity , ProxyActivity , 該 Activity 只是個空殼 , 持有從 apk 加載的 PluginActivity 類對象 , 在 ProxyActivity 聲明周期方法中調(diào)用對應(yīng) PluginActivity 類的生命周期方法
將 ProxyActivity 中要加載的全類名 , 設(shè)置在成員屬性中 ;
/*** 被代理的目標(biāo) Activity 組件的全類名*/ private String className = "";如果要使用類加載器加載 插件包 apk 中的 ProxyActivity , 則不能使用應(yīng)用本身的類加載器 , 插件管理器 PluginManager 中的類加載器已經(jīng)加載了插件包 apk 中的 dex 文件 , 因此可以獲取到 PluginActivity 字節(jié)碼對象 ;
// 創(chuàng)建 DexClassLoader mDexClassLoader = new DexClassLoader(loadPath, // 加載路徑optimizedDirectory.getAbsolutePath(), // apk 解壓緩存目錄null,context.getClassLoader() // DexClassLoader 加載器的父類加載器 );在支持 插件化的工程中 , " 宿主 " 模塊 和 " 插件 " 模塊 都要依賴該 " 插件化框架 " ;
調(diào)用插件化框架中的 PluginManager 單例對象中的類加載器 , 加載插件包 apk 中的 PluginActivity 類對象 ;
/*** 插件化框架核心類*/ public class PluginManager {/*** 類加載器* 用于加載插件包 apk 中的 classes.dex 文件中的字節(jié)碼對象*/private DexClassLoader mDexClassLoader;/*** 獲取類加載器* @return*/public DexClassLoader getmDexClassLoader() {return mDexClassLoader;} }設(shè)置 代理界面組件 ProxyActivity 中的類加載器為 插件化框中 中的 插件管理器 PluginManager 中的類加載器 ;
public class ProxyActivity extends AppCompatActivity {/*** 被代理的目標(biāo) Activity 組件的全類名*/private String className = "";@Overridepublic ClassLoader getClassLoader() {return PluginManager.getInstance().getmDexClassLoader();} }這樣就可以在 ProxyActivity 中調(diào)用 getClassLoader() 方法獲取插件管理器中的 DexClassLoader , 用于加載插件中的字節(jié)碼類對象 ;
二、生命周期回調(diào)方法
定義一個接口 , 接口中定義 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 , 實現(xiàn)了 PluginActivityInterface , 其中涉及到的生命周期函數(shù)重復(fù)了 , 如 AppCompatActivity 中的 public void onCreate(Bundle savedInstanceState) 方法與 PluginActivityInterface 接口中的 public void onCreate(Bundle savedInstanceState) 方法是重復(fù)的 , 這里在每個方法前面加上 @SuppressLint("MissingSuperCall") 注解 , 忽略該報錯 ;
所有的插件包中的 Activity 都要集繼承該 BaseActivity ;
這樣寫的目的是為了方便在代理 Activity 中可以隨意調(diào)用插件包中的 Activity 類的生命周期函數(shù) , 這些生命周期函數(shù)都是 protected 方法 , 不能直接調(diào)用 , 否則每個方法調(diào)用時 , 還要先反射修改訪問性 , 才能調(diào)用 ;
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 組件注入進(jìn)來* @param proxyActivity*/@Overridepublic void attach(Activity proxyActivity) {that = proxyActivity;}@SuppressLint("MissingSuperCall")@Overridepublic void onCreate(Bundle savedInstanceState) {}@SuppressLint("MissingSuperCall")@Overridepublic void onStart() {}@SuppressLint("MissingSuperCall")@Overridepublic void onResume() {}@SuppressLint("MissingSuperCall")@Overridepublic void onPause() {}@SuppressLint("MissingSuperCall")@Overridepublic void onStop() {}@SuppressLint("MissingSuperCall")@Overridepublic void onDestroy() {}@SuppressLint("MissingSuperCall")@Overridepublic void onSaveInstanceState(Bundle outState) {} }三、代理 Activity 組件
在代理 Activity 組件 ProxyActivity 中 ,
維護(hù)兩個成員屬性 ,
/*** 被代理的目標(biāo) Activity 組件的全類名*/ private String className = "";插件包類的 全類名 , 需要通過反射獲取該類的字節(jié)碼對象 ;
/*** 插件包中的 Activity 界面組件*/ private PluginActivityInterface pluginActivity;插件包中的 Activity 組件類 , 借助反射獲取該類 , 在 Activity 的各個聲明周期函數(shù)中 , 需要調(diào)用該 PluginActivityInterface 的各個對應(yīng)接口 ;
在 onCreate 方法中 , 先獲取類加載器 , 并反射 插件 Activity 字節(jié)碼對象 ; 并使用反射創(chuàng)建 Activity 類對象 ;
// 使用類加載器加載插件中的界面組件 Class<?> clazz = getClassLoader().loadClass(className); // 使用反射創(chuàng)建插件界面組件 Activity Activity activity = (Activity) clazz.newInstance();判斷插件 Activity 是否是 PluginActivityInterface 類型的 , 如果是強轉(zhuǎn)為 PluginActivityInterface 類型對象 , 并開始注入上下文 Activity , 在插件類中凡是涉及到調(diào)用上下文的地方 , 一律調(diào)用該注入的上下文對象 , 也就是代理 ProxyActivity 的上下文 ;
// 判斷 Activity 組件是否是 PluginActivityInterface 接口類型的 if (activity instanceof PluginActivityInterface){// 如果是 PluginActivityInterface 類型 , 則強轉(zhuǎn)為該類型this.pluginActivity = (PluginActivityInterface) activity;// 上下文注入// 將該 ProxyActivity 綁定注入到 插件包的 PluginActivity 類中// 該 PluginActivity 具有運行的上下文// 一旦綁定注入成功 , 則被代理的 PluginActivity 也具有了上下文pluginActivity.attach(this);// 調(diào)用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 聲明周期方法中調(diào)用對應(yīng) PluginActivity 類的生命周期方法*/ public class ProxyActivity extends AppCompatActivity {/*** 被代理的目標(biāo) Activity 組件的全類名*/private String className = "";/*** 插件包中的 Activity 界面組件*/private PluginActivityInterface pluginActivity;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_proxy);// 注意此處的 ClassLoader 類加載器必須是插件管理器中的類加載器try {// 使用類加載器加載插件中的界面組件Class<?> clazz = getClassLoader().loadClass(className);// 使用反射創(chuàng)建插件界面組件 ActivityActivity activity = (Activity) clazz.newInstance();// 判斷 Activity 組件是否是 PluginActivityInterface 接口類型的if (activity instanceof PluginActivityInterface){// 如果是 PluginActivityInterface 類型 , 則強轉(zhuǎn)為該類型this.pluginActivity = (PluginActivityInterface) activity;// 上下文注入// 將該 ProxyActivity 綁定注入到 插件包的 PluginActivity 類中// 該 PluginActivity 具有運行的上下文// 一旦綁定注入成功 , 則被代理的 PluginActivity 也具有了上下文pluginActivity.attach(this);// 調(diào)用pluginActivity.onCreate(savedInstanceState);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}@Overrideprotected void onStart() {super.onStart();pluginActivity.onStart();}@Overrideprotected void onResume() {super.onResume();pluginActivity.onResume();}@Overrideprotected void onPause() {super.onPause();pluginActivity.onPause();}@Overrideprotected void onStop() {super.onStop();pluginActivity.onStop();}@Overrideprotected void onDestroy() {super.onDestroy();pluginActivity.onDestroy();}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);pluginActivity.onSaveInstanceState(outState);}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);return pluginActivity.onTouchEvent(event);}@Overridepublic void onBackPressed() {super.onBackPressed();pluginActivity.onBackPressed();}@Overridepublic ClassLoader getClassLoader() {return PluginManager.getInstance().getmDexClassLoader();} }四、博客資源
博客資源 :
- GitHub : https://github.com/han1202012/Plugin
總結(jié)
以上是生活随笔為你收集整理的【Android 插件化】“ 插桩式 “ 插件化框架 ( 代理 Activity 组件开发 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android FFMPEG 开发】A
- 下一篇: 【商务智能】数据预处理