Registering for Push Notifications in Xcode 8/Swift 3.0?
I'm trying to get my app working in Xcode 8.0, and am running into an error. I know this code worked fine in previous versions of swift, but I'm assuming the code for this is changed in the new version. Here's the code I'm trying to run:
let settings = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.shared().registerForRemoteNotifications()
The error that I'm getting is "Argument labels '(forTypes:, categories:)' do not match any available overloads"
Is there a different command that I could try to get this working?
Solution 1:
Import the
UserNotifications
framework and add theUNUserNotificationCenterDelegate
in AppDelegate.swift
Request user permission
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
return true
}
Getting device token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
In case of error
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
In case if you need to know the permissions granted
UNUserNotificationCenter.current().getNotificationSettings(){ (settings) in
switch settings.soundSetting{
case .enabled:
print("enabled sound setting")
case .disabled:
print("setting has been disabled")
case .notSupported:
print("something vital went wrong here")
}
}
Solution 2:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if #available(iOS 10, *) {
//Notifications get posted to the function (delegate): func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void)"
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
guard error == nil else {
//Display Error.. Handle Error.. etc..
return
}
if granted {
//Do stuff here..
//Register for RemoteNotifications. Your Remote Notifications can display alerts now :)
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
else {
//Handle user denying permissions..
}
}
//Register for remote notifications.. If permission above is NOT granted, all notifications are delivered silently to AppDelegate.
application.registerForRemoteNotifications()
}
else {
let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
return true
}
Solution 3:
import UserNotifications
Next, go to the project editor for your target, and in the General tab, look for the Linked Frameworks and Libraries section.
Click + and select UserNotifications.framework:
// iOS 12 support
if #available(iOS 12, *) {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound, .provisional, .providesAppNotificationSettings, .criticalAlert]){ (granted, error) in }
application.registerForRemoteNotifications()
}
// iOS 10 support
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
}
// iOS 9 support
else if #available(iOS 9, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 8 support
else if #available(iOS 8, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 7 support
else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
Use Notification delegate methods
// Called when APNs has assigned the device a unique token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Convert token to string
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("APNs device token: \(deviceTokenString)")
}
// Called when APNs failed to register the device for push notifications
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Print the error to console (you should alert the user that registration failed)
print("APNs registration failed: \(error)")
}
For receiving push notification
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.noData)
}
Setting up push notifications is enabling the feature within Xcode 8 for your app. Simply go to the project editor for your target and then click on the Capabilities tab. Look for Push Notifications and toggle its value to ON.
Check below link for more Notification delegate methods
Handling Local and Remote Notifications UIApplicationDelegate - Handling Local and Remote Notifications
https://developer.apple.com/reference/uikit/uiapplicationdelegate
Solution 4:
I had issues with the answers here in converting the deviceToken Data object to a string to send to my server with the current beta of Xcode 8. Especially the one that was using deviceToken.description as in 8.0b6 that would return "32 Bytes" which isn't very useful :)
This is what worked for me...
Create an extension on Data to implement a "hexString" method:
extension Data {
func hexString() -> String {
return self.reduce("") { string, byte in
string + String(format: "%02X", byte)
}
}
}
And then use that when you receive the callback from registering for remote notifications:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.hexString()
// Send to your server here...
}
Solution 5:
In iOS10 instead of your code, you should request an authorization for notification with the following: (Don't forget to add the UserNotifications
Framework)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization([.alert, .sound, .badge]) { (granted: Bool, error: NSError?) in
// Do something here
}
}
Also, the correct code for you is (use in the else
of the previous condition, for example):
let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared().registerUserNotificationSettings(setting)
UIApplication.shared().registerForRemoteNotifications()
Finally, make sure Push Notification
is activated under target
-> Capabilities
-> Push notification
. (set it on On
)