找不到 'UNUserNotificationCenterDelegate' 的协议声明

Cannot find protocol declaration for 'UNUserNotificationCenterDelegate'

我有一个 iOS 应用程序使用 Firebase 进行通知。通知已设置并正常工作,我现在需要 receive/handle 通知以相应地呈现视图控制器。我使用Objective C代码来调用我的C++代码,因此我的项目中有一个桥接header,主要写在Swift.

我使用了 firebase 文档(以及其他示例)中的 this example。简而言之:遵守协议 UNUserNotificationCenterDelegate 并实现其功能。我也在 AppDelegate class.

中做 import UserNotifications

现在,在进行这些少量更改的编译时,我得到了这两个错误

Cannot find protocol declaration for 'UNUserNotificationCenterDelegate'

Unknown type name 'UNNotificationPresentationOptions'

对于生成的代码:

SWIFT_AVAILABILITY(ios,introduced=10)
@interface AppDelegate (SWIFT_EXTENSION(myapp)) <UNUserNotificationCenterDelegate>
- (void)userNotificationCenter:(UNUserNotificationCenter * _Nonnull)center willPresentNotification:(UNNotification * _Nonnull)notification withCompletionHandler:(void (^ _Nonnull)(UNNotificationPresentationOptions))completionHandler;
- (void)userNotificationCenter:(UNUserNotificationCenter * _Nonnull)center didReceiveNotificationResponse:(UNNotificationResponse * _Nonnull)response withCompletionHandler:(void (^ _Nonnull)(void))completionHandler;
@end

--- 更新

经过一些尝试和错误后,似乎注释掉了从 objC 到 Swift 的所有调用以及声明为 @objc 的 Swift 类型的所有使用使我的代码编译,并且桥接 header 不再抱怨了。这还包括在我的所有 Objective C 代码中注释掉 #import "myapp-Swift.h"(这可能是桥接 header 不再抱怨的原因)。不幸的是,在 ObjC 中停止使用 Swift 类型是不可行的,因为它需要对看似很小的更改进行相当多的重写。

我想这可能在某种程度上表明了问题的根源,但我仍然不确定为什么或如何影响 UNUserNotificationCenterDelegate 协议。

--- 结束更新

其他注意事项:

这是我的git diff供参考:

diff --git a/ios/myapp.xcodeproj/project.pbxproj b/ios/myapp.xcodeproj/project.pbxproj
index 1ac676e..ca3a814 100644
--- a/ios/myapp.xcodeproj/project.pbxproj
+++ b/ios/myapp.xcodeproj/project.pbxproj
@@ -1550,7 +1550,7 @@
                GCC_WARN_UNUSED_FUNCTION = YES;
                GCC_WARN_UNUSED_VARIABLE = YES;
                HEADER_SEARCH_PATHS = "";
-               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+               IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                MTL_ENABLE_DEBUG_INFO = YES;
                ONLY_ACTIVE_ARCH = YES;
                SDKROOT = iphoneos;
@@ -1601,7 +1601,7 @@
                GCC_WARN_UNUSED_FUNCTION = YES;
                GCC_WARN_UNUSED_VARIABLE = YES;
                HEADER_SEARCH_PATHS = "";
-               IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+               IPHONEOS_DEPLOYMENT_TARGET = 10.0;
                MTL_ENABLE_DEBUG_INFO = NO;
                SDKROOT = iphoneos;
                VALIDATE_PRODUCT = YES;
diff --git a/ios/myapp/AppDelegate.swift b/ios/myapp/AppDelegate.swift
index a1c9543..1010f99 100644
--- a/ios/myapp/AppDelegate.swift
+++ b/ios/myapp/AppDelegate.swift
@@ -7,6 +7,7 @@
 //
 
 import UIKit
+import UserNotifications
 import Firebase
 
 @UIApplicationMain
@@ -21,6 +22,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate
         FirebaseInterface.initialize()

         ShoppingListInterface.loadLastSavedShoppingList()
+
+        if #available(iOS 10.0, *) {
+            // For iOS 10 display notification (sent via APNS)
+            UNUserNotificationCenter.current().delegate = self
+
+            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
+            UNUserNotificationCenter.current().requestAuthorization(
+                options: authOptions,
+                completionHandler: {_, _ in })
+        } else {
+            let settings: UIUserNotificationSettings =
+            UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
+            application.registerUserNotificationSettings(settings)
+        }
+
         return true
     }
 
@@ -73,3 +91,46 @@ class AppDelegate: UIResponder, UIApplicationDelegate
         // TODO: Save ShoppingList
     }
 }
+
+@available(iOS 10, *)
+extension AppDelegate : UNUserNotificationCenterDelegate
+{
+
+  // Receive displayed notifications for iOS 10 devices.
+  func userNotificationCenter(_ center: UNUserNotificationCenter,
+                              willPresent notification: UNNotification,
+    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
+    let userInfo = notification.request.content.userInfo
+
+    // With swizzling disabled you must let Messaging know about the message, for Analytics
+    // Messaging.messaging().appDidReceiveMessage(userInfo)
+    // Print message ID.
+//    if let messageID = userInfo[gcmMessageIDKey] {
+//      print("Message ID: \(messageID)")
+//    }
+
+    // Print full message.
+    print(userInfo)
+
+    // Change this to your preferred presentation option
+    completionHandler([[.alert, .sound]])
+  }
+
+  func userNotificationCenter(_ center: UNUserNotificationCenter,
+                              didReceive response: UNNotificationResponse,
+                              withCompletionHandler completionHandler: @escaping () -> Void) {
+    let userInfo = response.notification.request.content.userInfo
+    // Print message ID.
+//    if let messageID = userInfo[gcmMessageIDKey] {
+//      print("Message ID: \(messageID)")
+//    }
+
+    // With swizzling disabled you must let Messaging know about the message, for Analytics
+    // Messaging.messaging().appDidReceiveMessage(userInfo)
+    // Print full message.
+    print(userInfo)
+
+    completionHandler()
+  }
+}
+// [END ios_10_message_handling]
diff --git a/ios/myapp/myapp-Bridging-Header.h b/ios/myapp/myapp-Bridging-Header.h
index 1b2d4c1..4973a15 100644
--- a/ios/myapp/myapp-Bridging-Header.h
+++ b/ios/myapp/myapp-Bridging-Header.h
@@ -11,6 +11,7 @@
     myapp-Swift.h, remember to do #import <UIKit/UIKit.h> in the Objective C
     header file.
  */
+#import <UserNotifications/UNUserNotificationCenter.h>
 #import "ShoppingListWrapper.h"
 #import "DBWrapper.h"
 #import "FirebaseWrapper.h"

经过一段时间的挖掘,我找到了错误的根源。简单做

#import <UserNotifications/UserNotifications.h> // Added this
#import "myapp-Swift.h"

编译代码。这样做的原因是对桥接头的作用感到困惑。我相信桥接头都是用于从 Objective C 到 Swift 的调用,反之亦然。事实并非如此。

  • myapp-Bridging-Header.h 将 Objective C 代码公开给 Swift 以便能够从 Swift 调用到 Objective C。
  • myapp-Swift.h 是自动生成的,并将任何标有 @objc 的 Swift 代码公开到 Objective C,以便能够从 Objective C 调用到 [=39] =].

由于 UNUserNotificationCenterDelegate 协议是 NSObjectProtocol 类型,协议声明在 Objective C 中。因此,除非先完成 #import <UserNotifications/UserNotifications.h>,否则生成的 myapp-Swift.h 不知道它。在这种情况下,甚至不需要在 Swift 中执行 import UserNotifications