Mendaftar untuk Pemberitahuan Push di Xcode 8 / Swift 3.0?

121

Saya mencoba membuat aplikasi saya berfungsi di Xcode 8.0 , dan saya mengalami kesalahan. Saya tahu kode ini berfungsi dengan baik di versi swift sebelumnya, tetapi saya berasumsi kode untuk ini diubah di versi baru. Inilah kode yang saya coba jalankan:

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

Kesalahan yang saya dapatkan adalah "Label argumen '(forTypes :, kategori :)' tidak cocok dengan kelebihan beban yang tersedia"

Apakah ada perintah lain yang bisa saya coba agar ini berfungsi?

Asher Hawthorne
sumber
2
Saya menulis panduan tentang cara melakukan hal itu: eladnava.com/…
Elad Nava

Jawaban:

307

Impor UserNotificationskerangka kerja dan tambahkan UNUserNotificationCenterDelegatedi AppDelegate.swift

Minta izin pengguna

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
}

Mendapatkan token perangkat

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

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

Jika terjadi kesalahan

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

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

Dalam kasus jika Anda perlu mengetahui izin yang diberikan

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 웃
sumber
1
Saya mendapatkan kesalahan di swift 2.3: UNUserNotificationCenter tidak memiliki anggota saat ini
Async-
Hay bisa Anda berikan save di objektif c
Ayaz
Sekadar catatan, tidak lagi mengembalikan token perangkat. Setidaknya dalam kasus saya itu hanya mengembalikan "32 byte"
Brian F Leighty
1
@ Async- Anda tidak melihat current () karena hanya bekerja di Swift 3.
Allen
4
@PavlosNicolaou Impor kerangka kerja 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
sumber
Apa manfaat tambahan dari kerangka baru ini? Apa yang saya lihat di sini adalah menggunakan 'completionHandler lebih delegasi' pendekatan dan kemudian pengambilan keputusan diberikan kepada Anda segera: kesalahan, diberikan, atau notGranted .... Dalam 6 <iOS <10 Anda harus melakukan application.isRegisteredForRemoteNotifications()untuk melihat apakah itu diberikan, dan gunakan metode delegasi lain jika Anda mengalami kesalahan. Baik? Ada yang lain?
Madu
mengapa jawaban Anda berbeda dari jawaban yang diterima? Dia memiliki application.registerForRemoteNotifications() setelah nyacenter.requestAuthorization
Madu
1
@Madu; Itu ditambahkan jika Anda ingin notifikasi "Remote" diaktifkan. Ketika saya menulis jawaban saya, tidak ada jawaban lain dan @OP tidak menentukan apakah mereka menginginkan dukungan jarak jauh atau lokal atau iOS 10 jadi saya menambahkan sebanyak yang saya bisa. Catatan: Anda tidak boleh mendaftar untuk RemoteNotifications hingga pengguna telah memberikan akses (jika tidak, semua notifikasi jarak jauh dikirim secara diam-diam [kecuali itu yang Anda inginkan] - tidak ada popup). Selain itu, keuntungan dari API baru ini adalah mendukung lampiran. Dengan kata lain, Anda dapat menambahkan GIF dan Gambar lainnya, Video, dll .. ke notifikasi Anda.
Brandon
3
Dalam penutupan, Anda harus melakukan tugas terkait UI di Utas Utama ... DispatchQueue.main.async {... lakukan hal-hal di sini ...}
Chris Allinson
1
Manfaat solusi ini ketika digunakan tidak di AppDelegate untuk melakukan hal yang sama dalam kode
Codenator81
27
import UserNotifications  

Selanjutnya, buka editor proyek untuk target Anda, dan di tab Umum, cari bagian Kerangka dan Perpustakaan Tertaut.

Klik + dan pilih 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])
}

Gunakan metode delegasi Pemberitahuan

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

Untuk menerima pemberitahuan push

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

Menyiapkan pemberitahuan push mengaktifkan fitur dalam Xcode 8 untuk aplikasi Anda. Cukup buka editor proyek untuk target Anda dan kemudian klik pada tab Capabilities . Cari Push Notifications dan alihkan nilainya ke ON .

Periksa tautan di bawah untuk mengetahui metode delegasi Notifikasi lainnya

Menangani Pemberitahuan Lokal dan Jarak Jauh UIApplicationDelegate - Menangani Pemberitahuan Lokal dan Jarak Jauh

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

