Ti stai registrando per le notifiche push in Xcode 8 / Swift 3.0?


121

Sto cercando di far funzionare la mia app in Xcode 8.0 e sto riscontrando un errore. So che questo codice ha funzionato bene nelle versioni precedenti di swift, ma presumo che il codice per questo sia stato modificato nella nuova versione. Ecco il codice che sto cercando di eseguire:

let settings = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil)     
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.shared().registerForRemoteNotifications()

L'errore che ricevo è "Le etichette degli argomenti" (forTypes :, categories :) "non corrispondono ad alcun sovraccarico disponibile"

C'è un comando diverso che potrei provare per farlo funzionare?


2
Ho scritto una guida su come farlo: eladnava.com/…
Elad Nava

Risposte:


307

Importa il UserNotificationsframework e aggiungi il file UNUserNotificationCenterDelegatein AppDelegate.swift

Richiedi l'autorizzazione dell'utente

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
}

Recupero del token del dispositivo

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    print(deviceTokenString)
}

In caso di errore

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {

        print("i am not available in simulator \(error)")
}

Casomai se hai bisogno di conoscere le autorizzazioni concesse

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")
            }
        }

1
Ricevo un errore in swift 2.3: UNUserNotificationCenter non ha membri attuali
Async-

Hay può fornire la parata nell'obiettivo c
Ayaz

Solo una nota, non restituisce più il token del dispositivo. Almeno nel mio caso restituisce semplicemente "32 byte"
Brian F Leighty

1
@ Async- Non vedi current () perché funziona solo in Swift 3.
Allen

4
@PavlosNicolaou Import the UserNotifications framework
Anish Parajuli 웃

48
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
}

Qual è il vantaggio aggiuntivo di questo nuovo framework? Quello che vedo qui è un approccio usando 'completionHandler sopra delegato' e poi il processo decisionale è dato a voi subito: l'errore, scontato, o notGranted .... In 6 <iOS <10 si doveva fare application.isRegisteredForRemoteNotifications()per vedere se si tratta di concesso e utilizzare un altro metodo delegato nel caso in cui si sia verificato un errore. Destra? Qualunque altra cosa?
Miele

perché la tua è diversa dalla risposta accettata? Ha un application.registerForRemoteNotifications() dopo il suocenter.requestAuthorization
Miele

1
@Miele; Questo viene aggiunto se vuoi abilitare le notifiche "Remote". Quando ho scritto la mia risposta, non esisteva nessun'altra risposta e @OP non ha specificato se volevano il supporto remoto o locale o iOS 10, quindi ho aggiunto il più possibile. Nota: non dovresti registrarti per RemoteNotifications fino a quando l'utente non ha concesso l'accesso (altrimenti tutte le notifiche remote vengono consegnate silenziosamente [a meno che non sia quello che vuoi] - nessun popup). Inoltre, il vantaggio della nuova API è che supporta gli allegati. In altre parole, puoi aggiungere GIF e altre immagini, video, ecc. Alle tue notifiche.
Brandon

3
Alla fine, dovrai eseguire le attività relative all'interfaccia utente sul thread principale ... DispatchQueue.main.async {... fai cose qui ...}
Chris Allinson,

1
Vantaggi di questa soluzione quando non viene utilizzata in AppDelegate per eseguire la stessa operazione nel codice
Codenator81

27
import UserNotifications  

Successivamente, vai all'editor del progetto per la tua destinazione e nella scheda Generale, cerca la sezione Framework collegati e librerie.

Fare clic su + e selezionare 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])
}

Usa metodi delegati di notifica

// 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)")
}

Per ricevere notifiche push

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    completionHandler(UIBackgroundFetchResult.noData)
}

L'impostazione delle notifiche push abilita la funzione all'interno di Xcode 8 per la tua app. Basta andare all'editor del progetto per il tuo target e quindi fare clic sulla scheda Funzionalità . Cerca Notifiche push e attiva il suo valore .

Controllare il collegamento sottostante per ulteriori metodi di delegato di notifica

Gestione delle notifiche locali e remote UIApplicationDelegate - Gestione delle notifiche locali e remote

https://developer.apple.com/reference/uikit/uiapplicationdelegate


20

Ho avuto problemi con le risposte qui nella conversione dell'oggetto dati deviceToken in una stringa da inviare al mio server con l'attuale beta di Xcode 8. Soprattutto quello che utilizzava deviceToken.description come in 8.0b6 che restituiva "32 byte" che non è molto utile :)

