RePlugin Sample 示例工程完全解析:宿主接入、内置/外置插件与跨插件通信实战

发布时间:2026/10/15 22:24:08
RePlugin Sample 示例工程完全解析:宿主接入、内置/外置插件与跨插件通信实战 移动开发插件系统原生移动【免费下载链接】RePluginRePlugin - A flexible, stable, easy-to-use Android Plug-in Framework项目地址https://gitcode.com/gh_mirrors/re/RePlugin点击查看免费下载本文基于 RePlugin 开源仓库中的 replugin-sample/README.md系统拆解 RePlugin 官方示例工程的整体结构、模块职责与核心调用方式。Sample 工程并非一个纯粹的演示工程它内部包含了大量可直接参考的调用代码与测试代码覆盖宿主接入、内置插件、外置插件、Kotlin 插件、跨插件通信等接入 RePlugin 时最关心的场景。读完本文你将能够对照仓库源码理清 host 与各 plugin 模块的组织方式掌握RePlugin.startActivity、RePlugin.install、RePlugin.fetchClassLoader、RePlugin.fetchBinder等关键 API 的真实用法并以此为模板搭建自己的插件化工程。一、Sample 工程总体结构四个模块各司其职RePlugin Sample 工程位于仓库的 replugin-sample 目录下顶层划分为host与plugin两大部分其中plugin下又包含四个插件工程。按照原文档的说明各模块的分工如下模块相对路径角色说明hostreplugin-sample/host主程序宿主Sample负责接入 RePlugin SDK并加载、启动各类插件plugin-demo1replugin-sample/plugin/plugin-demo1插件 1 Sample大部分演示逻辑都集中在这里以内置插件内置插件实例方式运行plugin-demo2replugin-sample/plugin/plugin-demo2插件 2 Sample主要是配合插件 1 而做的工作跨插件通信同样以内置插件方式运行plugin-demo3-kotlinreplugin-sample/plugin/plugin-demo3-kotlin插件 3 SampleKotlin 语言编写的插件实例以外置插件方式运行plugin-webviewreplugin-sample/plugin/plugin-webviewWebView 插件 Sample演示插件内 WebView 相关能力外置插件实例原文档明确指出阅读 Sample 代码需要和 RePlugin 的用法相结合因此本文在介绍每个模块时都会同时给出对应的源码路径与关键 API帮助你把示例代码翻译成接入指南。从目录结构看host 与各 plugin 都是独立的 Gradle 工程各自带有gradlew、settings.gradle说明 RePlugin 的宿主与插件在构建层面是解耦的——宿主通过 replugin-host-gradle 插件处理内置插件插件则通过 replugin-plugin-gradle 插件完成编译与打包这也与 Sample 中各模块独立成工程的事实相互印证。二、Host 宿主 Sample接入 RePlugin 的标准姿势Host 工程位于 replugin-sample/host/app其src/main/java下只有五个关键 Java 文件却完整覆盖了宿主接入的核心环节。下面逐一剖析。2.1 SampleApplication宿主初始化的标准模板SampleApplication.java 继承自RePluginApplication这是 RePlugin 宿主接入的最关键一步。对照 AndroidManifestapplication android:name.SampleApplication ... 也就是说宿主 Application 必须指向这个自定义类RePlugin 的框架初始化才会在attachBaseContext阶段完成。SampleApplication内部依次演示了三件事开启调试模式attachBaseContext中// FIXME 允许接收rpRunPlugin等Gradle Task发布时请务必关掉以免出现问题 RePlugin.enableDebugger(base, BuildConfig.DEBUG);源码注释提醒enableDebugger允许宿主接收rpRunPlugin等 Gradle Task 的指令发布时务必关闭以免出现安全问题。通过createConfig()定制 RePlugin 运行行为Override protected RePluginConfig createConfig() { RePluginConfig c new RePluginConfig(); // 允许插件使用宿主类。默认为关闭 c.setUseHostClassIfNotFound(true); // FIXME RePlugin默认会对安装的外置插件进行签名校验这里先关掉避免调试时出现签名错误 c.setVerifySign(!BuildConfig.DEBUG); // 针对安装失败等情况来做进一步的事件处理 c.setEventCallbacks(new HostEventCallbacks(this)); // FIXME 若宿主为Release则此处应加上您认为合法的插件的签名 // RePlugin.addCertSignature(AAAAAAAAA); // 在Art上优化第一次loadDex的速度 // c.setOptimizeArtLoadDex(true); return c; }这段代码是宿主配置的标准答案模板涉及四个核心配置项setUseHostClassIfNotFound(true)允许插件在自身找不到某个类时回退使用宿主类。默认为关闭Sample 中显式打开。setVerifySign(!BuildConfig.DEBUG)控制是否校验外置插件签名。调试阶段关闭Release 阶段开启同时源码注释建议在 Release 时通过RePlugin.addCertSignature(...)显式登记合法插件的签名。setEventCallbacks(...)注册事件回调用于处理插件安装失败等异常场景。注释中还保留了setOptimizeArtLoadDex(true)的示例在 Art 虚拟机上优化第一次loadDex的速度对应 Dex2OatUtils.java 的实现。通过createCallbacks()与事件回调定制行为createCallbacks()返回HostCallbacks其中覆写了onPluginNotExistsForActivity——当要打开的插件没有安装时触发源码注释明确说明在这里可以打开下载对话框并开始下载并把intent传递到对话框内以便下载完成后直接打开对应插件的 Activity这正是动态下发插件场景的接入点。HostEventCallbacks则覆写了两个事件onInstallPluginFailed(String path, InstallResult code)插件安装失败时触发可用于打点统计或特殊处理onStartActivityCompleted(String plugin, String activity, boolean result)打开 Activity 完成时触发可用于 APM、打点统计。2.2 MainActivity宿主调用插件的核心演示MainActivity.java 是宿主 UI 的入口布局见 activity_main.xml六个按钮分别演示了六类典型用法1以包名打开内置插件 Activity// 刻意以包名来打开 RePlugin.startActivity(MainActivity.this, RePlugin.createIntent(com.qihoo360.replugin.sample.demo1, com.qihoo360.replugin.sample.demo1.MainActivity));这里演示了RePlugin.createIntent(plugin, activity)与RePlugin.startActivity的配合第一个参数既可以传插件名Alias也可以传插件的包名两种方式都有效。2以别名Alias打开并期望返回结果Intent intent new Intent(); intent.setComponent(new ComponentName(demo1, com.qihoo360.replugin.sample.demo1.activity.for_result.ForResultActivity)); RePlugin.startActivityForResult(MainActivity.this, intent, REQUEST_CODE_DEMO1, null);注意ComponentName的第一个参数用了demo1插件名而非完整包名这是 RePlugin 支持的Alias 打开方式。宿主通过onActivityResult接收插件返回的数据RESULT_CODE_DEMO1 0x012对应插件侧的 ForResultActivity.java。3加载插件中的 FragmentstartActivity(new Intent(MainActivity.this, PluginFragmentActivity.class));这一步跳转到宿主的PluginFragmentActivity详见 2.3演示如何把插件里的 Fragment 展示到宿主的界面上。4检查并打开外置插件demo3if (RePlugin.isPluginInstalled(demo3)) { RePlugin.startActivity(MainActivity.this, RePlugin.createIntent(demo3, com.qihoo360.replugin.sample.demo3.MainActivity)); } else { Toast.makeText(MainActivity.this, You must install demo3 first!, Toast.LENGTH_SHORT).show(); }外置插件可能尚未安装所以先用RePlugin.isPluginInstalled(demo3)判断这是外置插件场景下必备的防御性检查。5模拟安装外置插件simulateInstallExternalPlugin()方法完整演示了外置插件的安装流程// 文件是否已经存在直接删除重来 String pluginFilePath getFilesDir().getAbsolutePath() File.separator demo3Apk; File pluginFile new File(pluginFilePath); if (pluginFile.exists()) { FileUtils.deleteQuietly(pluginFile); } // 开始复制把 assets/external/demo3.apk 拷到 files/ 目录 copyAssetsFileToAppFiles(demo3apkPath, demo3Apk); PluginInfo info null; if (pluginFile.exists()) { info RePlugin.install(pluginFilePath); } if (info ! null) { RePlugin.startActivity(MainActivity.this, RePlugin.createIntent(info.getName(), com.qihoo360.replugin.sample.demo3.MainActivity)); } else { Toast.makeText(MainActivity.this, install external plugin failed, Toast.LENGTH_SHORT).show(); }关键点在于RePlugin.install(pluginFilePath)返回的PluginInfo外置插件必须先install拿到PluginInfo再用info.getName()获取其动态插件名而不能像内置插件那样直接写死插件名。这正是 PluginFragmentActivity.java 顶部注释所强调的规则详见 2.4。6线程 ClassLoader 自检testThreadClassLoader()检查Thread.currentThread().getContextClassLoader() getClassLoader()。源码注释解释在 2.1.7 及以前版本直接调用此方法拿到的 ClassLoader 可能是PathClassLoader或为空有极个别 Java 库会用到此方法因此这里确保线程上下文 ClassLoader 与宿主一致这是插件化环境下容易踩的隐藏坑。2.3 PluginFragmentActivity在宿主中展示插件 FragmentPluginFragmentActivity.java 演示了插件 Fragment 的两种使用路径路径一XML/类名 Hook 方式RePlugin.registerHookingClass(com.qihoo360.replugin.sample.demo1.fragment.DemoFragment, RePlugin.createComponentName(pluginName, com.qihoo360.replugin.sample.demo1.fragment.DemoFragment), null);源码注释说明注册一个全局 Hook用于拦截系统对某类的寻找并定向到插件中的对应类主要目的是让 XML 布局中可以直接使用插件中的类。路径二代码中通过插件 ClassLoader 创建 FragmentClassLoader d1ClassLoader RePlugin.fetchClassLoader(pluginName); // 获取插件的ClassLoader Fragment fragment d1ClassLoader.loadClass(com.qihoo360.replugin.sample.demo1.fragment.DemoCodeFragment) .asSubclass(Fragment.class).newInstance(); // 使用插件的Classloader获取指定Fragment实例 getSupportFragmentManager().beginTransaction().add(R.id.container2, fragment).commit(); // 添加Fragment到UI这段代码揭示了RePlugin.fetchClassLoader(pluginName)的典型用法拿到插件 ClassLoader 后通过反射实例化插件内的 Fragment再交给宿主的FragmentManager托管。2.4 内置插件与外置插件的核心差异PluginFragmentActivity.java 顶部的注释是对内置/外置插件差异最权威的说明原文如下如果一个插件是内置插件那么这个插件的名字就是文件的前缀比如demo1.jar 插件的名字就是 demo1host-gradle 插件自动生成可以执行诸如RePlugin.fetchClassLoader(demo1)的操作如果一个插件是外置插件通过RePlugin.install(/sdcard/demo1.apk)安装的则必须动态获取这个插件的名字来使用PluginInfo pluginInfo RePlugin.install(/sdcard/demo1.apk); RePlugin.preload(pluginInfo); // 耗时 String name pluginInfo ! null ? pluginInfo.getName() : null; ClassLoader classLoader RePlugin.fetchClassLoader(name);对照宿主资源目录可以看得更清楚内置插件放在 replugin-sample/host/app/src/main/assets/plugins 下包括demo1.jar、demo2.jar、webview.jar。这些 jar 由 replugin-host-gradle 插件在构建期处理插件名即文件名前缀demo1、demo2、webview宿主启动时自动安装。外置插件放在 replugin-sample/host/app/src/main/assets/external 下目前只有demo3.apk由 plugin-demo3-kotlin 编译生成。它需要运行时手动RePlugin.install()安装详见 external/README。external/README 还额外说明了外置插件演示的设计意图将待安装的外置插件临时放在 assets/external 下其实开发者完全可以把外置插件放到 /sdcard、/data 等其他目录注意存储权限从 assets 拷贝到/data/data/packageName/files/的过程本质上就是在模拟外置插件首次安装时的下载过程。三、plugin-demo1内置插件的能力全景图plugin-demo1 是演示逻辑最丰富的模块源码目录覆盖了 Activity 各种启动模式、Theme、Service、Provider、Receiver、跨插件通信、AAR、WebView、FileProvider、通知等几乎全部插件能力。其 AndroidManifest.xml 本身就是一份插件组件如何声明的参考模板。3.1 入口与 ApplicationMainApp.java 演示了插件 Application 的用法——在onCreate中启动一个 Serviceprivate void testStartService() { Intent i new Intent(this, PluginDemoAppService.class); i.setAction(MyNameIsApp); startService(i); }源码注释说这是为了模拟个别插件的复杂行为插件 Application 启动时即可拉起自己的服务。MainActivity.java 则以 ListView Button 列表的形式罗列了全部测试项TestItem是理解各插件能力的最直观入口。3.2 Activity 启动模式与 Task 相关能力demo1 的activity目录按场景分包几乎覆盖了 Android 启动模式的全集场景示例类Manifest 关键配置标准模式StandardActivity.java无特殊配置singleTopSingleTopActivity1.javalaunchModesingleTopsingleInstanceTIActivity1.javalaunchModesingleInstancetaskAffinity多页task_affinity 下的 TAActivity1~4统一taskAffinity:ta_1主题样式theme 下三个 ActivityTheme.Black.NoTitleBar、Theme.Dialog、Theme.Black.NoTitleBar.FullscreenIntentFilter 隐式跳转IntentFilterDemoActivity1.javaaction android:nameandroid.intent.action.demo1/category_demostartActivityForResultForResultActivity.javasetResult(0x012, intent)后立即 finishWebViewWebViewActivity.java插件内 WebViewFileProviderFileProviderActivity.java插件内 FileProviderPreferencePrefActivity1/2PreferenceActivity这些 Activity 在 Manifest 中的声明方式AndroidManifest.xml可以直接照搬——插件内的 Activity 与普通 App 的声明没有区别这正是 RePlugin 无需在宿主预注册 的体现。demo1 的MainActivity中还演示了多种打开方式的等价性// 直接以 Intent 组件类打开插件内部跳转 Intent intent new Intent(v.getContext(), StandardActivity.class); v.getContext().startActivity(intent); // 通过 Action 隐式打开 Intent intent new Intent(com.qihoo360.replugin.sample.demo1.action.theme_fullscreen); intent.addCategory(com.qihoo360.repluginapp.replugin.demo1.CATEGORY1); v.getContext().startActivity(intent); // 以 Action 打开另一个插件demo2的 Activity Intent intent new Intent(com.qihoo360.replugin.sample.demo2.action.theme_fullscreen_2); RePlugin.startActivity(v.getContext(), intent, demo2, null);其中关于 category 有一条非常实用的注释经验若 Intent 中声明 categorymanifest 中未声明则无法找到 Activity若 manifest 中声明 categoryIntent 中未声明则可以找到 Activity。3.3 Service 与 Provider进程映射是关键demo1 的 Manifest 演示了插件 Service 的进程声明方式meta-data android:nameprocess_map android:value[ {from:com.qihoo360.replugin.sample.demo1:bg,to:$p0} ] / service android:name.service.PluginDemoService1 android:exportedfalse android:process:bg /这里的process_map是 RePlugin 的进程映射机制插件声明的:bg进程会被映射到宿主的坑位进程$p0对应宿主库中的ProcessPitProviderP0等占坑组件参见 replugin-host-library 目录。demo1 的 MainActivity.java 分别演示了显式启动 Service:p0进程与隐式启动 Service:UI进程两种方式。Provider 方面Provider2.java 声明为authoritiescom.qihoo360.replugin.sample.demo1.provider2由宿主通过ContentResolver.insert()跨进程调用见 demo1 MainActivity 中的 Provider: Query (at UI process) 测试项。3.4 跨插件通信三种官方推荐玩法demo1 与 demo2 的配合是跨插件通信的官方教材在 demo1 的 MainActivity.java 中集中展示了三种方式玩法一反射调用推荐天然版本隔离ClassLoader cl RePlugin.fetchClassLoader(demo2); Class clz cl.loadClass(com.qihoo360.replugin.sample.demo2.MainApp); Method m clz.getDeclaredMethod(helloFromDemo1, Context.class, String.class); m.invoke(null, v.getContext(), Demo1);源码注释强调这是 RePlugin 的推荐玩法反射调用 Demo2这样天然的做好了版本控制避免出现我们当年 2013 年的各种问题。即使 demo2 升级导致类或方法不存在也只是抛出异常不会影响 demo1 自身。玩法二跨插件资源复用LinearLayout contentView RePlugin.fetchViewByLayoutName(demo2, from_demo1, null);RePlugin.fetchViewByLayoutName(plugin, layoutName, context)直接取出 demo2 插件中的from_demo1布局并转成 Viewdemo2 的布局文件正是 from_demo1.xml。玩法三AIDL Binder 快速获取IBinder b RePlugin.fetchBinder(demo2, demo2test); IDemo2 demo2 IDemo2.Stub.asInterface(b); demo2.hello(helloooooooooooo);对应 demo2 侧的注册逻辑见 MainApp.javaRePlugin.registerPluginBinder(demo2test, new Demo2Impl());以及 AIDL 实现 Demo2Impl.java继承IDemo2.Stub。AIDL 接口定义位于 IDemo2.aidldemo1 与 demo2 共享同一份 AIDL 定义。3.5 其他能力AAR、WebView、FileProvider、通知demo1 还验证了与第三方/公共组件的兼容性AAR直接startActivity打开 library 中的 LibMainActivity对应布局 lib_activity_main.xml验证插件内引用 AAR 代码的可行性WebView插件内 WebView 场景webview 目录FileProvider插件内 FileProvider 场景provider/FileProvider.java其 Manifest 注释特别说明以下 provider作为插件时可注释掉作为单独 APK 时需要声明通知通过 NotifyUtils.java 发送通知并在 Android 13 上申请POST_NOTIFICATIONS权限。此外case.gradle 展示了一个可选的构建技巧当multiDexEnabled打开时可以额外引入 okhttp、gson、play-services 等较大依赖来模拟复杂插件的多 dex 场景。四、plugin-demo2配合型插件的三种示范plugin-demo2源码目录体量较小但功能非常聚焦专门负责配合插件 1 而做的工作验证三类能力1跨插件通信能力MainApp.onCreate中RePlugin.registerPluginBinder(demo2test, new Demo2Impl())配合静态方法helloFromDemo1分别支撑 demo1 的 Binder 快速获取与反射调用两种玩法见 3.4。2AppCompat 兼容AppCompatActivityDemo.java 验证插件内使用AppCompatActivity的能力。3DataBindingDataBindingActivity.java 与 Entry.java 验证插件内使用 DataBinding 的能力布局见 databinding_test.xml。此外还有 TestMultiDex.java 用于测试多 dex 场景。demo2 的 MainActivity.java 用纯代码构建 UI无 XML展示了最小插件的写法。五、plugin-demo3-kotlinKotlin 插件与外置安装流程plugin-demo3-kotlin 是用 Kotlin 编写、以外置插件形态运行的示例源码目录验证了 RePlugin 对 Kotlin 语言插件的完整支持。其 MainActivity.kt 打开时会弹出 Hello Kotlin ! Hello RePlugin ! 的 Toast并同样演示了 Kotlin 插件中三类能力的写法// Kotlin 插件内打开自身主题 Activity val intent Intent(v.context, ThemeBlackNoTitleBarActivity::class.java) v.context.startActivity(intent) // Kotlin 插件发送广播 val intent Intent() intent.action com.qihoo360.repluginapp.replugin.receiver.ACTION3 v.context.sendBroadcast(intent) // Kotlin 插件跨插件反射调用 demo2推荐玩法 val cl RePlugin.fetchClassLoader(demo2) val clz cl.loadClass(com.qihoo360.replugin.sample.demo2.MainApp) val m clz.getDeclaredMethod(helloFromDemo1, Context::class.java, String::class.java) m.invoke(null, v.context, Demo3)结合 2.2 与 2.4 可知demo3 的完整运行链路是宿主将demo3.apk从 assets/external 拷贝到 files 目录 →RePlugin.install()安装 →info.getName()获取插件名 →RePlugin.startActivity打开。Kotlin 插件在安装、加载、运行层面与 Java 插件并无差异。六、plugin-webviewWebView 插件独立示例plugin-webview 是独立的 WebView 插件工程源码目录内含common/通用 WebView 封装CommonWebView.java、CommonWebViewClient、CommonWebChromeClientviews/自定义 WebView 视图SimpleWebView.java、SimpleWebPageutils/WebView 资源加载辅助WebViewResourceHelper.java 等。宿主 MainActivity.java 中的 btn_start_demo4 按钮演示了打开方式if (RePlugin.isPluginInstalled(webview)) { RePlugin.startActivity(MainActivity.this, RePlugin.createIntent(webview, com.qihoo360.replugin.sample.webview.MainActivity)); } else { Toast.makeText(MainActivity.this, You must install webview first!, Toast.LENGTH_SHORT).show(); }webview.jar同样作为内置插件放在 assets/plugins 下安装后插件名即webview。七、构建与运行指引7.1 工程与仓库配置host 与各插件是彼此独立的 Gradle 工程。以 host 为例settings.gradle 展示了插件仓库的配置方式pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() mavenLocal() maven { allowInsecureProtocol true url http://maven.geelib.360.cn/nexus/repository/replugin/ } } resolutionStrategy { eachPlugin { if (requested.id.id com.qihoo360.replugin.replugin-host-gradle) { useModule(com.qihoo360.replugin:replugin-host-gradle: requested.version) } ... } } }这里将com.qihoo360.replugin.replugin-host-gradle插件 id 解析到com.qihoo360.replugin:replugin-host-gradle构件——即仓库中的 replugin-host-gradle 模块它负责在宿主构建期自动处理assets/plugins下的内置插件。7.2 内置插件的产物形态内置插件在 assets/plugins 下的产物是jardemo1.jar、demo2.jar、webview.jar而外置插件产物是apkdemo3.apk由 plugin-demo3-kotlin 编译生成。这一差异对应 RePlugin 的两类安装路径内置 jar由 host-gradle 插件在构建期合并进宿主 APK启动时自动安装插件名 文件名前缀外置 apk运行时通过RePlugin.install(path)手动安装插件名需从返回的PluginInfo动态获取。7.3 调试与发布建议结合 SampleApplication.java 中的 FIXME 注释运行 Sample 时有几点注意事项Debug 构建下RePlugin.enableDebugger(base, true)与setVerifySign(false)均会关闭签名校验与调试限制便于本地调试Release 构建务必恢复签名校验并登记合法插件签名外置插件演示demo3首次点击Install From Assets按钮时会模拟下载→安装→启动的完整链路如果打开 demo3 前未安装宿主会 Toast 提示 You must install demo3 first!这是RePlugin.isPluginInstalled防御性检查的预期行为。八、Sample 中高频 RePlugin API 速查表以下是 Sample 工程中使用到的高频 API 及其语义汇总可作为接入时的速查清单API语义Sample 出处RePlugin.startActivity(ctx, intent)启动插件 Activity参数可传插件名或包名host MainActivityRePlugin.createIntent(plugin, activity)构建指向插件 Activity 的 Intenthost MainActivityRePlugin.startActivityForResult(ctx, intent, requestCode, extras)带结果返回地启动插件 Activityhost MainActivityRePlugin.isPluginInstalled(name)判断插件是否已安装host MainActivityRePlugin.install(path)安装外置插件返回PluginInfohost MainActivityRePlugin.fetchClassLoader(name)获取插件 ClassLoader用于反射调用host PluginFragmentActivity、demo1RePlugin.fetchViewByLayoutName(plugin, layoutName, ctx)获取插件内布局生成的 Viewdemo1 MainActivityRePlugin.fetchBinder(plugin, binderKey)快速获取插件注册的 Binderdemo1 MainActivityRePlugin.registerPluginBinder(key, binder)插件侧注册 Binder 供其他插件获取demo2 MainAppRePlugin.registerHookingClass(from, to, methods)Hook 类查找支持 XML 中使用插件类host PluginFragmentActivityRePlugin.enableDebugger(ctx, enable)开启/关闭调试模式发布必须关闭host SampleApplicationRePlugin.addCertSignature(signature)登记合法插件签名Release 必配host SampleApplication注释示例以上 API 的底层实现可在 RePlugin.java宿主侧与 RePlugin.java插件侧中进一步查阅两侧 API 分工不同插件侧提供registerPluginBinder等能力宿主侧提供install、fetchClassLoader、startActivity等能力。九、总结如何把 Sample 工程变成自己的接入模板回到原文档的核心论断——它并非是纯粹的工程其内部包含了大量可供参考的调用代码并含有一些测试代码帮助开发者在接入时能够对 RePlugin 有所了解。对照源码我们可以总结出四条可复用的接入路径宿主接入照抄 SampleApplication.java 的RePluginApplication继承 createConfig/createCallbacks定制即可完成框架初始化内置插件接入参考 plugin-demo1正常开发 APK 并在 Manifest 中声明组件构建期交给 host-gradle 插件打包成 jar 放入assets/plugins外置插件接入参考 plugin-demo3-kotlin external/README 的安装链路在运行时RePlugin.install()动态下发跨插件通信优先采用 demo1 MainActivity 中的反射 ClassLoader方案必要时使用fetchBinderregisterPluginBinder的 AIDL 方案以获得天然的版本隔离与更优的性能表现。建议在接入阶段以本工程为最小可运行骨架逐步替换为自己的业务代码同时配合 replugin-host-library 与 replugin-plugin-library 中的 SDK 源码深入理解每个 API 的底层实现即可在较短时间内完成 RePlugin 的完整接入。赞分享移动开发插件系统原生移动【免费下载链接】RePluginRePlugin - A flexible, stable, easy-to-use Android Plug-in Framework项目地址https://gitcode.com/gh_mirrors/re/RePlugin点击查看免费下载相关推荐GPT-2 Medium模型压缩技术量化、剪枝与蒸馏的完整教程GPT 2 Medium模型压缩技术量化、剪枝与蒸馏的完整教程 GPT 2 Medium作为一款性能优异的语言模型在自然语言处理领域有着广泛应用。然而其较VirtualAPK 插件化框架实战指南宿主与插件工程接入、插件打包与核心运行原理VirtualAPK 插件化框架实战指南宿主与插件工程接入、插件打包与核心运行原理 VirtualAPK 是滴滴开源的一款轻量级 Android 插件化框架移动开发插件系统如何解决全志H6机顶盒在Armbian系统中的网络适配问题如何解决全志H6机顶盒在Armbian系统中的网络适配问题 全志H6平台机顶盒如天敏TM7Pro在Armbian系统中面临网络功能失效的挑战表现为系统启动嵌入式开发工具构建工具操作系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询