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

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

六、" 依赖库 " 模块代码



1、插件 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();
}



2、插件 Activity 基类


package com.example.plugin_core;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
/**
 * " 插件 " 模块中的 Activity 类都继承该类
 * 具体的 Activity 业务类的父类
 */
public class BaseActivity extends AppCompatActivity implements PluginActivityInterface {
    /**
     * 注入的 Activity , 代理该 Activity 类作为上下文
     */
    private Activity proxyActivity;
    /**
     * 注入代理 Activity
     * 在 ProxyActivity 中将代理 Activity 组件注入进来
     * @param proxyActivity
     */
    @Override
    public void attach(Activity proxyActivity) {
        this.proxyActivity = proxyActivity;
    }
    @Override
    public void setContentView(int layoutResID) {
        // 调用代理 Activity 中的 setContentView 方法
        if (proxyActivity != null) {
            proxyActivity.setContentView(layoutResID);
        }else{
            super.setContentView(layoutResID);
        }
    }
    @Override
    public void setContentView(View view) {
        // 调用代理 Activity 中的 setContentView 方法
        if (proxyActivity == null) {
            proxyActivity.setContentView(view);
        }else{
            super.setContentView(view);
        }
    }
    @Override
    public <T extends View> T findViewById(int id) {
        if (proxyActivity == null) {
            return proxyActivity.findViewById(id);
        }else{
            return super.findViewById(id);
        }
    }
    @Override
    public void startActivity(Intent intent) {
        if (proxyActivity == null) {
            intent.putExtra("className", intent.getComponent().getClassName());
            proxyActivity.startActivity(intent);
        }else{
            super.startActivity(intent);
        }
    }
    @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) {
    }
}




3、代理 Activity ( 桩 )


package com.example.plugin_core;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
/**
 * 插件化框架核心类
 */
public class PluginManager {
    /**
     * 类加载器
     * 用于加载插件包 apk 中的 classes.dex 文件中的字节码对象
     */
    private DexClassLoader mDexClassLoader;
    /**
     * 从插件包 apk 中加载的资源
     */
    private Resources mResources;
    /**
     * 插件包信息类
     */
    private PackageInfo mPackageInfo;
    /**
     * 加载插件的上下文对象
     */
    private Context mContext;
    /**
     * PluginManager 单例
     */
    private static PluginManager instance;
    private PluginManager(){
    }
    /**
     * 获取单例类
     * @return
     */
    public static PluginManager getInstance(){
        if (instance == null) {
            instance = new PluginManager();
        }
        return instance;
    }
    /**
     * 加载插件
     * @param context 加载插件的应用的上下文
     * @param loadPath 加载的插件包地址
     */
    public void loadPlugin(Context context, String loadPath) {
        this.mContext = context;
        // DexClassLoader 的 optimizedDirectory 操作目录必须是私有的
        // ( 模式必须是 Context.MODE_PRIVATE )
        File optimizedDirectory = context.getDir("cache_plugin", Context.MODE_PRIVATE);
        // 创建 DexClassLoader
        mDexClassLoader = new DexClassLoader(
                loadPath, // 加载路径
                optimizedDirectory.getAbsolutePath(), // apk 解压缓存目录
                null,
                context.getClassLoader() // DexClassLoader 加载器的父类加载器
        );
        // 加载资源
        try {
            // 通过反射创建 AssetManager
            AssetManager assetManager = AssetManager.class.newInstance();
            // 通过反射获取 AssetManager 中的 addAssetPath 隐藏方法
            Method addAssetPathMethod = assetManager.
                    getClass().
                    getDeclaredMethod("addAssetPath", String.class);
            // 调用反射方法
            addAssetPathMethod.invoke(assetManager, loadPath);
            // 获取资源
            mResources = new Resources(
                    assetManager,
                    context.getResources().getDisplayMetrics(),
                    context.getResources().getConfiguration()
            );
            // 获取插件包中的 Activity 类信息
            mPackageInfo = context.getPackageManager().getPackageArchiveInfo(
                    loadPath, // 加载的插件包路径
                    PackageManager.GET_ACTIVITIES); // 获取的包信息类名
        } catch (IllegalAccessException e) {
            // 调用 AssetManager.class.newInstance() 反射构造方法异常
            e.printStackTrace();
        } catch (InstantiationException e) {
            // 调用 AssetManager.class.newInstance() 反射构造方法异常
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // getDeclaredMethod 反射方法异常
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // invoke 执行反射方法异常
            e.printStackTrace();
        }
    }
    /**
     * 获取类加载器
     * @return
     */
    public DexClassLoader getmDexClassLoader() {
        return mDexClassLoader;
    }
    /**
     * 获取插件包中的 Package 信息
     * @return
     */
    public PackageInfo getmPackageInfo() {
        return mPackageInfo;
    }
    /**
     * 获取插件包中的资源
     * @return
     */
    public Resources getmResources() {
        return mResources;
    }
}





