Xcode 8 / Swift 3.0'da Anlık Bildirimler için Kaydolma?


121

Uygulamamı Xcode 8.0'da çalıştırmaya çalışıyorum ve bir hatayla karşılaşıyorum. Bu kodun swift'in önceki sürümlerinde iyi çalıştığını biliyorum, ancak bunun kodunun yeni sürümde değiştirildiğini varsayıyorum. İşte çalıştırmaya çalıştığım kod:

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

Aldığım hata "Bağımsız değişken etiketleri '(forTypes :, kategoriler :)' mevcut herhangi bir aşırı yüklemeyle eşleşmiyor"

Bunu çalıştırmaya çalışabileceğim farklı bir komut var mı?


2
Bunun nasıl yapılacağına dair bir rehber yazdım: eladnava.com/…
Elad Nava

Yanıtlar:


307

UserNotificationsÇerçeveyi içe aktarın ve UNUserNotificationCenterDelegateAppDelegate.swift'e ekleyin

Kullanıcı izni isteyin

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
}

Cihaz jetonu alınıyor

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

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

Hata durumunda

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

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

Verilen izinleri bilmeniz gerekirse

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
Hızlı 2.3'te hata alıyorum: UNUserNotificationCenter'ın şu anki üyesi yok
Async -

Hay c hedefinde tasarruf sağlayabilir misin
Ayaz

Sadece bir not, artık cihaz jetonunu döndürmüyor. En azından benim durumumda yalnızca "32 bayt" döndürüyor
Brian F Leighty

1
@ Async- Akımı () görmüyorsunuz çünkü yalnızca Swift 3'te çalışıyor.
Allen

4
@PavlosNicolaou Kullanıcı Bildirimleri çerçevesini içe aktar
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
}

Bu yeni çerçevenin ek faydası nedir? Ne ben burada bakın bir kullanarak 'completionHandler temsilci üzerinde' yaklaşımdır ve daha sonra karar verme hemen size verilen: hata, verilen veya notGranted .... 6 <iOS <10 size yapmak zorunda application.isRegisteredForRemoteNotifications()o olup olmadığını görmek için Sağ? Başka herhangi bir şey?
Honey

seninki neden kabul edilen cevaptan farklı? Geride bir application.registerForRemoteNotifications() sonra onuncenter.requestAuthorization
Bal

1
@Bal; Bu, "Uzaktan" bildirimlerin etkinleştirilmesini istiyorsanız eklenir. Cevabımı yazdığımda başka bir cevap yoktu ve @OP uzaktan mı yoksa yerel mi yoksa iOS 10 desteği mi istediklerini belirtmedi, bu yüzden elimden geldiğince ekledim. Not: Kullanıcı erişim izni verene kadar RemoteNotifications için kaydolmamalısınız (aksi halde tüm uzak bildirimler sessizce teslim edilir [istediğiniz bu değilse] - açılır pencere yok). Ayrıca, yeni API'nin avantajı, ekleri desteklemesidir. Diğer bir deyişle, bildirimlerinize GIF'ler ve diğer Görseller, Videolar vb. Ekleyebilirsiniz.
Brandon

3
Kapanışta, Ana İş Parçacığı üzerinde UI ile ilgili görevleri gerçekleştirmeniz gerekecek ... DispatchQueue.main.async {... burada bir şeyler yapın ...}
Chris Allinson

1
Kodda aynı şeyi yapmak için AppDelegate'de kullanılmadığında bu çözümün faydası
Codenator81

27
import UserNotifications  

Ardından, hedefiniz için proje düzenleyicisine gidin ve Genel sekmesinde Bağlantılı Çerçeveler ve Kitaplıklar bölümünü arayın.

+ Öğesini tıklayın ve UserNotifications.framework öğesini seçin:

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

Bildirim temsilcisi yöntemlerini kullanın

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

Push bildirimi almak için

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

Push bildirimlerini ayarlamak, uygulamanız için Xcode 8 içindeki özelliği etkinleştiriyor. Basitçe sizin hedef için proje editörü gidin ve sonra tıklayın Yetenekleri sekmesine . Anlık Bildirimleri arayın ve değerini AÇIK olarak değiştirin .

