swift - 单击 CallKit 中的应用程序图标时打开应用程序
问题描述
我使用 SINCH SDK 集成了语音通话,我的问题是当手机处于锁定屏幕时,我通过 CallKit 接到来电,我回答一切正常,但是当我按下应用程序图标时,应用程序在 VoiceCallController 中打开并再次运行并响铃声音。
class SINCallKitProvider: NSObject, CXProviderDelegate {
var _client: SINClient!
var _provider: CXProvider!
var _acDelegate: AudioContollerDelegate!
var _calls: [UUID : SINCall]
var _muted: Bool
init(withClient: SINClient) {
_client = withClient
_muted = false
_acDelegate = AudioContollerDelegate()
_client.audioController().delegate = _acDelegate
_calls = [:]
let config = CXProviderConfiguration(localizedName: "ok")
config.maximumCallGroups = 2
config.supportsVideo = false
config.maximumCallsPerCallGroup = 1
let callkitIcon = UIImage(named: "ok")
config.iconTemplateImageData = UIImagePNGRepresentation(callkitIcon!)
_provider = CXProvider(configuration: config)
super.init()
_provider.setDelegate(self, queue: nil)
NotificationCenter.default.addObserver(self, selector: #selector(callDidEnd), name: NSNotification.Name(rawValue: "SINCallDidEndNotification"), object: nil)
}
func reportNewIncomingCall (call: SINCall) {
let firstName = currentUser.string(forKey: "firstName")
let lastName = currentUser.string(forKey: "lastName")
let fullName = "\(firstName!) \(lastName!)"
var caller = fullName
if let call = call.headers["from"] {
caller = call as! String
}
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: caller)
_provider.reportNewIncomingCall(with: UUID(uuidString: call.callId)!, update: update) { (error) in
if error != nil {
print("error call \(error!.localizedDescription)")
return
}
self.addNewCall(call: call)
}
}
func addNewCall(call: SINCall) {
print("Added call \(call.callId)")
_calls[UUID(uuidString: call.callId)!] = call
}
// Handle cancel/bye event initiated by either caller or callee
@objc func callDidEnd(notification: Notification) {
if let call: SINCall = notification.userInfo![SINCallKey] as? SINCall {
let cause = SINGetCallEndedReason(cause: call.details.endCause)
_provider.reportCall(with: UUID(uuidString: call.callId)!, endedAt: call.details.endedTime, reason: cause)
if self.callExist(callId: call.callId) {
print("CallDidEnd, removing \(call.callId)")
_calls.removeValue(forKey: UUID(uuidString: call.callId)!)
}
} else {
print("****warning no call was reported")
}
}
func callExist (callId: String) -> Bool {
if _calls.count == 0 {
return false
}
for callKitCall in _calls.values {
if callKitCall.callId == callId {
return true
}
}
return false
}
func activeCalls() -> [SINCall] {
return Array(_calls.values)
}
func currentEstablishedCall () -> SINCall? {
let calls = activeCalls()
if calls.count == 1 && calls[0].state == SINCallState.established {
return calls[0]
} else {
return nil
}
}
//MARK: CXProvider delegate
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
print("Did activate")
_client.call()?.provider(provider, didActivate: audioSession)
}
func callForAction(action: CXCallAction) -> SINCall? {
let call = _calls[action.callUUID]
if call == nil {
print("Warning no call found for action \(action.callUUID)")
return nil
}
return call
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
print("Answer call action")
callForAction(action: action)!.answer()
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
print("end call action")
callForAction(action: action)!.hangup()
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
print("mute call action")
if _acDelegate.muted {
_client.audioController().unmute()
} else {
_client.audioController().mute()
}
action.fulfill()
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
print("did diactivate audio session")
}
func providerDidReset(_ provider: CXProvider) {
print("did reset")
}
//MARK: Helpers
func SINGetCallEndedReason(cause: SINCallEndCause) -> CXCallEndedReason {
switch cause {
case .error:
return CXCallEndedReason.failed
case.denied:
return CXCallEndedReason.remoteEnded
case .hungUp:
return CXCallEndedReason.remoteEnded
case .timeout:
return CXCallEndedReason.unanswered
case .canceled:
return CXCallEndedReason.unanswered
case .noAnswer:
return CXCallEndedReason.unanswered
case .otherDeviceAnswered:
return CXCallEndedReason.unanswered
default:
break
}
return CXCallEndedReason.failed
}
}
解决方案
您是说通过 CallKit 锁定屏幕 UI 上的应用程序图标进入您的应用程序时,您的应用程序没有呈现正确的视图?
如果这是你的问题,一个解决方案可能是:你应该在你的 callkit 提供者中维护一个列表或变量,只是为了检查你是否有任何连接的呼叫。并且您的应用程序委托应该侦听 applicationWillEnterForeground 通知,如果用户单击 callkit UI 上的应用程序图标,则会触发该通知。
当您收到 applicationWillEnterForeground 通知时,您检查您的 callkit 提供程序是否正在保持任何活动呼叫,如果是,则显示显示正在进行的呼叫的视图,否则显示您将在当前实现中显示的任何视图。
SinchCallKit 示例应用程序提供了一些用于处理此问题的实现参考(尽管在目标 c 中)。请检查该项目中的 AppDelegate.m、CallViewController.m 和 SINCallKitProvider.m。
推荐阅读
- javascript - amCharts:禁用 Legend 中某些项目的切换
- javascript - 您可以在选项卡更改时激活单独的事件吗?
- ruby - 从 file.write 修复文本的宽度
- python - Python:如何将函数拟合到点?
- pandas - 如何使用 Pandas 分组和求和
- matlab - 寻求有关尝试在 MATLAB 中为流行病模拟器读取 2D 元胞自动机的摩尔邻域的建议
- docker - Springboot 微服务和 Mongo 容器
- html - 浮动元素之间的奇怪间距
- javascript - 如何使用 ejs 将一些 JS 代码包含到 Bootstrap 模式中?
- authentication - 在 Mesosphere/DCOS 中启用 Authenticate Mesos API 的问题