4、插件管理器


package com.example.plugin_core;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
/**
 * 插件化框架核心类
 */
public class PluginManager {
    /**
     * 类加载器
     * 用于加载插件包 apk 中的 classes.dex 文件中的字节码对象
     */
    private DexClassLoader mDexClassLoader;
    /**
     * 从插件包 apk 中加载的资源
     */
    private Resources mResources;
    /**
     * 插件包信息类
     */
    private PackageInfo mPackageInfo;
    /**
     * 加载插件的上下文对象
     */
    private Context mContext;
    /**
     * PluginManager 单例
     */
    private static PluginManager instance;
    private PluginManager(){
    }
    /**
     * 获取单例类
     * @return
     */
    public static PluginManager getInstance(){
        if (instance == null) {
            instance = new PluginManager();
        }
        return instance;
    }
    /**
     * 加载插件
     * @param context 加载插件的应用的上下文
     * @param loadPath 加载的插件包地址
     */
    public void loadPlugin(Context context, String loadPath) {
        this.mContext = context;
        // DexClassLoader 的 optimizedDirectory 操作目录必须是私有的
        // ( 模式必须是 Context.MODE_PRIVATE )
        File optimizedDirectory = context.getDir("cache_plugin", Context.MODE_PRIVATE);
        // 创建 DexClassLoader
        mDexClassLoader = new DexClassLoader(
                loadPath, // 加载路径
                optimizedDirectory.getAbsolutePath(), // apk 解压缓存目录
                null,
                context.getClassLoader() // DexClassLoader 加载器的父类加载器
        );
        // 加载资源
        try {
            // 通过反射创建 AssetManager
            AssetManager assetManager = AssetManager.class.newInstance();
            // 通过反射获取 AssetManager 中的 addAssetPath 隐藏方法
            Method addAssetPathMethod = assetManager.
                    getClass().
                    getDeclaredMethod("addAssetPath", String.class);
            // 调用反射方法
            addAssetPathMethod.invoke(assetManager, loadPath);
            // 获取资源
            mResources = new Resources(
                    assetManager,
                    context.getResources().getDisplayMetrics(),
                    context.getResources().getConfiguration()
            );
            // 获取插件包中的 Activity 类信息
            mPackageInfo = context.getPackageManager().getPackageArchiveInfo(
                    loadPath, // 加载的插件包路径
                    PackageManager.GET_ACTIVITIES); // 获取的包信息类名
        } catch (IllegalAccessException e) {
            // 调用 AssetManager.class.newInstance() 反射构造方法异常
            e.printStackTrace();
        } catch (InstantiationException e) {
            // 调用 AssetManager.class.newInstance() 反射构造方法异常
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // getDeclaredMethod 反射方法异常
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // invoke 执行反射方法异常
            e.printStackTrace();
        }
    }
    /**
     * 获取类加载器
     * @return
     */
    public DexClassLoader getmDexClassLoader() {
        return mDexClassLoader;
    }
    /**
     * 获取插件包中的 Package 信息
     * @return
     */
    public PackageInfo getmPackageInfo() {
        return mPackageInfo;
    }
    /**
     * 获取插件包中的资源
     * @return
     */
    public Resources getmResources() {
        return mResources;
    }
}





目录
相关文章
|
10月前
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
436 64
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
362 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
807 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
387 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
4月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
482 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
4月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
446 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
4月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
882 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
5月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
665 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
4月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
239 0
|
5月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
391 6