Daha fazla Bildirim temsilcisi yöntemi için aşağıdaki bağlantıyı kontrol edin

Yerel ve Uzaktan Bildirimleri Yönetme UIApplicationDelegate - Yerel ve Uzaktan Bildirimleri İşleme

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


20

DeviceToken Data nesnesini sunucuma Xcode 8'in mevcut beta sürümüyle göndermek için bir dizeye dönüştürürken buradaki yanıtlarla ilgili sorunlar yaşadım. Özellikle 8.0b6'da olduğu gibi deviceToken.description kullanan ve "32 Bayt" döndüren pek kullanışlı değil :)

Bu benim için çalıştı ...

"HexString" yöntemini uygulamak için Veri üzerinde bir uzantı oluşturun:

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

Uzaktan bildirimlere kaydolmaktan geri aramayı aldığınızda bunu kullanın:

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

8
Ayrıca "32byte" sorunum vardı. Harika bir çözüm, dönüşümü bir uzantı oluşturmadan satır içi yapabilirsiniz. let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Şunun

1
API'nin kendisinden gelen bir çözüm olmaması saçma
Aviel Gross

1
Evet, API'nin iOS10'da yeni bildirim çerçevesini yaparken düzeltmemelerine şaşırdı
tomwilson

17

İOS10'da kodunuz yerine, aşağıdakilerle bildirim için bir yetkilendirme talep etmelisiniz: ( UserNotificationsÇerçeveyi eklemeyi unutmayın )

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

Ayrıca, sizin için doğru kod şudur ( elseörneğin, önceki koşulda kullanın ):

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

Son olarak, -> -> Push Notificationaltında etkinleştirildiğinden emin olun . (üzerine ayarlatargetCapabilitiesPush notificationOn )



2
Yanıt için çok teşekkürler! Ancak kodu kullanarak "Çözülmemiş tanımlayıcı 'UNUserNotificationCenter' kullanımı" diyor
Asher Hawthorne

Ve belgeler için çok teşekkür ederim blablabla! Bunu kendi sitesinde görmedim, var olduğuna sevindim. : D
Asher Hawthorne

4
Bekle, sanırım anladım! Sadece bildirim çerçevesini içe aktarmak zorunda kaldı. XD
Asher Hawthorne

1
Evet. Cevabımı gelecekteki okuyucuya eklemek için düzenleyeceğim. Ayrıca, yeni bildirimler hakkında okuyun, artık çok daha güçlü ve etkileşimli var. :)
tsnkff

8

Peki bu benim için çalışıyor. AppDelegate'te ilk

import UserNotifications

Sonra:

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

Cihaz jetonunu almak için:

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

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

}

5

Dikkat edin, bu eylem için ana konuyu kullanmalısınız.

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

2

İlk olarak , kullanıcı bildirim durumunu dinleyin, yani registerForRemoteNotifications()APNs cihaz belirteci almak için;
İkinci olarak , yetki isteyin. Kullanıcı tarafından yetkilendirildiğinde, deviceToken dinleyiciye gönderilecektir AppDelegate;
Üçüncü olarak , cihaz jetonunu sunucunuza bildirin.

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

birden çok bildirim nasıl eklenir?
ArgaPK

@ArgaPK, sunucu platformunuzun yaptığı şey push bildirimleridir.
DawnSong

0

Ast1'in cevabı çok basit ve kullanışlıdır. Benim için çalışıyor, çok teşekkür ederim. Ben sadece onu buraya işaret etmek istiyorum, böylece bu cevaba ihtiyaç duyan insanlar kolayca bulabilir. İşte yerel ve uzak (push) bildirim kaydetme kodum.

    //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

Aşağıdakileri yapmanız yeterlidir didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

Import deyimini hatırlayın:

import UserNotifications

Bunun kabul edilen cevap olması gerektiğine inanıyorum. registerForRemoteNotifications()Tamamlama işleyicisini aramak doğru görünüyor requestAuthorization(). Hatta registerForRemoteNotifications()bir if grantedifadeyle çevrelemek isteyebilirsiniz : center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica

-1

Bu yorumlanmış koda bir göz atın:

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

    }
}

Herhangi bir sorun olursa bana haber ver!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.