Registering for Push Notifications in Xcode 8/Swift 3.0?

107,062

Solution 1

Import the UserNotifications framework and add the UNUserNotificationCenterDelegate 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)

Share:
107,062
Asher Hawthorne
Author by

Asher Hawthorne

Updated on January 28, 2020

Comments

  • Asher Hawthorne
    Asher Hawthorne over 4 years

    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?

  • tsnkff
    tsnkff almost 8 years
    see : Page 73 of the Apple Doc here
  • Asher Hawthorne
    Asher Hawthorne almost 8 years
    Thank you so much for the reply! Using the code, however, it is saying "Use of unresolved identifier 'UNUserNotificationCenter'"
  • Asher Hawthorne
    Asher Hawthorne almost 8 years
    And thank you so much for the documentation, blablabla! I didn't see that on their site, I'm glad it exists. :D
  • Asher Hawthorne
    Asher Hawthorne almost 8 years
    Wait, I think I got it! Just had to import the notifications framework. XD
  • tsnkff
    tsnkff almost 8 years
    Yep. I'll edit my answer to add this for future reader. Also, read about the new notifications, there are way more powerful and interactive now. :)
  • Asher Hawthorne
    Asher Hawthorne almost 8 years
    I'm so excited, I've been wanting to add push notifications to my app (been learning Xcode as a hobby for the last year, but there are still so many things I need to know), and with the new notifications, I figure now is the time. I got notifications working with my dev iPhone, now I just have to figure out how to get the tokens for phones running the production version and pass them to the php script I'm using.
  • Async-
    Async- almost 8 years
    I get error in swift 2.3: UNUserNotificationCenter has no member current
  • Alain Stulz
    Alain Stulz over 7 years
    I also had the "32bytes" problem. Great solution, you can do the conversion in-line without creating an extension though. Like this: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
  • Aviel Gross
    Aviel Gross over 7 years
    Absurd that there is no solution coming from the API itself
  • Ayaz
    Ayaz over 7 years
    Hay can you provide the save in objective c
  • Brian F Leighty
    Brian F Leighty over 7 years
    Just a note, no longer returns the device token. At least in my case it merely returns "32 bytes"
  • Anish Parajuli 웃
    Anish Parajuli 웃 over 7 years
    @BrianFLeighty Thanks ,i have edited as ast1 comment
  • Allen
    Allen over 7 years
    @Async- You're not seeing current() because it's only working in Swift 3.
  • n3wbie
    n3wbie over 7 years
    Don't forget to link UserNotifications.framework to your target, and to import it in your AppDelegate. ;)
  • tomwilson
    tomwilson over 7 years
    Yeah it has always been pretty weird that API.. surprised they didn't fix it when doing the new notifications framework in iOS10
  • KML
    KML over 7 years
    How can I register for remote notifications outside of AppDelegate? I dont want pop ups being the first thing that happens when the user opens the app.
  • KML
    KML over 7 years
    @Anish웃 Hi it would be fantastic if you could suggest an answer to my questions here ! :) stackoverflow.com/questions/40587598/…
  • Anish Parajuli 웃
    Anish Parajuli 웃 over 7 years
    @KML just wrap these block of statements let center = UNUserNotificationCenter.current() center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in // Enable or disable features based on authorization. } application.registerForRemoteNotifications() inside a method in AppDelegate.And call the wrapper method from anywhere by getting the reference of AppDelegate. Keepin those methods on didFinishLaunchingWithOptions request permission as soon as when app is launched.So do as i have said priorly
  • LukeSideWalker
    LukeSideWalker about 7 years
    Thanks at first and please excuse the following question, that results just from a lack of experience and knowledge: What is the purpose of the deviceToken, what for is it used?
  • Anish Parajuli 웃
    Anish Parajuli 웃 about 7 years
    @LukeSideWalker The device token represents the identity of the device receiving the notification. APNs uses device tokens to identify each unique app and device combination.See more here
  • mfaani
    mfaani about 7 years
    What's the added benefit of this new framework? What I see here is a using 'completionHandler over delegate' approach and then the decision making is given to you right away: error, granted, or notGranted .... In 6< iOS <10 you had to do ‍application.isRegisteredForRemoteNotifications() to see if it's granted, and use another delegate method in case you had an error. Right? Anything else?
  • mfaani
    mfaani about 7 years
    What's the added benefit of this new framework? What I see here is a using 'completionHandler over delegate' approach and then the decision making is given to you right away: error, granted, or notGranted .... In 6< iOS <10 you had to do ‍application.isRegisteredForRemoteNotifications() to see if it's granted, and use another delegate method in case you had an error. Right? Anything else?
  • mfaani
    mfaani about 7 years
    why is your's different from the accepted answer? He has a application.registerForRemoteNotifications() after his center.requestAuthorization
  • Brandon
    Brandon about 7 years
    @Honey; That is added if you want "Remote" notifications enabled. When I wrote my answer, no other answer existed and @OP did not specify whether they wanted remote or local or iOS 10 support so I added as much as I could. Note: You shouldn't register for RemoteNotifications until the user has granted access (otherwise all remote notifications are delivered silently [unless that's what you want ] -- no popups). Also, the advantage of the new API is that it supports attachments. In other words, you can add GIF's and other Images, Videos, etc.. to your notifications.
  • Brandon
    Brandon about 7 years
    To add attachments, you do: notification.content.attachments = [UNNotificationAttachment(identifier: "png_identifier", url:imageURL , options: nil)] or UNNotificationAttachment(identifier: "audio_identifier", url:imageURL , options: [UNNotificationAttachmentOptionsTypeHintKey:kUTTypeMP3]), etc.. for example.
  • mfaani
    mfaani about 7 years
    Oh ok... interesting.... You mean the payload will have a URL of the gif? or it's being sent as Data?
  • Brandon
    Brandon about 7 years
    @Honey the notification will actually display as a gif when it is received and opened. If it is a video, it will show a thumbnail just like an image. The URL will be downloaded by the receiving device. If it is local, it will be sent as data and the receiving device will display it correctly. I believe videos will only be sent as a URL but with a preview (like in iMessage). I haven't tried all of them yet; just images and gifs.
  • Chris Allinson
    Chris Allinson about 7 years
    In the closure, you'll need to perform UI related tasks on the Main Thread ... DispatchQueue.main.async { ... update a label ... }
  • Chris Allinson
    Chris Allinson about 7 years
    In the closure, you'll need to perform UI related tasks on the Main Thread ... DispatchQueue.main.async { ... do stuff here ... }
  • Anish Parajuli 웃
    Anish Parajuli 웃 about 7 years
    @ChrisAllinson the callback is always in main thread after the operation completes
  • Pavlos
    Pavlos about 7 years
    I got unresolved identifier: 'UNUserNotificationCenter' do you know why? I am using Swift 3.1
  • Anish Parajuli 웃
    Anish Parajuli 웃 about 7 years
    @PavlosNicolaou Import the UserNotifications framework
  • Bocaxica
    Bocaxica almost 7 years
    I believe this should be the accepted answer. It seems correct to call registerForRemoteNotifications() in the completion handler of requestAuthorization(). You may even want to surround registerForRemoteNotifications() with an if granted statement: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
  • Dilip Tiwari
    Dilip Tiwari over 6 years
    @ThatlazyiOSGuy웃 Can u tell me step by step procedure if user will register in website app will get a notifications
  • Dilip Tiwari
    Dilip Tiwari over 6 years
    I want to display Push Notifications in Foreground State for iOS 8.0,i m receiving notifications in background state @tsnkff
  • Dilip Tiwari
    Dilip Tiwari over 6 years
    I want to display Push Notifications in Foreground State for iOS 8.0,i m receiving notifications in background state @ChrisAllinson
  • Chris Allinson
    Chris Allinson over 6 years
    @DilipTiwari last I checked you can "hear" that a push is received, but you have to manually handle that case in the didReceiveRemoteNotification AppDelegate method (and manually display something to the user) ... some further SO reading: stackoverflow.com/questions/14872088/…
  • DawnSong
    DawnSong over 6 years
    The error in requestAuthorization(options:completionHandler:) is always nil whenever I refuse to receive notification or do not provide a aps-certificate. How to get a real error?
  • DawnSong
    DawnSong about 6 years
    application.registerForRemoteNotifications() goes first, then request permission. The first step just may get several call back from iOS system in AppDelegate's didRegisterForRemoteNotificationsWithDeviceToken if you turn the notification switch on and off several times.
  • DawnSong
    DawnSong about 6 years
    Your answer is not very clear. application.registerForRemoteNotifications() goes first, then request permission. The first step just may get several call back from iOS system in AppDelegate's didRegisterForRemoteNotificationsWithDeviceToken if you turn the notification switch on and off several times.
  • ArgaPK
    ArgaPK about 6 years
    how to add/triger multiple notifications?
  • ArgaPK
    ArgaPK about 6 years
    how to add multiple notification?
  • ArgaPK
    ArgaPK about 6 years
    how to add/triger multiple notifications?
  • DawnSong
    DawnSong about 6 years
    @ArgaPK, To send push notifications is what your server platform does.
  • Smartcat
    Smartcat about 6 years
    @DawnSong I don't believe the order matters to iOS. It may matter to your app, though. If you don't seek and receive permission, iOS will silently notify your app. So it's generally best to ask user for permission BEFORE registering (and then only registering if granted the permission) unless you want the silent notifications.
  • Codenator81
    Codenator81 over 5 years
    Benefit of this solution when use not in AppDelegate to do same thing in code