telnyx-webrtc-ios
在 iOS 上启用 Telnyx 实时通信服务。📞 🔥
项目结构
- SDK 项目:启用 Telnyx WebRTC 通信。
- SDK 测试项目。
- 示例应用程序项目。
项目设置
- 克隆仓库
- 在项目根目录中运行
pod install
命令以安装依赖项。 - 打开 Workspace:
TelnyxRTC.xcworkspace
- 您将找到 3 个可构建目标
- SDK
- SDK 测试
- 示例应用程序
- 选择目标
TelnyxRTC (TelnyxRTC 项目)
编译 SDK
-
选择目标
TelnyxWebRTCDemo
运行示例应用程序。SDK 应手动构建以使应用程序运行(步骤 5) -
享受吧 😎
凭据 | 出站呼叫 | 入站呼叫 |
![]() |
![]() |
![]() |
直观SIP凭证
要使用TelnyxRTC SDK发起和接听通话,您需要获取SIP凭证。
- 访问https://portal.telnyx.com/
- 注册一个Telnyx账号。
- 创建一个凭证连接,以设置如何连接您的通话。
- 创建一个外呼语音配置文件,以配置您的出呼调用设置,并将其分配给凭证连接。
有关生成SIP凭证的更多信息,请参阅Telnyx WebRTC快速入门指南。
将Telnyx SDK添加到您的iOS客户端应用程序中
当前iOS SDK支持使用 Cocoapods。
Cocoapods
如果您的xcode项目尚未使用cocoapods,则需要配置它。
- 打开您的Podfile,并添加TelnyxRTC。
pod 'TelnyxRTC', '~> 0.1.0'
- 安装您的pods。您可以使用 --repo-update 标志确保您的cocoapods已更新至最新规格。
pod install --repo-update
- 打开您的.xcworkspace
- 在类的最顶级导入TelnyxRTC
import TelnyxRTC
- 禁用BITCODE(The GoogleWebRTC依赖项已禁用BITCODE):转到您的应用目标“构建设置”标签,搜索“bitcode”,并将其设置为“NO”
- 启用VoIP和音频后台模式:转到“签名与能力”标签,点击+能力按钮并添加这些后台模式
- 转到您的Info.plist文件,并添加“隐私 - 麦克风使用说明”键,并描述您的应用需要进行VoIP通话时需要麦克风访问。
- 您已经准备好一切!
Swift 包管理器
Xcode 内置了对 Swift 包管理器的支持。要添加一个包
- 选择文件 > 添加包
- 在 Swift 包管理器界面,搜索 https://github.com/team-telnyx/telnyx-webrtc-ios.git 包。
- 选择 主分支 并点击添加包
注意:如果添加包卡在下载阶段,尝试文件 > 包 > 重置包缓存,或者在终端运行命令 rm -rf ~/Library/Caches/org.swift.swiftpm/
更多内容请参阅 Apple 文档
提示:对于单个包,使用 Cocoapods 或 Swift 包管理器可以避免重复的二进制文件
使用方法
Telnyx 客户端设置
// Initialize the client
let telnyxClient = TxClient()
// Register to get SDK events
telnyxClient.delegate = self
// Setup yor connection parameters.
// Set the login credentials and the ringtone/ringback configurations if required.
// Ringtone / ringback tone files are not mandatory.
// You can user your sipUser and password
let txConfigUserAndPassowrd = TxConfig(sipUser: sipUser,
password: password,
pushDeviceToken: "DEVICE_APNS_TOKEN",
ringtone: "incoming_call.mp3",
ringBackTone: "ringback_tone.mp3",
//You can choose the appropriate verbosity level of the SDK.
//Logs are disabled by default
logLevel: .all)
// Or use a JWT Telnyx Token to authenticate
let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN",
pushDeviceToken: "DEVICE_APNS_TOKEN",
ringtone: "incoming_call.mp3",
ringBackTone: "ringback_tone.mp3",
//You can choose the appropriate verbosity level of the SDK. Logs are disabled by default
logLevel: .all)
do {
// Connect and login
// Use `txConfigUserAndPassowrd` or `txConfigToken`
try telnyxClient.connect(txConfig: txConfigToken)
} catch let error {
print("ViewController:: connect Error \(error)")
}
// You can call client.disconnect() when you're done.
Note: you need to relese the delegate manually when you are done.
// Disconnecting and Removing listeners.
telnyxClient.disconnect();
// Release the delegate
telnyxClient.delegate = nil
Telnyx 客户端代理
你需要创建一个客户端实例并设置代理。
// Initialize the client
let telnyxClient = TxClient()
// Register to get SDK events
telnyxClient.delegate = self
然后你将接收到以下事件
extension ViewController: TxClientDelegate {
func onRemoteCallEnded(callId: UUID) {
// Call has been removed internally.
}
func onSocketConnected() {
// When the client has successfully connected to the Telnyx Backend.
}
func onSocketDisconnected() {
// When the client from the Telnyx backend
}
func onClientError(error: Error) {
// Something went wrong.
}
func onClientReady() {
// You can start receiving incoming calls or
// start making calls once the client was fully initialized.
}
func onSessionUpdated(sessionId: String) {
// This function will be executed when a sessionId is received.
}
func onIncomingCall(call: Call) {
// Someone is calling you.
// This delegate method will be called when the app is in foreground and the Telnyx Client is connected.
}
func onPushCall(call: Call) {
// If you have configured Push Notifications and app is in background or the Telnyx Client is disconnected
// this delegate method will be called after the push notification is received.
// Update the current call with the incoming call
self.currentCall = call
}
// You can update your UI from here based on the call states.
// Check that the callId is the same as your current call.
func onCallStateUpdated(callState: CallState, callId: UUID) {
// handle the new call state
switch (callState) {
case .CONNECTING:
break
case .RINGING:
break
case .NEW:
break
case .ACTIVE:
break
case .DONE:
break
case .HELD:
break
}
}
}
呼叫
外呼
// Create a client instance
self.telnyxClient = TxClient()
// Asign the delegate to get SDK events
self.telnyxClient?.delegate = self
// Connect the client (Check TxClient class for more info)
self.telnyxClient?.connect(....)
// Create the call and start calling
self.currentCall = try self.telnyxClient?.newCall(callerName: "Caller name",
callerNumber: "155531234567",
// Destination is required and can be a phone number or SIP URI
destinationNumber: "18004377950",
callId: UUID.init())
这是一个通用示例:为了完全支持外呼,您需要实现CallKit以正确处理音频状态。更多信息请查看《Audio Session Handling WebRTC + CallKit》部分。
入境呼叫
如何接听来电
//Init your client
func initTelnyxClient() {
//
self.telnyxClient = TxClient()
// Asign the delegate to get SDK events
self.telnyxClient?.delegate = self
// Connect the client (Check TxClient class for more info)
self.telnyxClient?.connect(....)
}
extension ViewController: TxClientDelegate {
//....
func onIncomingCall(call: Call) {
// We are automatically answering any incoming call as an example, but
// maybe you want to store a reference of the call, and answer the call after a button press.
self.myCall = call.answer()
}
}
这是一个通用示例:为了完全支持入境呼叫,您需要实现PushKit + CallKit。更多信息请查看《设置VoIP推送通知》部分。
设置VoIP推送通知
为了在应用在后台运行或关闭时接收来电,您需要在您的任务控制中心门户帐户和您的应用程序中进行一系列设置。
VoIP Push - 门户设置
在此过程中,您将学习如何创建VoIP Push凭据并将凭据分配给SIP连接。
此过程需要以下内容
- 任务控制门户账户。
- SIP连接。
- 您的Apple VoIP Push证书。
有关设置推送通知的完整说明,请访问此链接。
VoIP Push - 应用程序设置
要在您的应用程序中接收Telnyx VoIP推送通知,以下设置是必需的
1. 将推送通知功能添加到您的Xcode项目
- 打开与您的应用关联的xcode工作区。
- 在项目导航器(左边的菜单)中,选择代表您的移动应用的项目图标。
- 在Xcode右窗格的右上角,选择您的应用的目标。
- 按+功能按钮。
- 启用推送通知
2. 在应用程序中配置PushKit
- 导入pushkit
import PushKit
- 初始化PushKit
private var pushRegistry = PKPushRegistry.init(queue: DispatchQueue.main)
...
func initPushKit() {
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = Set([.voIP])
}
- 实现PKPushRegistryDelegate
extension AppDelegate: PKPushRegistryDelegate {
// New push notification token assigned by APNS.
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
if (type == .voIP) {
// This push notification token has to be sent to Telnyx when connecting the Client.
let deviceToken = credentials.token.reduce("", {$0 + String(format: "%02X", $1) })
UserDefaults.standard.savePushToken(pushToken: deviceToken)
}
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
if (type == .voIP) {
// Delete incoming token in user defaults
let userDefaults = UserDefaults.init()
userDefaults.deletePushToken()
}
}
/**
This delegate method is available on iOS 11 and above.
*/
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
if (payload.type == .voIP) {
self.handleVoIPPushNotification(payload: payload)
}
if let version = Float(UIDevice.current.systemVersion), version >= 13.0 {
completion()
}
}
func handleVoIPPushNotification(payload: PKPushPayload) {
if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] {
let callId = metadata["call_id"] as? String
let callerName = (metadata["caller_name"] as? String) ?? ""
let callerNumber = (metadata["caller_number"] as? String) ?? ""
let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName
let uuid = UUID(uuidString: callId)
// Re-connect the client and process the push notification when is received.
// You will need tu use the credentials of the same user that is receiving the call.
let txConfig = TxConfig(sipUser: sipUser,
password: password,
pushDeviceToken: "APNS_PUSH_TOKEN")
try? telnyxClient?.processVoIPNotification(txConfig: txConfig)
// Report the incoming call to CallKit framework.
let callHandle = CXHandle(type: .generic, value: from)
let callUpdate = CXCallUpdate()
callUpdate.remoteHandle = callHandle
callUpdate.hasVideo = false
provider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in
if let error = error {
print("AppDelegate:: Failed to report incoming call: \(error.localizedDescription).")
} else {
print("AppDelegate:: Incoming call successfully reported.")
}
}
}
}
- 如果一切设置正确,当应用运行时APNS应分配一个推送令牌。
- 为了接收VoIP推送通知,您需要在连接到Telnyx客户端时发送您的推送令牌。
let txConfig = TxConfig(sipUser: sipUser,
password: password,
pushDeviceToken: "DEVICE_APNS_TOKEN",
//You can choose the appropriate verbosity level of the SDK.
logLevel: .all)
// Or use a JWT Telnyx Token to authenticate
let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN",
pushDeviceToken: "DEVICE_APNS_TOKEN",
//You can choose the appropriate verbosity level of the SDK. Logs are disabled by default
logLevel: .all)
有关Pushkit的更多信息,您可以查阅官方Apple文档。
重要:
- 您至少需要登录一次,在开始接收推送通知之前将您的设备令牌发送到Telnyx。
- 您需要实现'CallKit'以在有VoIP推送通知时报告来电。在iOS 13.0及更高版本中,如果您未能向CallKit报告通话,系统将终止您的应用。有关更多信息,请参阅Apple文档
c. 在您的应用中配置CallKit
PushKit
要求您在处理VoIP通话时使用CallKit
。CallKit
确保为设备上的用户设备提供调用相关服务的应用可无缝协作,并尊重勿扰等特性。CallKit
还运行系统与调用相关的UI,包括 incoming 或 outgoing call screens。使用CallKit
来显示这些界面并管理与之的交互。
有关CallKit
的更多信息,您可以查阅官方Apple文档。
通用设置
- 导入CallKit
import CallKit
- 初始化CallKit
func initCallKit() {
let configuration = CXProviderConfiguration(localizedName: "TelnyxRTC")
configuration.maximumCallGroups = 1
configuration.maximumCallsPerCallGroup = 1
callKitProvider = CXProvider(configuration: configuration)
if let provider = callKitProvider {
provider.setDelegate(self, queue: nil)
}
}
- 实现
CXProviderDelegate
方法。
音频会话处理WebRTC + CallKit
要使CallKit
与TelnyxRTC SDK
正确工作,您需要根据以下方式设置音频设备状态,基于CallKit
AudioSession状态:
extension AppDelegate : CXProviderDelegate {
...
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
self.telnyxClient?.isAudioDeviceEnabled = true
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
self.telnyxClient?.isAudioDeviceEnabled = false
}
}
禁用推送通知
可以通过调用以下代码来为当前用户禁用推送通知
telnyxClient.disablePushNotifications()
文档
有关更多信息,您可以
- 克隆仓库
- 并检查导出的文档:在
docs/index.html
有疑问吗?需要评论吗?在构建有趣的东西吗?加入我们的Slack频道并分享。