Vous vous inscrivez aux notifications push dans Xcode 8 / Swift 3.0?

121

J'essaie de faire fonctionner mon application dans Xcode 8.0 et je rencontre une erreur. Je sais que ce code fonctionnait bien dans les versions précédentes de swift, mais je suppose que le code pour cela est changé dans la nouvelle version. Voici le code que j'essaye d'exécuter:

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

L'erreur que j'obtiens est "Les étiquettes d'argument '(forTypes :, categories :)' ne correspondent à aucune surcharge disponible"

Existe-t-il une commande différente que je pourrais essayer de faire fonctionner?

Asher Hawthorne
la source
2
J'ai écrit un guide sur la façon de faire exactement cela: eladnava.com
Elad Nava

Réponses:

307

Importez le UserNotificationsframework et ajoutez le UNUserNotificationCenterDelegatedans AppDelegate.swift

Demander l'autorisation de l'utilisateur

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
}

Obtention du jeton d'appareil

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

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

En cas d'erreur

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

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

Au cas où vous auriez besoin de connaître les autorisations accordées

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")
            }
        }
Anish Parajuli 웃
la source
1
J'obtiens une erreur dans swift 2.3: UNUserNotificationCenter n'a pas de membre actuel
Async-
Hay pouvez-vous fournir l'arrêt dans l'objectif c
Ayaz
Juste une note, ne renvoie plus le jeton d'appareil. Au moins dans mon cas, il renvoie simplement "32 octets"
Brian F Leighty
1
@ Async - Vous ne voyez pas le courant () car il ne fonctionne que dans Swift 3.
Allen
4
@PavlosNicolaou Importer le framework UserNotifications
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
}
Brandon
la source
Quel est l'avantage supplémentaire de ce nouveau framework? Ce que je vois ici est en utilisant 'completionHandler sur délégué approche et la prise de décision est donnée à vous tout de suite: erreur, accordée ou notGranted .... Dans 6 <iOS <10 vous deviez faire application.isRegisteredForRemoteNotifications()pour voir si elle est accordé et utilisez une autre méthode de délégué au cas où vous auriez une erreur. Droite? Rien d'autre?
Honey
pourquoi la vôtre est-elle différente de la réponse acceptée? Il a un application.registerForRemoteNotifications() après soncenter.requestAuthorization
Chérie
1
@Mon chéri; Cela est ajouté si vous souhaitez activer les notifications "à distance". Quand j'ai écrit ma réponse, aucune autre réponse n'existait et @OP n'a pas précisé s'ils voulaient un support distant ou local ou iOS 10, j'ai donc ajouté autant que possible. Remarque: Vous ne devriez pas vous inscrire à RemoteNotifications tant que l'utilisateur n'a pas accordé l'accès (sinon toutes les notifications à distance sont envoyées silencieusement [sauf si c'est ce que vous voulez] - pas de popup). En outre, l'avantage de la nouvelle API est qu'elle prend en charge les pièces jointes. En d'autres termes, vous pouvez ajouter des GIF et d'autres images, vidéos, etc. à vos notifications.
Brandon
3
Dans la fermeture, vous devrez effectuer des tâches liées à l'interface utilisateur sur le fil de discussion principal ... DispatchQueue.main.async {... faire des choses ici ...}
Chris Allinson
1
Bénéficiez de cette solution lorsque vous ne l'utilisez pas dans AppDelegate pour faire la même chose dans le code
Codenator81
27
import UserNotifications  

Ensuite, allez dans l'éditeur de projet de votre cible et dans l'onglet Général, recherchez la section Frameworks et bibliothèques liés.

Cliquez sur + et sélectionnez 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])
}

Utiliser les méthodes de délégué de notification

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

Pour recevoir une notification push

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

La configuration des notifications push active la fonctionnalité dans Xcode 8 pour votre application. Allez simplement dans l'éditeur de projet de votre cible , puis cliquez sur l' onglet Capacités . Recherchez les notifications Push et bascule sa valeur ON .

Vérifiez le lien ci-dessous pour plus de méthodes de délégué de notification

