To generate local notifications in my library, I need to use either UserNotification or UILocalNotification depending on what my host app uses. (Some customers are still using the deprecated didReceiveLocalNotification: API).
Now when I create my notification, is it possible, at runtime, to determine which system the host app uses and create the appropriate APIs. This means I will need to conditionally import and use the UserNotification header file.
EDIT:
Regarding the use of NSClassFromString:
if (NSClassFromString(#"FrameworkClass") == nil) {
// the framework is not available
} else {
// the framework is avaiable
}
But I have a lot of UserNotification code to write. I don't think using performSelector: would be very practical.
What about preprocessor macros?
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
// Only COMPILE this if compiled against BaseSDK iOS10.0 or greater
#import <UserNotifications/UserNotifications.h>
#endif
This is example Register for remote notifications checking API
In Swift
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)
}
application.registerForRemoteNotifications()
In Obj-C
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
// iOS 10 or later
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions =
UNAuthorizationOptionAlert
| UNAuthorizationOptionSound
| UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
#endif
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
I don't think you can import a framework at runtime in Objective-C.
You can tap into objective c runtime magic and use performSelector: to call selectors/methods without importing a class/framework but you don't necessarily want to use it as there is no compile-time checking on selector names and may result in app crashes if it is not used propertly.
The only way I can think of achieving what you want is to weak-link UserNotifications framework in your library.
On runtime you can check whether your client supports the framework, and if the framework symbols are available, you can run them safely.
Doing it this way, you get the compile time safety of method name checking, and you can write your code in a normal manner but yeah don't forget to check for the availability of the framework before executing any of its symbols.
Related
I have an iOS app that includes user 'alarms' - sent to user when the the app is not in foreground. I am using UNUserNotifications and all is working well in iOS 10 and iOS 11 testing.
I would also like to reach users who are still using iOS 8 and iOS 9.
In order to send notifications to the iOS 8 users, do I need to include alternate methods that use UILocalNotifications? Or will iOS 8 respond correctly UNUserNotificatons?
If I need to include both, I can use some if's to use the right one based on OS. It just seems odd that I must include a deprecated technique.
UNUserNotifications are iOS 10 and higher, so won't work on iOS 8 and iOS 9. In that case you should check if is UNUserNotifications exists, or otherwise fall back to the older methods, eg:
if (NSClassFromString(#"UNUserNotificationCenter")) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNAuthorizationOptions options = (UNAuthorizationOptionBadge | UNAuthorizationOptionAlert | UNAuthorizationOptionSound);
[center requestAuthorizationWithOptions: options
completionHandler: ^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(#"Granted notifications!");
}
}];
}
else {
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes: userNotificationTypes categories: nil];
[[UIApplication sharedApplication] registerUserNotificationSettings: settings];
}
The UserNotifications framework was added to iOS with iOS 10, so for any version before that, you'll need to use the older UILocalNotification. You are correct that UILocalNotification was deprecated in iOS 10 in favor of UserNotifications.framework, but before iOS 10, symbols from the UserNotifications framework are unavailable, so there's no other way. You can use a simple iOS version check to determine when to use either method:
if(#available(iOS 10, *)){
//UserNotifications method
}
else{
//UILocalNotification method
}
i'm trying to add Firebase to my IOS application using their api Guide,
and i'm adding the "Register for remote notifications" code under my didFinishLaunchingWithOptions in my AppDelegate.m as suggested by Firebase.
but it writes an error saying
Property 'delegate' not found on object of type 'id'
here is my didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Register app for remote notifications
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
} else {
// iOS 10 or later
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions =
UNAuthorizationOptionAlert
| UNAuthorizationOptionSound
| UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
#endif
}
[application registerForRemoteNotifications];
what am i doing wrong ?
I executed your code in iOS 11 & iOS 8 , working for me. I think it is crashing somewhere else.
In my on-boarding I have a UIPageViewController containing a ‘primer’ screen at the end for authorizing notifications. The user would tap a button labeled “Enable Notifications” and the notifications permission dialog would appear. How do I accomplish this?
You can put:
Objective-C
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// Enable or disable features based on authorization.
}];
[[UIApplication sharedApplication] registerForRemoteNotifications]; // you can also set here for local notification.
Swift
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
UIApplication.shared.registerForRemoteNotifications() // you can also set here for local notification.
inside your IBAction.
Please remember also add import UserNotifications for Swift or #import <UserNotifications/UserNotifications.h> for Objective-C in file where you have IBAction and make sure that Push Notification is activated under target - Capabilities - Push notification.
Objective-C:
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
I use APNS and it's work fine on iOS 9.
With the new push API changes on iOS10 i cant register for push notification so i insert the next changes:
Enable push notification in the target capabilities tab.
In didFinishLaunchingWithOptions we check the OS version and register as followed :
if (SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(#"10.0")) {
//ios 10 Notifiction
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ){
[[UIApplication sharedApplication] registerForRemoteNotifications];
NSLog(#"iOS 10 push notification register successfully ");
}
}];
} else {
// iOS 8-9 Notifications
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
NSLog(#"iOS 9 push notification register successfully ");
}
With this changes I manage to perform registration in iOS 9 and iOS 10 but I have couple of problems :
Once I enable the push notification in the target capabilities tab the push notification stop working on iOS 9 although the registration was complete successfully .
The push doesn’t work on iOS 10 at all although the registration was complete successfully .
Please keep in mind that if I turn off the push notification in the target capabilities tab (with the same code) the push return to work on iOS 9 but I cant register for APNS on iOS 10.
if #available(iOS 8.0, *) {
let settings: UIUserNotificationSettings = UIUserNotificationSettings (types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}else {
let types: UIRemoteNotificationType = [.alert, .badge, .sound]
application.registerForRemoteNotifications(matching: types)
}
I am using parse notifications, but I want the notification to give an alert and a sound. I now have this:
var pushSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: .Alert, categories: nil)
But how do I also register for .sound? In objective-C it's apparently this:
// Let device know you're going to be sending one of these types of notifications.
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
But, I am very new to Swift and I really don't know how to use it in Swift!
Thanks in Advance!
This should work...
let pushSettings = UIUserNotificationSettings(forTypes: .Alert | .Badge | .Sound, categories: nil)