跳转到正文

HarmonyOS 接入 ​

需要查某个方法的参数、返回值或回调时,查看 HarmonyOS 方法参考。

HarmonyOS SDK 使用 ArkTS 与 ArkUI,公开模块为 @popoim/sdk。宿主提供会话、通讯录所在的主导航以及应用生命周期,SDK 管理聊天、资料、群与通话内部流程。

环境与模块接入 ​

最低 HarmonyOS NEXT 5.0.0 / API 12,当前面向手机。源码工程使用 DevEco Studio 5.0.0 Release 对应工具链,已验证构建号 5.0.3.910;选择工具链时应保持工程的 API 12 与 runtimeOS: HarmonyOS 配置一致。

在 DevEco Studio 打开 harmony/,同步 OHPM 依赖后构建 sdk 模块。Release HAR 输出到 sdk/build/default/outputs/default/sdk.har。该模块的公开入口为 sdk/Index.ets,腾讯 LiteAV 依赖由模块清单管理。

宿主与 harmony 目录相邻时,在宿主 entry/oh-package.json5 添加本地引用,然后执行 OHPM 同步:

json5
{
  "dependencies": {
    "@popoim/sdk": "file:../../harmony/sdk/build/default/outputs/default/sdk.har"
  }
}

修改 SDK 后重新构建 HAR,再同步宿主依赖;避免宿主继续编译旧产物。

初始化与 AuthProvider ​

用户同意隐私政策后,在应用级生命周期初始化一次:

ts
import { common } from '@kit.AbilityKit'
import { PopoIM, PopoConfig, PopoAuthInfo, PopoUser } from '@popoim/sdk'

function configureIM(context: common.Context): void {
  PopoIM.initialize(context, new PopoConfig(
    'https://example.com',
    async (): Promise<PopoAuthInfo> => {
      return await hostAuth.fetchImAuth()
    },
    'wss://example.com/ws',
    () => {
      // 同步激活宿主承载会话根页的标签。
      AppStorage.set<number>('host.selectedTab', 0)
    }
  ))
}

hostAuth 为宿主自己的后端适配,返回 PopoAuthInfo。认证结果按以下构造器转换,expireAt 使用 Unix 秒:

ts
const auth = new PopoAuthInfo(
  new PopoUser(userID, nickname, avatar, username, signature),
  token,
  expireAt
)

webSocketURL 可省略,默认从服务地址派生 /ws。最后一个回调 onConversationRequested 只负责同步激活宿主容器,不需要传递 SDK 内部页面路径;宿主使用自己的标签顺序即可。

两个 UI 入口 ​

将两个根页放入宿主对应标签内容区,在 ArkUI build() 中使用:

ts
import { PopoConversationPage, PopoContactPage, PopoCallPage } from '@popoim/sdk'
ts
PopoConversationPage({
  onNavigationChanged: (inside: boolean) => {
    this.messagesNested = inside
  }
})

PopoContactPage({
  active: this.selectedTab === 1,
  onNavigationChanged: (inside: boolean) => {
    this.contactsNested = inside
  }
})

这里的 messagesNested、contactsNested 和 selectedTab 是宿主状态。宿主依据当前可见标签的嵌套状态隐藏或恢复自己的 TabBar,不能让隐藏根页的回调覆盖可见页状态。通讯录根页保留在内存但不可见时,传 active: false。

启用 SDK 通话时,另外在应用根 Stack 的主内容上方放置一个 PopoCallPage():

ts
Stack() {
  HostMainPage()
  PopoCallPage()
}
.width('100%')
.height('100%')

HostMainPage 是宿主自己的主页面。会话与通讯录仍为两个导航入口,通话页只负责根层展示。

登录、退出与切换账号 ​

ts
// 可选:宿主已确认本机账号时预热只读缓存。
await PopoIM.restoreCachedSession(verifiedUser)
await PopoIM.login()

// Provider 的宿主身份更新后,再次显式登录完成切号。
await PopoIM.login()

// 用户退出宿主:
PopoIM.logout()

缓存恢复返回是否恢复成功的布尔值,不请求 Token 或网络。login() 等待首次同步完成;网络暂时失败可保留本地内容,恢复联网或回到前台时 SDK 会重试。自动续期只允许原身份,不能用于静默切号。

常用公开操作 ​

ts
import { PopoUI, PopoConversationTarget } from '@popoim/sdk'

await PopoUI.openConversation(PopoConversationTarget.friend('linzhou'))
await PopoUI.openConversation(PopoConversationTarget.group('6655312956'))

const observer = PopoIM.addUnreadListener(count => {
  // 替换宿主对应角标;100 展示为 99+。
  AppStorage.set<number>('host.unread.message', count.conversation)
  AppStorage.set<number>('host.unread.contact', count.contact)
})

await PopoIM.updateCurrentUser(updatedUser)
const bytes = await PopoIM.cacheSize()
const remainingBytes = await PopoIM.clearCache()

// 订阅所属组件或宿主生命周期结束时:
PopoIM.removeUnreadListener(observer)

openConversation 成功表示目标已解析并交给根页导航,页面动画由 ArkUI 完成。会话根页尚未挂载时,需要初始化中的 onConversationRequested 激活宿主容器;不能直接导航 SDK 内部页面。

宿主 Ability 在前后台切换时转发:

ts
onForeground(): void {
  PopoIM.setApplicationActive(true)
}

onBackground(): void {
  PopoIM.setApplicationActive(false)
}

权限与平台注意事项 ​

最终 HAP 要合并网络权限,并为 ohos.permission.MICROPHONE、ohos.permission.CAMERA 提供真实的用户授权理由;相册与文件使用系统 Picker,无需广泛存储权限。相机、扫码和媒体交互依赖当前可见页面的 Ability 上下文,SDK 根页会进行绑定。

普通推送服务、通知授权、alias 与桌面角标由宿主负责。可信普通通知点击可调用 PopoIM.handleMessageNotification(conversationID),同样通过初始化回调激活消息容器;这里接收通知携带的内部会话 ID,与 PopoUI.openConversation 接收的公开目标不同。来电通过进程内实时连接处理,不应自行增加来电推送轮询。

未读监听返回 opaque observer,需保存并在结束时移除。主题跟随宿主系统深浅色资源。缓存统计和清理异步执行,保留聊天记录、草稿与待发送内容。

接入检查 ​

用真机验证消息与通讯录切换、内部页 TabBar 隐藏、业务入口打开聊天、后台恢复和账号切换。扫码需分别检查相机授权、相册识别与取消;通话另外检查相机、麦克风拒绝后的返回与重试。