Gestion des notifications locales et distantes UIApplicationDelegate - Gestion des notifications locales et distantes

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

Mohamed Jaleel Nazir
la source
20

J'ai eu des problèmes avec les réponses ici en convertissant l'objet de données deviceToken en une chaîne à envoyer à mon serveur avec la version bêta actuelle de Xcode 8. Surtout celui qui utilisait deviceToken.description comme dans 8.0b6 qui renverrait "32 octets" qui n'est pas très utile :)

C'est ce qui a fonctionné pour moi...

Créez une extension sur Data pour implémenter une méthode "hexString":

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

Et puis utilisez-le lorsque vous recevez le rappel de l'inscription aux notifications à distance:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenString = deviceToken.hexString()
    // Send to your server here...
}
Tomwilson
la source
8
J'ai également eu le problème "32bytes". Excellente solution, vous pouvez effectuer la conversion en ligne sans créer d'extension. Comme ça: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz
1
Absurde qu'il n'y ait pas de solution venant de l'API elle
Aviel Gross
1
Oui, cette API a toujours été assez étrange ... surpris de ne pas l'avoir corrigée lors de la création du nouveau cadre de notifications dans iOS10
Tomwilson
17

Dans iOS10 au lieu de votre code, vous devez demander une autorisation de notification avec ce qui suit: (N'oubliez pas d'ajouter le UserNotificationsFramework)

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

En outre, le code correct pour vous est (à utiliser dans la elsecondition précédente, par exemple):

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

Enfin, assurez-vous que Push Notificationest activé sous target-> Capabilities-> Push notification. (allumez-le On)

tsnkff
la source
1
voir: Page 73 de l' Apple Doc ici
tsnkff
2
Merci beaucoup pour la réponse! En utilisant le code, cependant, il est dit "Utilisation de l'identifiant non résolu 'UNUserNotificationCenter'"
Asher Hawthorne
Et merci beaucoup pour la documentation, blablabla! Je n'ai pas vu ça sur leur site, je suis content que ça existe. : D
Asher Hawthorne
4
Attendez, je pense que je l'ai compris! Juste eu à importer le cadre de notifications. XD
Asher Hawthorne
1
Oui. Je modifierai ma réponse pour l'ajouter à un futur lecteur. En outre, lisez les nouvelles notifications, il y a maintenant beaucoup plus puissant et interactif. :)
tsnkff
8

Eh bien, ce travail pour moi. Premier dans AppDelegate

import UserNotifications

Ensuite:

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

Pour obtenir un devicetoken:

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

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

}
GoIn Su
la source
5

Attention, vous devriez utiliser le fil de discussion principal pour cette action.

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

Tout d'abord , écoutez l'état de notification de l'utilisateur, c'est- registerForRemoteNotifications()à- dire pour obtenir un jeton d'appareil APN;
Deuxièmement , demandez une autorisation. Lorsqu'il est autorisé par l'utilisateur, deviceToken sera envoyé à l'auditeur, le AppDelegate;
Troisièmement , signalez le jeton d'appareil à votre serveur.

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) {
        //
    }
}
DawnSong
la source
comment ajouter plusieurs notifications?
ArgaPK
@ArgaPK, envoyer des notifications push est ce que fait votre plate-forme serveur.
DawnSong
0

La réponse d' ast1 est très simple et utile. Cela fonctionne pour moi, merci beaucoup. Je veux juste le signaler ici, afin que les personnes qui ont besoin de cette réponse puissent la trouver facilement. Donc, voici mon code d'enregistrement de la notification locale et distante (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
}
Luthfi Rahman
la source
0

Procédez simplement comme suit dans didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

Rappelez-vous de l'instruction d'importation:

import UserNotifications
Bartłomiej Semańczyk
la source
Je pense que cela devrait être la réponse acceptée. Il semble correct d'appeler registerForRemoteNotifications()le gestionnaire d'achèvement de requestAuthorization(). Vous voudrez peut-être même entourer registerForRemoteNotifications()d'une if granteddéclaration: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica
-1

Jetez un œil à ce code commenté:

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

    }
}

Faites-moi savoir s'il y a un problème!

CrazyPro007
la source