I have a an iOS app using Firebase for notifications. Notifications are set up and working, and I now need to receive/handle the notifications to present view controllers accordingly. I use Objective C code to call my C++ code, and therefore I have a bridging header in my project, which is mainly written in Swift.
I have used this example from the firebase documentation (as well as other examples). In short terms: conform to the protocol UNUserNotificationCenterDelegate
and implement its functions. I also do import UserNotifications
in my AppDelegate
class.
Now, when compiling with these few changes I get these two errors
Cannot find protocol declaration for 'UNUserNotificationCenterDelegate'
Unknown type name 'UNNotificationPresentationOptions'
for the generated code:
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
After some trial and error it seems that commenting out all calls from objC to Swift as well as all usage of Swift types declared as @objc
makes my code compile, and the bridging header does not complain anymore. This also includes commenting out #import "myapp-Swift.h"
in all my Objective C code (which is probably why the bridging header does not complain anymore). Unfortunately it is not feasible to stop using the Swift types in ObjC, as it would require quite some rewrite for a seemingly small change.
I guess this could somewhat indicate the origin of the issue, though I am still no sure why or how this affects the UNUserNotificationCenterDelegate
protocol.
Other things to note:
myapp-Swift.h
.#import <UserNotifications/UNUserNotificationCenter.h>
to my bridging header. Xcode does not complain about the include, so it does find it, but it does not help. Doing #import <UserNotifications/UserNotifications.h>
does not work either.UNUserNotificationCenterDelegate
both in the AppDelegate
itself and as an extension. The errors are the same in both cases..mm
files and the errors originate from there.UserNotifications.framework
is in Frameworks, Libraries and Embedded Content
.UserNotifications.framework
is in Link Binary With Libraries
.Here is my git diff
for reference:
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"
After digging for some time I found the source of the error. Simply doing
#import <UserNotifications/UserNotifications.h> // Added this
#import "myapp-Swift.h"
makes the code compile. The reason for this originates from confusion about what the bridging header does. I believed that the bridging header was both for calling from Objective C to Swift and vice versa. This is not the case.
myapp-Bridging-Header.h
exposes Objective C code to Swift to be able to call from Swift to Objective C.myapp-Swift.h
is autogenerated and exposes any Swift code marked with @objc
to Objective C, to be able to call from Objective C to Swift.Since the UNUserNotificationCenterDelegate
protocol is of type NSObjectProtocol, the protocol declaration is in Objective C. Thus, the generated myapp-Swift.h
does not know about it unless #import <UserNotifications/UserNotifications.h>
is done first. Doing import UserNotifications
in Swift is not even needed in this case.