Mohamed Jaleel Nazir
sumber
20

Saya memiliki masalah dengan jawaban di sini dalam mengonversi objek Data deviceToken ke string untuk dikirim ke server saya dengan beta Xcode 8 saat ini. Terutama yang menggunakan deviceToken.description seperti pada 8.0b6 yang akan mengembalikan "32 Bytes" yang mana tidak terlalu berguna :)

Inilah yang berhasil untuk saya ...

Buat ekstensi pada Data untuk menerapkan metode "hexString":

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

Dan kemudian gunakan itu ketika Anda menerima panggilan balik dari mendaftar untuk pemberitahuan jarak jauh:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenString = deviceToken.hexString()
    // Send to your server here...
}
tomwilson.dll
sumber
8
Saya juga mengalami masalah "32bytes". Solusi hebat, Anda dapat melakukan konversi in-line tanpa membuat ekstensi sekalipun. Seperti ini: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz
1
Tidak masuk akal bahwa tidak ada solusi yang berasal dari API itu sendiri
Aviel Gross
1
Ya itu selalu sangat aneh bahwa API .. terkejut mereka tidak memperbaikinya saat melakukan kerangka pemberitahuan baru di iOS10
tomwilson
17

Di iOS10 alih-alih kode Anda, Anda harus meminta otorisasi untuk pemberitahuan dengan yang berikut: (Jangan lupa untuk menambahkan UserNotificationsKerangka)

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

Selain itu, kode yang benar untuk Anda adalah (gunakan di elsekondisi sebelumnya, misalnya):

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

Terakhir, pastikan Push Notificationdiaktifkan di bawah target-> Capabilities-> Push notification. (nyalakan On)

tsnkff
sumber
1
lihat: Halaman 73 dari Apple Doc di sini
tsnkff
2
Terima kasih banyak atas jawabannya! Namun, menggunakan kode tersebut mengatakan "Penggunaan pengenal yang belum terselesaikan 'UNUserNotificationCenter'"
Asher Hawthorne
Dan terima kasih banyak atas dokumentasinya, blablabla! Saya tidak melihatnya di situs mereka, saya senang situs itu ada. : D
Asher Hawthorne
4
Tunggu, saya rasa saya mengerti! Hanya perlu mengimpor kerangka notifikasi. XD
Asher Hawthorne
1
Ya. Saya akan mengedit jawaban saya untuk menambahkan ini untuk pembaca selanjutnya. Juga, baca tentang pemberitahuan baru, sekarang ada cara yang lebih kuat dan interaktif. :)
tsnkff
8

Nah ini bekerja untuk saya. Pertama di AppDelegate

import UserNotifications

Kemudian:

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

Untuk mendapatkan token perangkat:

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

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

}
GoIn Su
sumber
5

Perhatian, Anda harus menggunakan utas utama untuk tindakan ini.

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

Pertama , dengarkan status pemberitahuan pengguna, misalnya, registerForRemoteNotifications()untuk mendapatkan token perangkat APN;
Kedua , minta otorisasi. Saat diberi otorisasi oleh pengguna, deviceToken akan dikirim ke pendengar, yang AppDelegate;
Ketiga , laporkan token perangkat ke server Anda.

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
sumber
bagaimana cara menambahkan beberapa notifikasi?
ArgaPK
@ArgaPK, Untuk mengirim pemberitahuan push adalah apa yang dilakukan platform server Anda.
DawnSong
0

Jawaban dari ast1 sangat sederhana dan bermanfaat. Ini berhasil untuk saya, terima kasih banyak. Saya hanya ingin menunjukkannya di sini, agar orang yang membutuhkan jawaban ini dapat menemukannya dengan mudah. Jadi, inilah kode saya dari mendaftar notifikasi lokal dan jarak jauh (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
sumber
0

Cukup lakukan hal berikut di didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

Ingat tentang pernyataan import:

import UserNotifications
Bartłomiej Semańczyk
sumber
Saya percaya ini harus menjadi jawaban yang diterima. Tampaknya benar untuk memanggil registerForRemoteNotifications()penangan penyelesaian requestAuthorization(). Anda bahkan mungkin ingin dikelilingi registerForRemoteNotifications()dengan if grantedpernyataan: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica
-1

Lihatlah kode yang dikomentari ini:

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

    }
}

Beri tahu saya jika ada masalah!

CrazyPro007
sumber