Questo è ciò che ha funzionato per me...

Crea un'estensione su Data per implementare un metodo "hexString":

extension Data {
    func hexString() -> String {
        return self.reduce("") { string, byte in
            string + String(format: "%02X", byte)
        }
    }
}

E poi usalo quando ricevi la richiamata dalla registrazione per le notifiche remote:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenString = deviceToken.hexString()
    // Send to your server here...
}

8
Ho anche avuto il problema dei "32 byte". Ottima soluzione, puoi eseguire la conversione in linea senza creare un'estensione. In questo modo: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz

1
Assurdo che non ci sia soluzione proveniente dall'API stessa
Aviel Gross

1
Sì, è sempre stato piuttosto strano quell'API .. sorpreso che non lo abbiano risolto durante il nuovo framework di notifiche in iOS10
tomwilson

17

In iOS10 invece del tuo codice, dovresti richiedere un'autorizzazione per la notifica con quanto segue: (Non dimenticare di aggiungere il UserNotificationsFramework)

if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().requestAuthorization([.alert, .sound, .badge]) { (granted: Bool, error: NSError?) in
            // Do something here
        }
    }

Inoltre, il codice corretto per te è (utilizzare nella elsecondizione precedente, ad esempio):

let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared().registerUserNotificationSettings(setting)
UIApplication.shared().registerForRemoteNotifications()

Infine, assicurati che Push Notificationsia attivato in target-> Capabilities-> Push notification. (impostalo su On)


1
vedi: Pagina 73 dell'Apple Doc qui
tsnkff

2
Grazie mille per la risposta! Utilizzando il codice, tuttavia, si dice "Uso dell'identificatore non risolto 'UNUserNotificationCenter'"
Asher Hawthorne

E grazie mille per la documentazione, blablabla! Non l'ho visto sul loro sito, sono contento che esista. : D
Asher Hawthorne

4
Aspetta, penso di averlo capito! Dovevo solo importare il framework delle notifiche. XD
Asher Hawthorne

1
Sì. Modificherò la mia risposta per aggiungerla per il futuro lettore. Inoltre, leggi le nuove notifiche, ora ci sono molto più potenti e interattive. :)
tsnkff

8

Ebbene questo lavoro per me. Primo in AppDelegate

import UserNotifications

Poi:

   func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        registerForRemoteNotification()
        return true
    }

    func registerForRemoteNotification() {
        if #available(iOS 10.0, *) {
            let center  = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
                if error == nil{
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
        else {
            UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
            UIApplication.shared.registerForRemoteNotifications()
        }
    }

Per ottenere devicetoken:

  func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

       let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})

}

5

Attenzione, dovresti usare il thread principale per questa azione.

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
        if granted {
            DispatchQueue.main.async(execute: {
                UIApplication.shared.registerForRemoteNotifications()
            })
        }
    }

2

Innanzitutto , ascolta lo stato di notifica dell'utente, ovvero registerForRemoteNotifications()per ottenere il token del dispositivo APN;
Secondo , richiedi l'autorizzazione. Quando viene autorizzato dall'utente, deviceToken verrà inviato all'ascoltatore, il AppDelegate;
Terzo , segnala il token del dispositivo al tuo server.

extension AppDelegate {
    /// 1. 监听 deviceToken
    UIApplication.shared.registerForRemoteNotifications()

    /// 2. 向操作系统索要推送权限(并获取推送 token)
    static func registerRemoteNotifications() {
        if #available(iOS 10, *) {
            let uc = UNUserNotificationCenter.current()
            uc.delegate = UIApplication.shared.delegate as? AppDelegate
            uc.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
                if let error = error { // 无论是拒绝推送,还是不提供 aps-certificate,此 error 始终为 nil
                    print("UNUserNotificationCenter 注册通知失败, \(error)")
                }
                DispatchQueue.main.async {
                    onAuthorization(granted: granted)
                }
            }
        } else {
            let app = UIApplication.shared
            app.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil)) // 获取用户授权
        }
    }

    // 在 app.registerUserNotificationSettings() 之后收到用户接受或拒绝及默拒后,此委托方法被调用
    func application(_ app: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
        // 已申请推送权限,所作的检测才有效
        // a 征询推送许可时,用户把app切到后台,就等价于默拒了推送
        // b 在系统设置里打开推送,但关掉所有形式的提醒,等价于拒绝推送,得不token,也收不推送
        // c 关掉badge, alert和sound 时,notificationSettings.types.rawValue 等于 0 和 app.isRegisteredForRemoteNotifications 成立,但能得到token,也能收到推送(锁屏和通知中心也能看到推送),这说明types涵盖并不全面
        // 对于模拟器来说,由于不能接收推送,所以 isRegisteredForRemoteNotifications 始终为 false
       onAuthorization(granted: app.isRegisteredForRemoteNotifications)
    }

    static func onAuthorization(granted: Bool) {
        guard granted else { return }
        // do something
    }
}

