Registrieren für Push-Benachrichtigungen in Xcode 8 / Swift 3.0?

121

Ich versuche, meine App in Xcode 8.0 zum Laufen zu bringen, und es tritt ein Fehler auf. Ich weiß, dass dieser Code in früheren Versionen von Swift gut funktioniert hat, aber ich gehe davon aus, dass der Code dafür in der neuen Version geändert wurde. Hier ist der Code, den ich ausführen möchte:

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

Der Fehler, den ich erhalte, lautet "Argumentbezeichnungen" (forTypes:, Kategorien :) "stimmen nicht mit verfügbaren Überladungen überein".

Gibt es einen anderen Befehl, mit dem ich versuchen könnte, dies zum Laufen zu bringen?

Asher Hawthorne
quelle
2
Ich schrieb eine Anleitung, wie man genau das macht: eladnava.com/…
Elad Nava

Antworten:

307

Importieren Sie das UserNotificationsFramework und fügen Sie das UNUserNotificationCenterDelegatein AppDelegate.swift hinzu

Benutzerberechtigung anfordern

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
}

Geräte-Token abrufen

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

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

Im Fehlerfall

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

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

Falls Sie die erteilten Berechtigungen kennen müssen

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 웃
quelle
1
Ich erhalte eine Fehlermeldung in Swift 2.3: UNUserNotificationCenter hat kein aktuelles Mitglied
Async
Heu können Sie die Rettung in Ziel c
Ayaz
Nur eine Notiz, das Gerätetoken wird nicht mehr zurückgegeben. Zumindest in meinem Fall gibt es nur "32 Bytes" zurück
Brian F Leighty
1
@ Async- Sie sehen nicht current (), weil es nur in Swift 3 funktioniert.
Allen
4
@PavlosNicolaou Importieren Sie das UserNotifications Framework
Anish Parajuli 23
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
quelle
Was ist der zusätzliche Vorteil dieses neuen Frameworks? Was ich sehe , ist hier ein mit ‚completionHandler über Delegat‘ -Ansatz und dann wird die Entscheidungsfindung Sie sofort gegeben: Fehler, gewährt oder notGranted .... In 6 <iOS <10 Sie tun musste , um zuapplication.isRegisteredForRemoteNotifications() sehen , ob es gewährt, und verwenden Sie eine andere Delegate-Methode, falls Sie einen Fehler hatten. Richtig? Noch etwas?
Honig
Warum unterscheidet sich Ihre Antwort von der akzeptierten? Er hat eine application.registerForRemoteNotifications() nach seinemcenter.requestAuthorization
Honey
1
@Honig; Dies wird hinzugefügt, wenn "Remote" -Benachrichtigungen aktiviert werden sollen. Als ich meine Antwort schrieb, gab es keine andere Antwort und @OP gab nicht an, ob Remote- oder lokale Unterstützung oder iOS 10-Unterstützung gewünscht wurde, sodass ich so viel wie möglich hinzufügte. Hinweis: Sie sollten sich erst dann für RemoteNotifications registrieren, wenn der Benutzer Zugriff gewährt hat (andernfalls werden alle Remote-Benachrichtigungen stillschweigend übermittelt [sofern Sie dies nicht möchten] - keine Popups). Der Vorteil der neuen API besteht auch darin, dass sie Anhänge unterstützt. Mit anderen Worten, Sie können Ihren Benachrichtigungen GIFs und andere Bilder, Videos usw. hinzufügen.
Brandon
3
Im Abschluss müssen Sie UI-bezogene Aufgaben im Haupt-Thread ausführen ... DispatchQueue.main.async {... hier Sachen machen ...}
Chris Allinson
1
Nutzen Sie diese Lösung, wenn Sie sie nicht in AppDelegate verwenden, um dasselbe im Code zu tun
Codenator81
27
import UserNotifications  

Wechseln Sie als Nächstes zum Projekteditor für Ihr Ziel und suchen Sie auf der Registerkarte Allgemein nach dem Abschnitt Verknüpfte Frameworks und Bibliotheken.

Klicken Sie auf + und wählen Sie 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])
}

Verwenden Sie Benachrichtigungsdelegatmethoden

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

Zum Empfangen von Push-Benachrichtigungen

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

Durch das Einrichten von Push-Benachrichtigungen wird die Funktion in Xcode 8 für Ihre App aktiviert. Gehen Sie einfach zum Projekteditor für Ihr Ziel und klicken Sie dann auf die Registerkarte Funktionen . Suchen Sie nach Push-Benachrichtigungen und schalten Sie den Wert auf EIN .

Unter dem folgenden Link finden Sie weitere Methoden für Benachrichtigungsdelegierte

