react-native-linphone-sdk
v0.8.2
Published
test
Readme
react-native-linphone-sdk
for linephone
Installation
npm install react-native-linphone-sdkIOS
Add Content To Podfile
source "https://gitlab.linphone.org/BC/public/podspec.git"Android
add
allprojects {
repositories {
maven {
name "linphone.org maven repository"
url "https://linphone.org/maven_repository/"
content {
includeGroup "org.linphone"
}
}
}
}to android/build.gradle
add
implementation 'androidx.media:media:1.2.0'to build.gradle
说明:SIP 通话所需的全部权限(
CAMERA/RECORD_AUDIO/MODIFY_AUDIO_SETTINGS/ 前台服务等) 已收进库的 AndroidManifest.xml,宿主无需手动添加任何权限,详见下方「四、Android 集成」。
Usage
import { multiply } from 'react-native-linphone-sdk';
// ...
const result = await multiply(3, 7);宿主 App 集成指南(后台来电保活版本)
本版本起,SIP 账号注册、来电接听/挂断的核心逻辑下沉到了 Android 原生层(前台 Service 持有 Linphone Core),实现了:
- App 退后台 / 锁屏 / 被划掉后仍能保持 SIP 注册并收到来电;
- 后台来电弹原生悬浮窗 + 高优先级通知(兼容华为/小米等国产 ROM);
- 悬浮窗/通知/App 内三处接听逻辑统一,接听后重新打开 App 通话状态不丢失。
一、JS API 兼容性
已有 API 全部保持不变,老项目升级后不需要改业务代码:
SipProvider/useSipAccount/useSIPClient/useSIPClientStatus/useSipSetting等 Hook 用法不变;UserAgent的register()/unregister()/call()等用法不变;Session的answer()/terminate()/toggleHold()/sendDTMF()等用法不变;Core原有方法不变。
二、新增 JS API(可选使用)
useSIPClient 新增返回值
| 字段 | 说明 |
|---|---|
| isConfirmed | 当前 activeSession 是否已接通(从 Session 实例派生)。 |
| isProgress | 当前 activeSession 是否呼叫中。 |
| bindVideoViews(session?) | 手动重绑视频窗口。建议在视频渲染组件的 onLayout 中调用。恢复视频通话时会自动调用一次。 |
内部机制(宿主一般无需直接调用)
以下方法由库内部使用,已在 SipProvider / useSIPClient 中自动调用,业务代码不需要感知:
| 方法 | 平台 | 内部用途 |
|---|---|---|
| Core.getActiveCalls() | Android | useSIPClient 用它恢复活跃通话(悬浮窗接听后 App 拉起时不丢状态)。 |
| Core.getAccountsState() | Android | SipProvider 启动和切前台时用它同步各账号的 isRegistered / isProgress。 |
| Core.setVideoWindowIds(...) | Android | bindVideoViews() 内部调用它重绑视频窗口。 |
三者 iOS 均未实现,JS 侧已做防御(返回空值不崩溃)。
CallKeepService(原生来电界面,opt-in)
默认不启用,库内部不会强制 setup。由宿主 App 在设置/权限界面显式开启:
import { CallKeepService } from 'react-native-linphone-sdk';
// 开启(内部会完成 setup + 请求 PhoneAccount 等权限,并同步状态到原生层)
await CallKeepService.setEnabled(true);
// 查询当前状态(同步)
const enabled = CallKeepService.isEnabled();启用后来电 UI 的分工(任何状态下只有一个系统级 UI,不会重复弹出):
| App 状态 | CallKeep 启用 | CallKeep 未启用(默认) | |---|---|---| | 前台 | App 自己的界面(CallKeep 不插手) | App 自己的界面 | | 后台(JS 存活) | CallKeep 原生来电 UI | 悬浮窗 + 通知 | | 被杀(JS 死亡) | 回落 悬浮窗 + 通知 | 悬浮窗 + 通知 |
被杀场景回落悬浮窗的原因:CallKeep 的接听事件走进程内广播,JS 死亡时无法完成 SIP 接听; 悬浮窗 + 通知的接听链路完全在原生层闭环,不依赖 JS。
Permissions 新增方法
openAutoStartSettings()(跳国产 ROM 自启动设置)、registerPhoneAccount()、hasPhoneAccount()、requestCallKeepPermissions(),均已挂在 useSIPPermission() 的返回值上。
三、安装
npm install react-native-linphone-sdk @livekit/react-native-callkeep react-native-mmkv react-native-permissions react-native-get-random-values@livekit/react-native-callkeep(>= 2.0.0)是 peerDependency,必须安装,用于原生来电界面(Android ConnectionService / iOS CallKit)。react-native-mmkv用于设置项持久化(回音消除、DTMF 类型等)。
iOS 额外步骤:
cd ios && pod install并在 Info.plist 中加入:
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>audio</string>
</array>四、Android 集成
4.1 AndroidManifest.xml:一般无需修改
库的 AndroidManifest.xml 已声明下列内容,Gradle 合并清单时自动带入宿主 App,不需要手动复制:
- 前台 Service
LinphoneCoreService(stopWithTask="false",foregroundServiceType="microphone|phoneCall",保证后台接听后通话中能正常采集麦克风); - CallKeep 的
VoiceConnectionService(phoneCall|microphone,通话中切后台的麦克风由 Telecom 授权); - 来电操作广播
IncomingCallActionReceiver、开机自启LinphoneCoreBootReceiver; - 权限:
FOREGROUND_SERVICE、FOREGROUND_SERVICE_MICROPHONE、FOREGROUND_SERVICE_PHONE_CALL、POST_NOTIFICATIONS、WAKE_LOCK、USE_FULL_SCREEN_INTENT、SYSTEM_ALERT_WINDOW、RECEIVE_BOOT_COMPLETED、READ_PHONE_STATE、CALL_PHONE、MANAGE_OWN_CALLS、CAMERA、RECORD_AUDIO、MODIFY_AUDIO_SETTINGS、ACCESS_NETWORK_STATE、CHANGE_NETWORK_STATE、REQUEST_IGNORE_BATTERY_OPTIMIZATIONS(麦克风/相机仍需按 4.2 引导用户做运行时授权,这里只是清单声明); <queries>包可见性声明(华为/小米/OPPO/vivo/三星/一加的自启动管理页面所在系统应用),保证 Android 11+ 上openAutoStartSettings()能正常跳转到厂商自启动设置页,而不是落到应用详情页。
4.2 宿主需要做的
运行时权限引导(建议首次启动时处理):
- 麦克风 / 摄像头(
useSIPPermission().requestAll()); - 通知权限(Android 13+,
POST_NOTIFICATIONS); - 悬浮窗权限(
Permissions.checkOverlayPermission()/openOverlaySettings(),国产 ROM 后台弹接听界面必需); - 忽略电池优化(
Permissions.isIgnoringBatteryOptimizations()/openPowerSettings()); - 自启动权限(
Permissions.openAutoStartSettings(),小米/华为保活关键,系统无 API 只能跳设置页引导); - 电话账户(
CallKeepService.registerPhoneAccount(),Android 原生接听界面必需)。
- 麦克风 / 摄像头(
行为说明(不需要代码,但建议知晓):
- SIP 账号会在原生层持久化,进程被杀重启后自动恢复并重新注册,不需要 JS 参与;
- App 划掉后保活通知由系统调度重启,正常场景 1~4 秒恢复;高频连续划卡会触发系统退避(16s/64s 甚至更久),属系统行为。
若宿主同时使用 notifee 9.x:notifee 的 manifest 声明了
foregroundServiceType="shortService"(API 34 枚举值),compileSdk <= 33的项目会资源链接失败。需要在宿主 manifest 中替换(不是删除)成 compileSdk 认识的合法值:<!-- 注意:manifest 根标签上必须已声明 xmlns:tools="http://schemas.android.com/tools",否则编译报 unbound prefix --> <service android:name="app.notifee.core.ForegroundService" tools:replace="android:foregroundServiceType" android:foregroundServiceType="microphone" />⚠️ 不要用
tools:remove把该属性剥掉:notifee 前台服务启动时会带 type(默认 0x80), manifest 没有声明任何 type 时,Android 12+ 上启动即闪退 (foregroundServiceType 0x80 is not a subset of 0x0)。 这里替换的值要与 JS 侧foregroundServiceTypes配置一致,可写多个如"microphone|dataSync"。这是唯一需要宿主手动改
AndroidManifest.xml的场景;不使用 notifee 则完全不用改。
4.3 来电接听后恢复通话状态(视频通话必看)
悬浮窗/通知接听后 App 被拉起,useSIPClient 会自动从 Core.getActiveCalls() 重建 Session(sessions、activeSession、isConfirmed 均恢复正常)。视频通话需要视频窗口重绑才有画面:
const { previewVideoViewRef, remoteVideoViewRef, bindVideoViews } = useSIPClient(agentId);
<PreviewVideoView ref={previewVideoViewRef} onLayout={() => bindVideoViews()} ... />
<PreviewVideoView ref={remoteVideoViewRef} onLayout={() => bindVideoViews()} ... />音频通话无需任何处理。
五、iOS 注意事项
- 后台/锁屏来电走 CallKit(CallKeep),App 被杀后纯内网无法来电(iOS 系统限制,需 APNs/PushKit 兜底,方案见 TODO.md);
getActiveCalls/getAccountsState/setVideoWindowIdsiOS 原生未实现,JS 侧已做防御(返回空值不崩溃),如需相同能力需后续在ios/LinphoneSdk.swift补齐。
六、多账号说明
- 支持多 SIP 账号同时注册,
SipAccountStore按Configuration.id去重持久化,请保证每个账号的id全局唯一,否则恢复时会互相覆盖; - 通过
setCurrent(userAgent)(即Core.setDefaultAccount)切换默认账号来控制用哪个账号拨打/接听。
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT
Made with create-react-native-library
