插件化开发:Android端的插件化与ArkUI-X的结合(131)
将 Android 端的插件化架构与 ArkUI-X 跨平台框架结合,是实现“一次开发,三端部署”(HarmonyOS、Android、iOS)以及复杂业务模块解耦的高级工程实践。在这种结合模式下,ArkUI-X 负责提供跨平台的 UI 渲染与业务逻辑,而 Android 原生侧则通过插件化机制来承载底层硬件能力、动态模块加载及复杂的平台交互。
以下是该结合方案的架构设计与实战落地指南:
一、 核心架构设计:插件化与 ArkUI-X 的协同
在大型应用(如华为运动健康)的落地实践中,通常采用以下分层策略:
- 跨平台 UI 与业务层:使用 ArkUI-X 开发核心业务页面,实现一套代码在 Android、iOS 和鸿蒙上复用。
- 平台适配与桥接层(Bridge):针对底层硬件差异(如蓝牙连接、传感器数据、页面跳转),通过 ArkUI-X 提供的 Bridge 机制桥接到 Android 原生插件中。
- Android 插件化宿主层:将 ArkUI-X 的跨平台产物(如 HAP 包)作为插件资源预置到 Android 宿主的 Asset 目录下参与编译。宿主通过 ArkUI-X SDK 提供的接口拉起跨平台页面,同时利用 Android 插件化框架(如 Tinker、VirtualAPK 等)动态管理原生功能插件。
1. Android 宿主层:Activity 与插件注册
在 Android 宿主工程中,ArkUI-X 的跨平台页面通过继承 StageActivity 来承载。以下是一个包含完整导入、插件注册、跨平台实例初始化及参数传递的 Activity 代码。
package com.example.arkuixhost;
import android.content.Intent;
import android.os.Bundle;
import ohos.stage.ability.adapter.StageActivity;
public class EntryEntryAbilityActivity extends StageActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 【核心】必须在 super.onCreate() 之前添加原生插件
// 传入实现了 IArkUIXPlugin 接口的类的完整包名
addPlugin("com.example.arkuixhost.plugins.BluetoothPlugin");
addPlugin("com.example.arkuixhost.plugins.SensorPlugin");
// 设置跨平台实例名称,用于拉起对应的 ArkTS 模块
// 格式通常为: 包名:模块名:Ability名:
setInstanceName("com.example.arkuixhost:entry:EntryAbility:");
// 调用父类 onCreate 启动 ArkUI-X 引擎
super.onCreate(savedInstanceState);
// 演示:从外部拉起该 Activity 时传递 JSON 参数给 ArkTS 侧
handleExternalParams();
}
private void handleExternalParams() {
Intent intent = getIntent();
if (intent != null && intent.hasExtra("params")) {
String jsonParams = intent.getStringExtra("params");
// 将参数透传给 ArkUI-X 引擎
// setStartParams(jsonParams); // 视具体 SDK 版本而定
}
}
@Override
protected void onDestroy() {
// StageActivity 会自动触发插件的 onUnRegistry,
// 但如果有额外的原生资源,需在此处手动释放
super.onDestroy();
}
}
2. 平台适配与桥接层:原生插件与 Bridge 通信
以下代码展示了如何完整实现 IArkUIXPlugin 接口,并包含了一个完整的 Bridge 类,实现了从 ArkTS 调用原生蓝牙设备扫描,以及原生主动向 ArkTS 推送扫描结果的完整双向通信。
package com.example.arkuixhost.plugins;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import org.json.JSONObject;
import ohos.ace.adapter.IArkUIXPlugin;
import ohos.ace.adapter.PluginContext;
import ohos.ace.adapter.capability.bridge.BridgeManager;
import ohos.ace.adapter.capability.bridge.BridgePlugin;
/**
* 蓝牙原生插件:实现生命周期管理与双向通信
*/
public class BluetoothPlugin implements IArkUIXPlugin {
private BluetoothBridge bluetoothBridge;
@Override
public void onRegistry(PluginContext pluginContext) {
// 在 StageActivity.onCreate 时被触发
// 初始化 Bridge,绑定上下文与通信通道名称
bluetoothBridge = new BluetoothBridge(
pluginContext.getContext(),
"BluetoothBridge",
pluginContext.getBridgeManager()
);
}
@Override
public void onUnRegistry(PluginContext pluginContext) {
// 在 StageActivity.onDestroy 时被触发
// 必须释放原生资源,防止内存泄漏
if (bluetoothBridge != null) {
bluetoothBridge.destroy();
bluetoothBridge = null;
}
}
}
/**
* 蓝牙通信桥接器:处理具体的业务逻辑与数据回传
*/
class BluetoothBridge extends BridgePlugin {
private Context context;
public BluetoothBridge(Context context, String bridgeName, BridgeManager manager) {
super(manager, bridgeName);
this.context = context;
}
/**
* 接收来自 ArkTS 侧的调用
*/
@Override
public void onMethodCall(String method, String params, BridgeCallback callback) {
if ("startScan".equals(method)) {
try {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null && adapter.isEnabled()) {
adapter.startDiscovery();
// 成功回调
callback.onSuccess("{\"status\":\"scanning\"}");
} else {
callback.onError("{\"code\":1001,\"msg\":\"Bluetooth disabled\"}");
}
} catch (Exception e) {
callback.onError("{\"code\":500,\"msg\":\"" + e.getMessage() + "\"}");
}
} else {
callback.onError("{\"code\":404,\"msg\":\"Method not found\"}");
}
}
/**
* 原生主动向 ArkTS 侧推送数据(如扫描到设备时)
*/
public void pushDeviceFound(String deviceName, String macAddress) {
try {
JSONObject json = new JSONObject();
json.put("name", deviceName);
json.put("mac", macAddress);
// 主动触发 ArkTS 侧的 onReceive 回调
sendEvent("onDeviceFound", json.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
context = null;
}
}
3. 跨平台 UI 与业务层: ArkTS 调用与工程配置
在 ArkUI-X 跨平台工程中,需要配置参与编译的模块,并在 ArkTS 代码中通过统一的 API 调用上述 Android 原生插件。
工程配置文件:
// .arkui-x/arkui-x-config.json5
{
"crossplatform": true,
"modules": [
"entry", // 主业务模块
"bluetooth" // 独立的蓝牙跨平台模块
]
}
ArkTS 业务调用代码:
// src/main/ets/pages/DeviceListPage.ets
import { bridge } from '@ohos.arkui-x.bridge'; // 假设的 ArkUI-X 桥接 API
@Entry
@Component
struct DeviceListPage {
@State devices: string[] = [];
aboutToAppear() {
// 1. 注册接收原生主动推送的事件监听
bridge.on('BluetoothBridge', 'onDeviceFound', (data: string) => {
const deviceInfo = JSON.parse(data);
this.devices.push(`${deviceInfo.name} (${deviceInfo.mac})`);
});
}
private startScan() {
// 2. 主动调用 Android 原生插件的 startScan 方法
bridge.invoke('BluetoothBridge', 'startScan', {}, (result: string) => {
const res = JSON.parse(result);
if (res.status === 'scanning') {
console.info('原生蓝牙扫描已启动');
}
}, (error: string) => {
console.error('启动扫描失败:', error);
});
}
build() {
Column() {
Button('扫描蓝牙设备')
.onClick(() => this.startScan())
List() {
ForEach(this.devices, (device: string) => {
ListItem() { Text(device) }
})
}
}
}
}
二、 Android 端 ArkUI-X 插件生命周期管理
在 Android 宿主工程中,ArkUI-X 提供了标准的插件接口 IArkUIXPlugin,开发者需实现该接口来管理原生插件的创建与销毁,确保内存安全。
1. 实现插件接口
import ohos.ace.adapter.IArkUIXPlugin;
import ohos.ace.adapter.PluginContext;
import ohos.ace.adapter.capability.bridge.BridgePlugin;
public class MyNativePlugin implements IArkUIXPlugin {
public Bridge myBridge = null;
@Override
public void onRegistry(PluginContext pluginContext) {
// 插件注册时触发:初始化 Bridge 或原生资源
myBridge = new MyBridge(pluginContext.getContext(), "MyTestBridge",
pluginContext.getBridgeManager());
}
@Override
public void onUnRegistry(PluginContext pluginContext) {
// 插件注销时触发:释放原生资源,防止内存泄漏
if (myBridge != null) {
myBridge = null;
}
}
}
2. 在 StageActivity 中注册插件
必须在 super.onCreate() 之前调用 addPlugin 方法,传入插件的完整包名:
import ohos.stage.ability.adapter.StageActivity;
public class EntryActivity extends StageActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 必须在超类 onCreate 之前添加插件
addPlugin("com.example.plugin.MyNativePlugin");
setInstanceName("com.example.app:entry:EntryAbility:");
super.onCreate(savedInstanceState);
}
}
注:StageActivity 会在 onCreate 时触发 onRegistry,在 onDestroy 时触发 onUnRegistry。
三、 原生拉起 ArkUI-X 跨平台页面与传参
在 Android 插件化宿主中,可通过 Intent 拉起 ArkUI-X 的跨平台页面,并支持传递 JSON 格式的参数:
Intent intent = new Intent();
intent.setClass(this, EntryEntryAbilityActivity.class);
intent.putExtra("params",
"{\"params\":[{\"key\":\"userId\",\"type\":10,\"value\":\"12345\"}]}");
startActivity(intent);
Android 侧通过 setInstanceName 接口拉起对应的跨平台 Entry 模块,并将参数无缝传递给 ArkTS 侧。
四、 进阶:结合鸿蒙生态的跨平台插件化
随着 ArkUI-X 5.0.5+ 版本的发布,Android 适配能力得到全面升级,为插件化提供了更灵活的支持:
- Fragment 深度集成:新增支持 Android Fragment 与跨平台界面的无缝对接,开发者可直接在 ArkUI-X 中调用 Fragment 组件,非常适合在插件化架构中将跨页面嵌入原生 Fragment 容器中。
- 原生视图嵌入:通过新增的
XComponent组件,支持在跨平台界面中嵌入 Android 原生 View,实现复杂原生插件(如地图、视频播放器)的混合渲染。 - 内存管理优化:框架自动回收 Activity/ViewController 销毁时的 API 插件内存,大幅降低了插件化架构下的内存泄漏风险。
1. Fragment 深度集成:原生宿主动态加载跨平台页面
在 Android 插件化架构中,将 ArkUI-X 的跨平台页面作为 Fragment 嵌入到原生 Activity 中,实现业务模块的解耦与按需加载。
package com.example.arkuixhost;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import ohos.stage.ability.adapter.StageFragment;
/**
* 原生宿主 Activity:通过 Fragment 容器加载跨平台页面
*/
public class PluginHostActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plugin_host);
// 获取原生布局中的 Fragment 容器
if (savedInstanceState == null) {
// 创建 ArkUI-X 提供的跨平台 Fragment 实例
StageFragment crossPlatformFragment = StageFragment.newInstance(
"com.example.arkuixhost:entry:EntryAbility:" // 对应 ArkTS 侧的实例名
);
// 将跨平台 Fragment 动态添加到原生容器中
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, crossPlatformFragment)
.commit();
}
}
}
2. 原生视图嵌入:跨平台界面集成 Android 原生 View
通过 ArkUI-X 的 XComponent 组件,在跨平台页面中无缝嵌入 Android 原生视图(如高德地图、ExoPlayer 等),实现混合渲染。
// src/main/ets/pages/MapViewPage.ets
import { XComponent, XComponentController, XComponentType } from '@ohos.arkui-x.component';
@Entry
@Component
struct MapViewPage {
private mapController: XComponentController = new XComponentController();
aboutToAppear() {
// 当原生 View 被加载并挂载到 XComponent 时触发
this.mapController.onLoad = () => {
console.info('原生地图 View 已成功嵌入跨平台界面');
// 可在此处通过 Bridge 向原生地图发送初始化坐标等指令
};
}
build() {
Column() {
Text('跨平台业务标题').fontSize(20).margin({ bottom: 10 })
// 使用 XComponent 承载 Android 原生 View
XComponent({
id: 'nativeMapView',
type: XComponentType.SURFACE,
controller: this.mapController
})
.width('100%')
.height(400)
}
.width('100%')
.height('100%')
}
}
3. 内存管理优化:插件化架构下的安全销毁机制
结合 ArkUI-X 5.0.5+ 的自动内存回收特性,在原生侧规范生命周期管理,彻底杜绝插件化场景下的内存泄漏。
package com.example.arkuixhost.plugins;
import android.os.Bundle;
import ohos.stage.ability.adapter.StageActivity;
import ohos.ace.adapter.IArkUIXPlugin;
import ohos.ace.adapter.PluginContext;
/**
* 跨平台宿主 Activity:演示安全的内存回收机制
*/
public class SafeMemoryActivity extends StageActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 注册原生插件
addPlugin("com.example.arkuixhost.plugins.HeavyResourcePlugin");
setInstanceName("com.example.arkuixhost:entry:EntryAbility:");
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
// 【核心】ArkUI-X 5.0.5+ 会在 super.onDestroy() 中自动回收
// 所有已注册 IArkUIXPlugin 的内存与关联的 API 插件。
// 开发者仅需确保在插件的 onUnRegistry 中释放自定义的 Native 资源。
super.onDestroy();
}
}
/**
* 重量级资源插件:遵循自动回收规范
*/
class HeavyResourcePlugin implements IArkUIXPlugin {
@Override
public void onRegistry(PluginContext pluginContext) {
// 初始化重量级原生资源(如音视频解码器、传感器监听)
}
@Override
public void onUnRegistry(PluginContext pluginContext) {
// 框架自动触发:在此处安全释放原生资源,防止内存泄漏
// 无需手动解绑 Activity 引用,框架已接管生命周期
}
}
- 模块化拆分:将健康、运动等独立业务抽离为单独的跨平台 Module,编译为 HAP 包供 Android 宿主按需加载。
- 接口抽象:在跨平台层定义统一的数据接口,通过动态编译脚本或 Bridge 根据宿主平台(Android/iOS/HarmonyOS)注入不同的原生实现。
- 联动编译:利用 ArkUI-X 的 ACE Tools 工具链,支持在 Android Studio 工程中直接触发 ArkTS 代码的联动编译,提升原生与跨平台混合开发的调试效率。
更多推荐

所有评论(0)