HarmonyOS 7 新特性(二十四)|ModularObjectExtensionAbility 与 Taihe IPC

HarmonyOS 7(API 26)Beta2 新增基于 ModularObjectExtensionAbility 的模块化对象开发指导,并提供使用 Taihe 生成 IPC 通信代码的路径。该能力涉及跨应用调用与 Native 接口,接入时应以当前 C/C++ 指南和权限规则为准。
很多团队希望把文档转换、媒体处理或专业计算能力开放给其他应用,却容易走向两个极端:要么复制同一套代码到多个工程,要么暴露过大的远程服务接口。模块化对象模型提供了更清晰的边界:服务端把特定功能封装为独立模块并暴露 Proxy,客户端通过连接获得对象并跨进程调用。
本文以“文档应用开放 PDF 转换能力”为例,拆解接口设计、连接生命周期、Taihe 代码生成、身份校验、超时和版本兼容。
一、先判断是否真的需要跨应用
同一应用内部复用,优先使用 HAR/HSP 或普通领域模块;跨设备调用应评估分布式能力;只有当独立应用需要调用受控功能,且服务端必须保留实现与资源所有权时,才适合 ModularObjectExtensionAbility。
跨应用会引入进程死亡、权限、序列化、版本和调试成本。不要为了“架构高级”把简单函数变成 IPC。
二、四个核心角色
官方模型包含服务端、客户端、Stub 和 Proxy。服务端 Extension 创建 Stub 处理请求;系统把它转换成客户端可用的 Proxy;客户端通过 Connect 建立连接,通过 Disconnect 结束生命周期。
Client App
-> Connect(bundleName/moduleName/abilityName)
-> Proxy.convert(request)
System IPC
-> Stub.onConvert(request)
-> Domain Service
<- structured result
Proxy 与 Stub 是通信边界,复杂业务逻辑应放在领域服务中。
三、接口先做窄而稳定
interface ConvertRequest {
requestId: string
sourceUri: string
targetFormat: 'pdf' | 'png'
options: {
quality: 'standard' | 'high'
pageRange?: string
}
}
type ConvertResponse =
| { ok: true; requestId: string; outputUri: string; sha256: string }
| { ok: false; requestId: string; code: string; retryable: boolean }
不要传递任意文件路径或让客户端控制服务端内部目录。输入使用受控 URI,输出返回只读或有时效的 URI。

四、版本字段不可省略
客户端和服务端可能独立升级。每个协议声明主版本、次版本与能力列表,连接成功后先协商,再调用具体方法。
interface ModuleHandshake {
protocolMajor: number
protocolMinor: number
capabilities: string[]
maxPayloadBytes: number
}
function isCompatible(local: ModuleHandshake, remote: ModuleHandshake): boolean {
return local.protocolMajor === remote.protocolMajor
}
新增可选字段通常兼容,改变字段语义或删除方法属于破坏性变化,应提升主版本并保留迁移期。
五、Taihe 生成代码仍要审查
Taihe 可以减少手写 IPC 样板,但生成代码不是业务正确性的证明。审查重点包括:类型映射是否正确、错误码是否完整、对象所有权由谁释放、连接断开回调是否覆盖、生成文件是否能稳定再生。
将接口定义文件纳入版本控制,把生成命令固定到构建脚本。不要直接修改生成文件,否则下次再生会丢失修改。
contracts/
document_converter.taihe
generated/
document_converter_proxy.*
document_converter_stub.*
service/
converter_domain_service.*
六、连接管理是状态机
每次连接会创建新的 Extension 实例。客户端必须处理连接中、已连接、断开、服务端死亡和重试。
type ConnectionState =
| { kind: 'idle' }
| { kind: 'connecting'; attempt: number }
| { kind: 'ready'; sessionId: string }
| { kind: 'disconnected'; reason: string }
class ModuleConnection {
state: ConnectionState = { kind: 'idle' }
private pending = new Map<string, AbortController>()
disconnect(reason: string) {
for (const task of this.pending.values()) task.abort()
this.pending.clear()
this.state = { kind: 'disconnected', reason }
}
}
页面销毁不一定代表共享连接应立即断开,应由应用级连接管理器统一所有权。
七、跨进程请求必须有超时和幂等
服务端可能繁忙或进程被系统回收。请求携带稳定 requestId,服务端对重复请求返回已有结果或明确状态。客户端超时后不能假设任务没有执行。
async function callWithTimeout<T>(job: Promise<T>, timeoutMs: number): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('IPC_TIMEOUT')), timeoutMs)
)
return Promise.race([job, timeout])
}
耗时转换最好返回任务句柄并提供查询接口,避免单个 IPC 长时间占用。
八、安全校验放在服务端
服务端验证调用方身份、能力授权、输入 URI、大小、格式和调用频率。客户端界面上的禁用按钮不能替代服务端校验。
敏感动作应要求用户可感知确认;临时文件使用隔离目录并按任务清理;日志只记录请求 ID 和错误码,不记录文档内容。
九、失败和回退
客户端无法连接时可提示安装/升级服务提供方,或回退到本地轻量能力。版本不兼容应返回明确错误并引导升级,不能无限重连。
服务端重启后未完成任务需要根据持久化策略恢复或标记失败。中间文件必须能被定期清理,防止断点任务占满存储。
十、验证矩阵
describe('module protocol', () => {
it('rejects a different major version', () => {
expect(isCompatible(v1Client, v2Server)).toBe(false)
})
it('deduplicates the same request id', async () => {
await service.convert(request)
await service.convert(request)
expect(worker.callCount).toBe(1)
})
})
真机覆盖:首次连接、并发调用、服务端被杀、客户端后台、权限拒绝、超大文件、协议不兼容和断开重连。
十一、上线清单
- 已证明跨应用调用的必要性;
- 接口窄、结构化、带版本与稳定错误码;
- Taihe 生成物可重复生成且未手改;
- 连接、断开与服务端死亡都有处理;
- 请求有超时、幂等和迟到结果策略;
- 服务端完成身份、URI、大小与频率校验;
- 临时文件、日志和连接都有明确生命周期。

结语
模块化对象的价值在于“安全开放一个明确能力”,而不是把整个应用变成远程对象。用稳定契约约束 Proxy/Stub,用连接状态机处理进程不可靠性,再让 Taihe 负责可生成的通信样板,跨应用能力才能长期演进。
官方参考
- 模块化对象模型概述:https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/modular-object-extension-overview
- 模块化对象开发指导:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/modular-object-extension-ability
更多推荐


所有评论(0)