英文:
PushKit delegate methods not being called after putting them in a separate manager class
问题
在应用程序委托中添加PushKit代理后,它能够完美工作。以下是代码:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.voipRegistration()
return true
}
// 注册VoIP通知
func voipRegistration() {
// 创建推送注册对象
let mainQueue = DispatchQueue.main
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
}
// MARK: - PKPushRegistryDelegate
extension AppDelegate: PKPushRegistryDelegate {
// 处理更新的推送凭据
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
print("pushRegistry -> deviceToken: \(deviceToken)")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
print("pushRegistry: didInvalidatePushTokenForType:")
}
// 处理传入推送
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
// 显示呼叫屏幕
if type == .voIP {
print("VoIP")
} else {
print("Nope")
}
if UIApplication.shared.applicationState == UIApplication.State.active {
print("Active")
} else {
let config = CallKit.CXProviderConfiguration()
config.supportsVideo = true
let provider = CXProvider(configuration: config)
let testCallKit = TestCallKitFile()
testCallKit.recieveACall(provider: provider)
}
}
}
这段代码之所以工作,是因为从didUpdate credentials
方法中打印了一个设备令牌。但是,当将代理方法放在一个单独的类中时,它们不会被调用(我知道这是因为令牌没有被打印)。以下是代码:
VoIPNotificationManager类
class VoIPNotificationManager: NSObject, PKPushRegistryDelegate {
func registerForVoIPNotifications() {
let mainQueue = DispatchQueue.main
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
// 处理更新的推送凭据
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
print("pushRegistry -> deviceToken: \(deviceToken)")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
print("pushRegistry: didInvalidatePushTokenForType:")
}
// 处理传入推送
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
// 显示呼叫屏幕
if type == .voIP {
print("VoIP")
} else {
print("Nope")
}
if UIApplication.shared.applicationState == UIApplication.State.active {
print("Active")
} else {
let config = CallKit.CXProviderConfiguration()
config.supportsVideo = true
let provider = CXProvider(configuration: config)
let testCallKit = TestCallKitFile()
testCallKit.recieveACall(provider: provider)
}
}
}
然后,在应用程序委托的didFinishLaunchingWithOptions
方法中调用它,如下所示:
// 注册VoIP通知
let voipNotificationManager = VoIPNotificationManager()
voipNotificationManager.registerForVoIPNotifications()
此外,这是一个SwiftUI应用。
英文:
When I add the PushKit delegates in the App Delegate, it works perfectly. Here's the code:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.voipRegistration()
return true
}
// Register for VoIP notifications
func voipRegistration() {
// Create a push registry object
let mainQueue = DispatchQueue.main
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
}
// MARK: - PKPushRegistryDelegate
extension AppDelegate : PKPushRegistryDelegate {
// Handle updated push credentials
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
print("pushRegistry -> deviceToken :\(deviceToken)")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
print("pushRegistry:didInvalidatePushTokenForType:")
}
// Handle incoming pushes
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
// Show call screen
if type == .voIP {
print("VoIP")
} else {
print("Nope")
}
if UIApplication.shared.applicationState == UIApplication.State.active {
print("Active")
} else {
let config = CallKit.CXProviderConfiguration()
config.supportsVideo = true
let provider = CXProvider(configuration: config)
let testCallKit = TestCallKitFile()
testCallKit.recieveACall(provider: provider)
}
}
}
This code works because a token is being printed from the didUpdate credentials
method. But when I put the delegate methods in a separate class, they are not being called (I know that because the token is not being printed). Here's the code:
VoIPNotificationManager class
class VoIPNotificationManager: NSObject, PKPushRegistryDelegate {
func registerForVoIPNotifications() {
let mainQueue = DispatchQueue.main
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
// Handle updated push credentials
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
print("pushRegistry -> deviceToken :\(deviceToken)")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
print("pushRegistry:didInvalidatePushTokenForType:")
}
// Handle incoming pushes
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
// Show call screen
if type == .voIP {
print("VoIP")
} else {
print("Nope")
}
if UIApplication.shared.applicationState == UIApplication.State.active {
print("Active")
} else {
let config = CallKit.CXProviderConfiguration()
config.supportsVideo = true
let provider = CXProvider(configuration: config)
let testCallKit = TestCallKitFile()
testCallKit.recieveACall(provider: provider)
}
}
}
And I am calling this in the appDelegate's didFinishLaunchingWithOptions
method like so:
// Register for voip notifs
let voipNotificationManager = VoIPNotificationManager()
voipNotificationManager.registerForVoIPNotifications()
Also, this is a SwiftUI app.
答案1
得分: 1
看起来你没有在didFinishLaunchingWithOptions
方法之外保存对voipNotificationManager
的引用。我说得对吗?如果是这样,那么在didFinishLaunchingWithOptions
完成后,该管理器将被释放,因为没有剩余的强引用。
以下是内存管理在Swift中的工作方式的链接:链接
我建议你将voipNotificationManager
作为应用程序代理的属性,就像这样:
class AppDelegate: UIResponder, UIApplicationDelegate {
let voipNotificationManager = VoIPNotificationManager()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
voipNotificationManager.registerForVoIPNotifications()
return true
}
...
}
英文:
It looks like you don't store a reference to your voipNotificationManager
outside of the didFinishLaunchingWithOptions
method.
Am I right?
If so, the manager just gets deallocated after the didFinishLaunchingWithOptions
finishes. As there are no strong references left.
Here is how memory management works in swift link
What I would suggest you do is make your voipNotificationManager
a property on the app delegate like so
class AppDelegate: UIResponder, UIApplicationDelegate {
let voipNotificationManager = VoIPNotificationManager()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
voipNotificationManager.registerForVoIPNotifications()
return true
}
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论