Skip to content
UniApp 接入网易云信音频通话
概述
UniApp 通过 nativeplugins 机制集成网易云信 NERTC 音频通话 SDK。核心工作集中在原生插件与框架层的桥接配置、自定义基座调试,以及通话控制、事件监听和错误处理。
基本概念
nativeplugins
nativeplugins 是 UniApp 项目下存放原生插件的目录。每个插件包含 Android 与 iOS 原生库(.aar、.jar、.framework、.a)以及描述元信息的 package.json 文件。与 npm 包不同,nativeplugins 中的代码在打包时直接编译进 App 原生层。
自定义基座
标准运行基座不包含第三方原生插件。自定义基座(Custom Base)将 nativeplugins 下的原生代码打入基座 APK 或 IPA,使得开发调试期间能够实际调用原生能力。正式发布时仍需通过云打包或离线打包将原生插件打入最终产物。
桥接对象
JS 层通过 uni.requireNativePlugin('pluginName') 获取一个 JS-Native 桥接代理对象。调用代理对象的方法时,参数序列化后传给原生层,返回值通过回调异步返回。信令与控制消息走该桥接通道,音频媒体数据则通过独立的媒体通道传输,不经过 JS Bridge。因此控制类调用的延迟(通常 1–5 毫秒)不会影响实时音频质量。
工作原理
HBuilderX 编译时读取 nativeplugins 下各插件的 package.json,获取插件标识与原生模块信息,随后将原生模块注入编译入口;同时在 JS 层暴露 uni.requireNativePlugin,运行时返回桥接代理对象。制作自定义基座时,HBuilderX 根据 manifest.json 中声明的插件,将对应原生库打包进基座。调试阶段用自定义基座运行即可调用插件提供的原生方法。
基本用法
准备 SDK 与目录结构
将网易云信提供的 UniApp 版 NERTC SDK 解压后放入 nativeplugins 目录,典型结构:
text
项目根/
├── nativeplugins/
│ └── NERTC-SDK/
│ ├── android/
│ │ ├── libs/ # .aar 文件
│ │ └── AndroidManifest.xml
│ ├── ios/
│ │ ├── NERTC.framework/
│ │ └── module.json
│ └── package.json
├── manifest.json
└── pages/配置 manifest.json
在 manifest.json 中声明插件,使编译系统识别:
json
{
"app-plus": {
"usingComponents": true,
"nativePlugins": [
{
"name": "NERTC-SDK",
"class": "com.example.nertc.NERTCPlugin"
}
]
}
}class 的值需与插件 package.json 中声明的原生类名一致。
配置原生权限
Android 在 nativeplugins/NERTC-SDK/android/AndroidManifest.xml 中声明录音权限,打包时该文件会合并到主 AndroidManifest.xml:
xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />iOS 在 ios/Info.plist 中添加麦克风使用描述:
xml
<key>NSMicrophoneUsageDescription</key>
<string>用于音频通话</string>若使用插件自带的配置文件,也可通过 package.json 的 ios.plist 字段注入。
制作自定义基座
在 HBuilderX 菜单栏选择 运行 → 制作自定义基座,等待打包完成。打包成功后,设备会安装自定义基座,之后运行项目即可调用原生能力。通过 CLI 也可触发:
bash
npx @dcloudio/hbuilderx-cli make --platform android --type custom初始化与加入房间
js
// 获取原生插件实例
const nertc = uni.requireNativePlugin('NERTC-SDK');
// 注册事件监听(详见 API 节)
nertc.setEventListener((event) => {
switch (event.type) {
case 'onRemoteUserAudioStart':
console.log('远端用户音频开启:', event.uid);
break;
case 'onError':
console.error('错误:', event.errCode, event.errMsg);
break;
}
});
// 初始化 SDK
nertc.init({
appKey: 'YOUR_APP_KEY',
logLevel: 'info',
}, (result) => {
if (result.code === 0) {
nertc.joinChannel({
channelName: 'testRoom',
uid: 'user123',
role: 'broadcaster', // 主播角色,可发布音频流
}, (joinResult) => {
console.log('加入房间结果:', joinResult);
});
} else {
console.error('初始化失败:', result);
}
});初始化必须在加入房间前完成,joinChannel 依赖初始化成功的回调。
API
以下列出音频通话场景的核心 API,均为桥接代理对象的方法。
init(options, callback)
初始化引擎。
options.appKey:网易云信控制台获取的 AppKey。options.logLevel:日志级别,可选debug、info、warn、error。callback(result):result.code === 0表示成功。
joinChannel(options, callback)
加入频道。
options.channelName:频道名。options.uid:用户标识,需在频道内唯一。options.role:角色,broadcaster(可发布流)或audience(只订阅)。callback(result):result.code状态码。
leaveChannel(callback)
离开当前频道,释放资源。
enableLocalAudio(enable, callback)
开关本地音频采集。enable 为 true 开启麦克风,false 静音。
switchSpeaker(enable, callback)
切换扬声器。enable 为 true 使用扬声器,false 使用听筒。
setEventListener(callback)
设置事件监听器,回调函数接收事件对象。常见事件类型:
onRemoteUserAudioStart:远端用户音频开启,事件携带uid。onRemoteUserAudioStop:远端用户音频关闭。onUserJoined:远端用户加入频道。onUserLeft:远端用户离开频道。onError:错误事件,携带errCode和errMsg。onConnectionStateChanged:连接状态变化。
监听器应在 init 之前注册,避免丢失早期事件(如初始化过程中的错误回调)。
错误码
初始化或通话过程中的错误通过回调返回,常见错误码:
0:成功。-1:未知错误。-2:参数错误。-3:未初始化或初始化未完成。-4:网络连接失败。
onError 事件中也会带有 errCode,可据此进行重试或提示用户。
示例
完整通话流程:初始化、加入房间、监听远端音频、开关麦克风、切换扬声器、离开房间并处理错误。
js
const nertc = uni.requireNativePlugin('NERTC-SDK');
// 事件监听
nertc.setEventListener((event) => {
console.log('事件:', event.type, event);
if (event.type === 'onRemoteUserAudioStart') {
console.log(`用户 ${event.uid} 开始说话`);
} else if (event.type === 'onError') {
uni.showToast({ title: `错误: ${event.errMsg}`, icon: 'none' });
}
});
// 初始化
nertc.init({
appKey: 'YOUR_APP_KEY',
logLevel: 'info',
}, (result) => {
if (result.code !== 0) {
console.error('初始化失败,错误码:', result.code);
return;
}
// 加入频道
nertc.joinChannel({
channelName: 'audio_room_1',
uid: 'user_001',
role: 'broadcaster',
}, (joinResult) => {
if (joinResult.code !== 0) {
console.error('加入房间失败:', joinResult.code);
return;
}
console.log('加入房间成功');
// 打开扬声器
nertc.switchSpeaker(true, (res) => {
console.log('扬声器已切换:', res);
});
});
});
// 页面离开时退出频道并关闭音频采集
function onPageHide() {
nertc.enableLocalAudio(false, () => {
nertc.leaveChannel((res) => {
console.log('已离开频道:', res);
});
});
}该示例覆盖了从初始化到退出通话的完整链路,并包含错误分支处理。
注意点
- 音频权限:Android 需通过
uni.authorize动态请求RECORD_AUDIO权限,iOS 需配置NSMicrophoneUsageDescription。权限未授予时,初始化可能不报错,但通话建立后本地或远端无音频,属于静默失败。排查时应先检查系统权限状态及 iOS 的AVAudioSession.recordPermission。 - 自定义基座与发布打包:自定义基座仅用于开发调试。正式发布必须通过云打包或离线打包,且需确保原生库的混淆规则(ProGuard)未被过滤。若自定义基座测试通过但正式包调用失败,常见原因是混淆规则缺失,需在
proguard-rules.pro中添加-keep指令保留插件相关类。 - HBuilderX 版本差异:3.6 及以上版本统一了插件加载模型。旧版本项目迁移时需检查
nativeplugins下package.json的字段格式。若出现插件未识别错误,应对比 SDK 文档中推荐的字段名与当前项目中的实际字段。 - 回调时机:
init未完成时调用joinChannel会返回错误码-3,因此必须等待初始化回调成功后再加入房间。事件监听器建议在init之前注册,确保初始化过程中的错误能被捕获。 - 后台运行:iOS 应用进入后台后音频可能被中断,需在工程配置中开启 Background Modes 的 Audio 能力。
限制
- 桥接代理仅支持异步回调,不支持同步返回值。操作结果必须通过回调或事件获取。
- 原生插件本身不能热更新,插件变更需要重新打包基座。
- 音频通话的媒体通道依赖原生网络模块,弱网下的重连策略由 SDK 内部控制,JS 层只能监听连接状态变化事件。
参考链接
- 网易云信 NERTC UniApp SDK 集成文档:
https://doc.yunxin.163.com/nertc/sdk-integration/uniapp - UniApp nativePlugins 开发指南:
https://nativesupport.dcloud.net.cn/NativePlugin/README - HBuilderX 自定义基座说明:
https://hx.dcloud.net.cn/Tutorial/App/CustomBase
(文档链接请以官方最新版本为准)
