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

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

文章目录

Android 插件化系列文章目录

前言

一、" 宿主 " 模块启动 " 插件 " 模块过程

1、" 插件 " 模块类名获取

2、" 插件 " 模块类加载器获取

二、" 宿主 " 模块加载 " 插件 " 模块中的资源文件


前言

上一篇博客 【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 ) 中对注入的上下文进行了相关代理操作 , 插件包中的界面组件 PluginActivity 凡是涉及上下文的操作 , 都统一委托给注入的上下文来完成 ;





一、" 宿主 " 模块启动 " 插件 " 模块过程



1、" 插件 " 模块类名获取


加载 " 插件 " 模块 apk 安装包 :


拷贝插件包 : 应用启动后 , 先将插件包 apk 文件从 assets 目录拷贝到 getExternalFilesDir(null) 目录中 ;


加载插件包 : 使用 PluginManager 加载插件包 ;


/*
    加载 " 插件 " 模块的 apk 文件
    先将该插件包拷贝到
 */
String path = getExternalFilesDir(null).getAbsolutePath() + "/plugin-debug.apk";
PluginManager.getInstance().loadPlugin(this, path);



获取 " 插件 " 模块中的 Activity 数组信息 :


// 获取  " 插件 " 模块中的 Activity 数组信息
ActivityInfo[] activityInfos = PluginManager.getInstance().getmPackageInfo().activities;
1
2
获取插件包信息 : 其中的 loadPath , 就是 getExternalFilesDir(null).getAbsolutePath() + "/plugin-debug.apk" 路径 ;
/**
 * 插件化框架核心类
 */
public class PluginManager {
    /**
     * 插件包信息类
     */
    private PackageInfo mPackageInfo;
    /**
     * 加载插件
     * @param context 加载插件的应用的上下文
     * @param loadPath 加载的插件包地址
     */
    public void loadPlugin(Context context, String loadPath) {
        this.mContext = context;
            // 获取插件包中的 Activity 类信息
            mPackageInfo = context.getPackageManager().getPackageArchiveInfo(
                    loadPath, // 加载的插件包路径
                    PackageManager.GET_ACTIVITIES); // 获取的包信息类名
    }
    /**
     * 获取插件包中的 Package 信息
     * @return
     */
    public PackageInfo getmPackageInfo() {
        return mPackageInfo;
    }
}


获取要启动的 Activity 全类名 : 获取插件包中的 Launcher Activity 的全类名 , 并封装到 Intent 中 , 启动 Activity ;


 

public void onClick(View view) {
        // 跳转到 plugin_core 模块的代理 Activity
        // 首先要获取 " 插件 " 模块中的入口 Activity 类
        Intent intent = new Intent(this, ProxyActivity.class);
        // 获取  " 插件 " 模块中的 Activity 数组信息
        ActivityInfo[] activityInfos = PluginManager.getInstance().getmPackageInfo().activities;
        // 获取的插件包中的 Activity 不为空 , 才进行界面跳转
        if (activityInfos.length > 0) {
            // 这里取插件包中的第 0 个 Activity
            // 次序就是在 AndroidManifest.xml 清单文件中定义 Activity 组件的次序
            // 必须将 Launcher Activity 定义在第一个位置
            // 不能在 Launcher Activity 之前定义 Activity 组件
            // 传入的是代理的目标组件的全类名
            intent.putExtra("CLASS_NAME", activityInfos[0]);
            startActivity(intent);
        }
    }


特别注意在插件包的 AndroidManifest.xml 清单文件中定义 Activity 组件的次序 , Launcher Activity 必须定义为底 1 11 个 ;


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.plugin">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Plugin">
        <activity android:name=".PluginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>



2、" 插件 " 模块类加载器获取


拿到了插件包中要启动 Activity 的全类名 , 在 ProxyActivity 中 , 就可以根据该 Activity 全类名 , 使用 从 PluginManager 中获取的 类加载器 , 使用 反射 加载该全类名对应的 Activity 类 , 并使用反射初始化该类 ;


/**
 * 该 Activity 只是个空壳 ;
 * 主要用于持有从 apk 加载的 Activity 类
 * 并在 ProxyActivity  声明周期方法中调用对应 PluginActivity 类的生命周期方法
 */
public class ProxyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_proxy);
        // 要代理的目标组件的全类名
        className = getIntent().getStringExtra("CLASS_NAME");
        // 注意此处的 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();
        }
    }
}


注意 ProxyActivity 的 getClassLoader 必须被覆盖 , 否则 使用 " 宿主 " 模块的类加载器 无法查找到 " 插件 " 模块安装包中的字节码类 ;


/**
 * 该 Activity 只是个空壳 ;
 * 主要用于持有从 apk 加载的 Activity 类
 * 并在 ProxyActivity  声明周期方法中调用对应 PluginActivity 类的生命周期方法
 */
public class ProxyActivity extends AppCompatActivity {
    /**
     * 需要使用插件包加载的类加载器
     * @return
     */
    @Override
    public ClassLoader getClassLoader() {
        return PluginManager.getInstance().getmDexClassLoader();
    }
}



目录
相关文章
|
3月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
4月前
|
存储 Android开发 开发者
深入理解安卓应用开发的核心组件
【10月更文挑战第8天】探索Android应用开发的精髓,本文带你了解安卓核心组件的奥秘,包括Activity、Service、BroadcastReceiver和ContentProvider。我们将通过代码示例,揭示这些组件如何协同工作,构建出功能强大且响应迅速的应用程序。无论你是初学者还是资深开发者,这篇文章都将为你提供新的视角和深度知识。
|
4月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
151 0
|
2月前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
4月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
112 6
|
4月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
41 3
|
4月前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
41 3
|
4月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
4月前
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
80 6
|
4月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
33 0

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 3
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 7
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 10
    Android学习自定义View(四)——继承控件(滑动时ListView的Item出现删除按钮)