Cisco Webex iOS SDK
Cisco Webex iOS SDK 使您能够轻松地将安全和便利的 Cisco Webex 消息和呼叫功能集成到您的 iOS 应用中。
此 SDK 用 Swift 5 编写,并需要 iOS 11 或更高版本。
目录
安装
假设您已经有了 Xcode 项目,例如 MyWebexApp,以下是将 Webex iOS SDK 集成到您的 Xcode 项目中的步骤,使用 CocoaPods
-
安装 CocoaPods
gem install cocoapods
-
设置 CocoaPods
pod setup
-
在 MyWebexApp 项目目录中创建一个名为
Podfile
的新文件,包含以下内容source 'https://github.com/CocoaPods/Specs.git' use_frameworks! target 'MyWebexApp' do platform :ios, '11.0' pod 'WebexSDK' end target 'MyWebexAppBroadcastExtension' do platform :ios, '11.2' pod 'WebexBroadcastExtensionKit' end
-
从您的 MyWebexApp 项目目录安装 Webex iOS SDK
pod install
用法
使用SDK,您将需要Cisco Webex集成凭据。如果您还没有Cisco Webex账户,请访问Webex for Developers创建您的账户并注册集成。您的应用需要通过OAuth授权流程对现有的Cisco Webex用户进行用户验证,或通过JSON Web Token对没有Cisco Webex账户的访客用户进行验证。
有关此SDK的更多信息,请参阅Webex for Developers网站的iOS SDK区域。
示例
以下是如何在您的应用中使用iOS SDK的一些示例。
-
使用基于Webex ID的认证创建Webex实例(《OAuth-based)
let clientId = "$YOUR_CLIENT_ID" let clientSecret = "$YOUR_CLIENT_SECRET" let scope = "spark:all" let redirectUri = "Webexdemoapp://response" let authenticator = OAuthAuthenticator(clientId: clientId, clientSecret: clientSecret, scope: scope, redirectUri: redirectUri) let webex = Webex(authenticator: authenticator) if !authenticator.authorized { authenticator.authorize(parentViewController: self) { success in if !success { print("User not authorized") } } }
-
使用基于Guest ID的认证创建Webex实例(《JWT-based)
let authenticator = JWTAuthenticator() let webex = Webex(authenticator: authenticator) if !authenticator.authorized { authenticator.authorizedWith(jwt: myJwt) }
-
将设备注册以发送和接收通话
webex.phone.register() { error in if let error = error { // Device not registered, and calls will not be sent or received } else { // Device registered } }
-
使用Webex服务
webex.spaces.create(title: "Hello World") { response in switch response.result { case .success(let space): // ... case .failure(let error): // ... } } // ... webex.memberships.create(spaceId: spaceId, personEmail: email) { response in switch response.result { case .success(let membership): // ... case .failure(let error): // ... } }
-
拨打外出电话
webex.phone.dial("[email protected]", option: MediaOption.audioVideo(local: ..., remote: ...)) { ret in switch ret { case .success(let call): call.onConnected = { // ... } call.onDisconnected = { reason in // ... } case .failure(let error): // failure } }
-
接收通话
webex.phone.onIncoming = { call in call.answer(option: MediaOption.audioVideo(local: ..., remote: ...)) { error in if let error = error { // success } else { // failure } }
-
拨打空间通话
webex.phone.dial(spaceId, option: MediaOption.audioVideo(local: ..., remote: ...)) { ret in switch ret { case .success(let call): call.onConnected = { // ... } call.onDisconnected = { reason in // ... } call.onCallMembershipChanged = { changed in switch changed { case .joined(let membership): // case .left(let membership): // default: // } } case .failure(let error): // failure } }
-
屏幕共享(只读)
webex.phone.dial("[email protected]", option: MediaOption.audioVideoScreenShare(video: (local: ..., remote: ...))) { ret in switch ret { case .success(let call): call.onConnected = { // ... } call.onDisconnected = { reason in // ... } call.onMediaChanged = { changed in switch changed { ... case .remoteSendingScreenShare(let sending): call.screenShareRenderView = sending ? view : nil } } case .failure(let error): // failure } }
-
发布一条消息
let plain = "foo" let markdown = "**foo**" let html = "<strong>foo</strong>"
let text = Message.Text.html(html: html) webex.messages.post(text, toPersonEmail: emailAddress, completionHandler: { response in switch response.result { case .success(let message): // ... case .failure(let error): // ... } }
let text = Message.Text.markdown(markdown: markdown, html: html, plain: text) webex.messages.post(text, toPersonEmail: emailAddress, completionHandler: { response in switch response.result { case .success(let message): // ... case .failure(let error): // ... } }
-
接收消息事件
webex.messages.onEvent = { messageEvent in switch messageEvent{ case .messageReceived(let message): // ... break case .messageDeleted(let messageId): // ... break } }
-
发送消息已读回执
webex.messages.markAsRead(spaceId: spaceId, messageId: messageId, completionHandler: { response in switch response.result { case .success(_): // ... case .failure(let error): // ... } })
-
屏幕共享(发送)
在第12部分,在您的容器应用程序中
webex.phone.dial("[email protected]", option: MediaOption.audioVideoScreenShare(video: ..., screenShare: ..., applicationGroupIdentifier: "group.your.application.group.identifier"))) { ret in switch ret { case .success(let call): call.oniOSBroadcastingChanged = { event in if #available(iOS 11.2, *) { switch event { case .extensionConnected : call.startSharing() { error in // ... } break case .extensionDisconnected: call.stopSharing() { error in // ... } break } } } } case .failure(let error): // failure } }
在第12部分,在你的广播上传扩展样本处理器中
override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) { // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional. WebexBroadcastExtension.sharedInstance.start(applicationGroupIdentifier: "group.your.application.group.identifier") { error in if let webexError = error { // ... } else { WebexBroadcastExtension.sharedInstance.onError = { error in // ... } WebexBroadcastExtension.sharedInstance.onStateChange = { state in // state change } } } } override func broadcastFinished() { // User has requested to finish the broadcast. WebexBroadcastExtension.sharedInstance.finish() } override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) { switch sampleBufferType { case RPSampleBufferType.video: // Handle video sample buffer WebexBroadcastExtension.sharedInstance.handleVideoSampleBuffer(sampleBuffer: sampleBuffer) break case RPSampleBufferType.audioApp: // Handle audio sample buffer for app audio break case RPSampleBufferType.audioMic: // Handle audio sample buffer for mic audio break } }
在第12部分,获取有关容器应用程序 & 广播上传扩展和设置应用程序组的更多技术细节
-
在一个会议中接收更多视频流
class VideoCallViewController: MultiStreamObserver { ... var onAuxStreamChanged: ((AuxStreamChangeEvent) -> Void)? = { ... switch event { case .auxStreamOpenedEvent(let view, let result): switch result { case .success(let auxStream): ... case .failure(let error): ... } case .auxStreamPersonChangedEvent(let auxStream,_,_): ... case .auxStreamSendingVideoEvent(let auxStream): ... case .auxStreamSizeChangedEvent(let auxStream): ... case .auxStreamClosedEvent(let view, let error): ... } } var onAuxStreamAvailable: (() -> MediaRenderView?)? = { ... return self.mediaRenderViews.filter({!$0.inUse}).first? } var onAuxStreamUnavailable: (() -> MediaRenderView?)? = { ... return self.mediaRenderViews.filter({$0.inUse}).last? } override func viewWillAppear(_ animated: Bool) { ... // set the observer of this call to get multi stream event. self.call.multiStreamObserver = self ... } }
-
接收成员资格事件
webex.memberships.onEvent = { membershipEvent in switch membershipEvent { case .created(let membership): // ... case .deleted(let membership): // ... case .update(let membership): // ... case .seen(let membership, let lastSeenId): // ... } }
-
获取空间中所有成员的已读状态
webex.memberships.listWithReadStatus(spaceId: spaceId, completionHandler: { response in switch response.result { case .success(let readStatuses): // ... case .failure(let error): // ... } })
-
接收空间事件
webex.spaces.onEvent = { spaceEvent in switch spaceEvent { case .create(let space): // ... case .update(let space): // ... case .spaceCallStarted(let spaceId): // ... case .spaceCallEnded(let spaceId): // ... } }
-
获取登录用户的空间的已读状态
webex.spaces.getWithReadStatus(spaceId: spaceId, completionHandler: { response in switch response.result { case .success(let spaceInfo): if let lastActivityDate = spaceInfo.lastActivityDate, let lastSeenDate = spaceInfo.lastSeenActivityDate, lastActivityDate > lastSeenDate { // space is unreadable }else { // space is readable } case .failure(let error): // ... } })
-
获取空间会议的详细信息
webex.spaces.getMeetingInfo(spaceId: spaceId, completionHandler: { response in switch response.result { case .success(let meetingInfo): // ... case .failure(let error): // ... } })
-
获取正在进行通话的空间列表
webex.spaces.listWithActiveCalls(completionHandler: { (result) in switch result { case .success(let spaceIds): // ... case .failure(_ ): // ... } })
-
更改活动讲者和其他参会者组合视频的布局
let option: MediaOption = MediaOption.audioVideo(local: ..., remote: ...) option.layout = .grid webex.phone.dial(spaceId, option: option) { ret in // ... }
-
背景噪声消除(BNR)
第21.1节:启用BNR
webex.phone.audioBNREnabled = true
第21.2节:设置BNR模式,默认值为
.HP
。它仅影响在设置audioBNREnabled
为true的情况下。webex.phone.audioBNRMode = .HP
从Cisco SparkSDK迁移
本指南的目的是帮助您从Cisco SparkSDK迁移到Cisco WebexSDK。
假设您已经有一个与SparkSDK集成的项目。
-
在您的Pod文件中
移除之前的SparkSDK:
pod 'SparkSDK'添加WebexSDK:pod 'WebexSDK'
-
转到项目目录,并运行
pod install
-
替换代码中的sdk导入信息
在项目范围内进行替换
"import SparkSDK" => "import WebexSDK"
-
如果您使用Storyboard进行UI
更改媒体渲染视图的模块,在"Indentity inspector"中
"SparkSDK" => "WebexSDK"
用途
从SparkSDK到WebexSDK的API更改列表。
描述 | SparkSDK使用 | WebexSDK使用 |
---|---|---|
创建新实例 | let spark = Spark(authenticator: authenticator) | let webex = Webex(authenticator: authenticator) |
"Room"客户端重命名为"Space"客户端 | spark.rooms.list(roomId:{rooomId}) | webex.spaces.list(spaceId:{roomId}) |
"SparkError"重命名为"WebexError" | let error = SparkError.Auth | let error = WebexError.Auth |
建议在项目代码中将包含"spark"的变量替换为"webex"。
项目名称
© 2016-2021 Cisco Systems, Inc.及其分支机构。版权所有。
有关详细信息,请参阅LICENSE。