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
--- Update
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.
--- End Update
Other things to note:
- The error originates from an Objective C++ file where I import the generated
myapp-Swift.h
. - I tried adding
#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. - I tried conforming to
UNUserNotificationCenterDelegate
both in theAppDelegate
itself and as an extension. The errors are the same in both cases. - The bridging header is included in my
.mm
files and the errors originate from there. UserNotifications.framework
is inFrameworks, Libraries and Embedded Content
.UserNotifications.framework
is inLink Binary With Libraries
.- I tried changing the deployment target to newer versions without luck.
- I looked at this question which is basically the same as this one, but nothing works. It points further to
- this question, but that is not my use case.
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
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 generatedmyapp-Swift.h
does not know about it unless#import <UserNotifications/UserNotifications.h>
is done first. Doingimport UserNotifications
in Swift is not even needed in this case.