extension AppDelegate {
    func application(_ app: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        //
    }

    // 模拟器得不到 token,没配置 aps-certificate 的项目也得不到 token,网络原因也可能导致得不到 token
    func application(_ app: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        //
    }
}

come aggiungere più notifiche?
ArgaPK

@ArgaPK, inviare notifiche push è ciò che fa la tua piattaforma server.
DawnSong

0

La risposta di ast1 è molto semplice e utile. Per me funziona, grazie mille. Voglio solo metterlo qui, così le persone che hanno bisogno di questa risposta possono trovarlo facilmente. Quindi, ecco il mio codice per la registrazione della notifica locale e remota (push).

    //1. In Appdelegate: didFinishLaunchingWithOptions add these line of codes
    let mynotif = UNUserNotificationCenter.current()
    mynotif.requestAuthorization(options: [.alert, .sound, .badge]) {(granted, error) in }//register and ask user's permission for local notification

    //2. Add these functions at the bottom of your AppDelegate before the last "}"
    func application(_ application: UIApplication, didRegister notificationSettings: UNNotificationSettings) {
        application.registerForRemoteNotifications()//register for push notif after users granted their permission for showing notification
}
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let tokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
    print("Device Token: \(tokenString)")//print device token in debugger console
}
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register: \(error)")//print error in debugger console
}

0

Basta fare quanto segue in didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

    center.delegate = self
    center.requestAuthorization(options: []) { _, _ in
        application.registerForRemoteNotifications()
    }
}

Ricorda sulla dichiarazione di importazione:

import UserNotifications

Credo che questa dovrebbe essere la risposta accettata. Sembra corretto chiamare registerForRemoteNotifications()il gestore del completamento di requestAuthorization(). Potresti anche circondarti registerForRemoteNotifications()di una if granteddichiarazione: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica

-1

Dai un'occhiata a questo codice commentato:

import Foundation
import UserNotifications
import ObjectMapper

class AppDelegate{

    let center = UNUserNotificationCenter.current()
}

extension AppDelegate {

    struct Keys {
        static let deviceToken = "deviceToken"
    }

    // MARK: - UIApplicationDelegate Methods
    func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

        if let tokenData: String = String(data: deviceToken, encoding: String.Encoding.utf8) {
            debugPrint("Device Push Token \(tokenData)")
        }

        // Prepare the Device Token for Registration (remove spaces and < >)
        setDeviceToken(deviceToken)
    }

    func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        debugPrint(error.localizedDescription)
    }

    // MARK: - Private Methods
    /**
     Register remote notification to send notifications
     */
    func registerRemoteNotification() {

        center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in

            // Enable or disable features based on authorization.
            if granted  == true {

                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            } else {
                debugPrint("User denied the permissions")
            }
        }
    }

    /**
     Deregister remote notification
     */
    func deregisterRemoteNotification() {
        UIApplication.shared.unregisterForRemoteNotifications()
    }

    func setDeviceToken(_ token: Data) {
        let token = token.map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
        UserDefaults.setObject(token as AnyObject?, forKey: “deviceToken”)
    }

    class func deviceToken() -> String {
        let deviceToken: String? = UserDefaults.objectForKey(“deviceToken”) as? String

        if isObjectInitialized(deviceToken as AnyObject?) {
            return deviceToken!
        }

        return "123"
    }

    func isObjectInitialized(_ value: AnyObject?) -> Bool {
        guard let _ = value else {
                return false
         }
            return true
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping(UNNotificationPresentationOptions) -> Swift.Void) {

        ("\(notification.request.content.userInfo) Identifier: \(notification.request.identifier)")

        completionHandler([.alert, .badge, .sound])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping() -> Swift.Void) {

        debugPrint("\(response.notification.request.content.userInfo) Identifier: \(response.notification.request.identifier)")

    }
}

Fammi sapere se c'è qualche problema!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.