Cisco Webex iOS SDK
Cisco Webex iOS SDK 可以让您轻松地将安全且便捷的 Cisco Webex 消息和呼叫功能集成到您的 iOS 应用中。
此 SDK 使用 Swift 5 编写,并需要 iOS 11 或更高版本。
目录
安装
假设您已经有了 Xcode 项目,例如用于您的 iOS 应用的 MyWebexApp,以下是使用 CocoaPods 集成 Webex iOS SDK 到您 Xcode 项目的步骤
-
安装 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,您需要Webex集成凭据。如果您还没有Webex账户,请访问Webex开发者创建账户并注册您的集成。对于现有的Webex用户,您的应用需要通过OAuth授权流进行用户认证,对于没有Webex账户的访客用户,需要通过JSON Web Token进行认证。
有关此SDK的更多信息,请参阅Webex开发者网站的iOS SDK区域。
示例
以下是如何在您的应用中使用iOS SDK的一些示例。
-
使用Webex ID认证(基于OAuth)创建Webex实例
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认证(基于JWT)创建Webex实例
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.1 在您的容器应用中
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.2 在您的广播上传扩展示例处理程序中
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.3 了解有关容器应用及广播上传扩展和设置App Group的更多技术细节
-
在会议中接收更多视频流
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的项目。
-
在您的Podfile中
移除之前的SparkSDK:
pod 'SparkSDK'添加WebexSDK: pod 'WebexSDK'
-
转到项目目录,并运行
pod install
-
替换代码中的sdk导入信息
在项目范围内替换
"import SparkSDK" => "import WebexSDK"
-
如果您使用故事板进行UI
在"Identity Inspector"中更改Media Render View的模块
"SparkSDK" => "WebexSDK"
使用方法
从SparkSDK到WebexSDK的API变更列表。
描述 | SparkSDK使用 | WebexSDK使用 |
---|---|---|
创建新实例 | let spark = Spark(authenticator: authenticator) | let webex = Webex(authenticator: authenticator) |
"室"客户端重命名为"空间"客户端 | spark.rooms.list(roomId:{rooomId}) | webex.spaces.list(spaceId:{roomId}) |
"SparkError"重命名为"WebexError" | let error = SparkError.Auth | let error = WebexError.Auth |
建议在项目代码中将包含"spark"的变量替换为"webex"。
授权协议
© 2016-2020 Cisco Systems, Inc.及其关联公司。版权所有。
有关详细信息,请参阅授权协议。