Behandeln lokaler und Remote-Benachrichtigungen UIApplicationDelegate - Behandeln lokaler und Remote-Benachrichtigungen

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

Mohamed Jaleel Nazir
quelle
20

Ich hatte Probleme mit den Antworten hier beim Konvertieren des deviceToken Data-Objekts in eine Zeichenfolge, die mit der aktuellen Beta von Xcode 8 an meinen Server gesendet werden soll. Insbesondere die, die deviceToken.description wie in 8.0b6 verwendete und "32 Bytes" zurückgab ist nicht sehr nützlich :)

Das hat bei mir funktioniert ...

Erstellen Sie eine Erweiterung für Daten, um eine "hexString" -Methode zu implementieren:

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

Verwenden Sie dies dann, wenn Sie den Rückruf von der Registrierung für Remote-Benachrichtigungen erhalten:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenString = deviceToken.hexString()
    // Send to your server here...
}
Tomwilson
quelle
8
Ich hatte auch das Problem "32 Bytes". Tolle Lösung, Sie können die Konvertierung inline durchführen, ohne eine Erweiterung zu erstellen. So: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz
1
Absurd, dass es keine Lösung von der API selbst gibt
Aviel Gross
1
Ja, es war schon immer ziemlich seltsam, dass API .. überrascht, dass sie es nicht behoben haben, als sie das neue Benachrichtigungs-Framework in iOS10
Tomwilson
17

In iOS10 sollten Sie anstelle Ihres Codes eine Autorisierung zur Benachrichtigung mit folgenden Anforderungen anfordern: (Vergessen Sie nicht, das UserNotificationsFramework hinzuzufügen. )

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

Außerdem ist der richtige Code für Sie ( elsez. B. in der vorherigen Bedingung):

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

Stellen Sie abschließend sicher, dass Push Notificationunter target-> Capabilities-> aktiviert ist Push notification. (setzen Sie es auf On)

tsnkff
quelle
1
siehe: Seite 73 des Apple Doc hier
tsnkff
2
Vielen Dank für die Antwort! Unter Verwendung des Codes heißt es jedoch "Verwendung des nicht aufgelösten Bezeichners 'UNUserNotificationCenter'"
Asher Hawthorne
Und vielen Dank für die Dokumentation, blablabla! Ich habe das auf ihrer Seite nicht gesehen, ich bin froh, dass es existiert. : D
Asher Hawthorne
4
Warten Sie, ich glaube ich habe es verstanden! Musste nur das Benachrichtigungs-Framework importieren. XD
Asher Hawthorne
1
Ja. Ich werde meine Antwort bearbeiten, um sie für zukünftige Leser hinzuzufügen. Lesen Sie auch über die neuen Benachrichtigungen, es gibt jetzt viel leistungsfähigere und interaktivere. :)
tsnkff
8

Nun, diese Arbeit für mich. Zuerst in AppDelegate

import UserNotifications

Dann:

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

Devicetoken bekommen:

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

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

}
GoIn Su
quelle
5

Kopf hoch, Sie sollten den Haupt-Thread für diese Aktion verwenden.

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

Erstens , hören Benutzerbenachrichtigungsstatus, dh registerForRemoteNotifications()APNs Gerät zu bekommen Token;
Zweitens beantragen Sie die Autorisierung. Wenn das Gerät vom Benutzer autorisiert wurde, wird es an den Listener gesendet AppDelegate.
Drittens melden Sie das Gerätetoken Ihrem 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) {
        //
    }
}
DawnSong
quelle
Wie füge ich mehrere Benachrichtigungen hinzu?
ArgaPK
@ArgaPK, Push-Benachrichtigungen zu senden, ist das, was Ihre Serverplattform tut.
DawnSong
0

Die Antwort von ast1 ist sehr einfach und nützlich. Es funktioniert bei mir, vielen Dank. Ich möchte hier nur darauf hinweisen, damit Leute, die diese Antwort brauchen, sie leicht finden können. Hier ist mein Code für die Registrierung der lokalen und Remote-Benachrichtigung (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
quelle
0

Gehen Sie einfach wie folgt vor didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

Denken Sie an die Importanweisung:

import UserNotifications
Bartłomiej Semańczyk
quelle
Ich glaube, das sollte die akzeptierte Antwort sein. Es scheint richtig, registerForRemoteNotifications()den Completion-Handler von aufzurufen requestAuthorization(). Vielleicht möchten Sie sogar registerForRemoteNotifications()mit einer if grantedAussage umgeben: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica
-1

Schauen Sie sich diesen kommentierten Code an:

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

    }
}

Lassen Sie mich wissen, wenn es ein Problem gibt!

CrazyPro007
quelle