กำลังลงทะเบียนสำหรับการแจ้งเตือนแบบพุชใน Xcode 8 / Swift 3.0 หรือไม่


121

ฉันกำลังพยายามให้แอปทำงานในXcode 8.0และพบข้อผิดพลาด ฉันรู้ว่ารหัสนี้ใช้งานได้ดีในเวอร์ชันก่อนหน้าของ swift แต่ฉันสมมติว่ารหัสนี้มีการเปลี่ยนแปลงในเวอร์ชันใหม่ นี่คือรหัสที่ฉันพยายามเรียกใช้:

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

ข้อผิดพลาดที่ฉันได้รับคือ "ป้ายกำกับอาร์กิวเมนต์ '(forTypes :, หมวดหมู่ :)' ไม่ตรงกับการโอเวอร์โหลดใด ๆ ที่มีอยู่"

มีคำสั่งอื่นที่ฉันสามารถลองเพื่อให้มันใช้งานได้หรือไม่?


2
ฉันเขียนคำแนะนำเกี่ยวกับการทำเช่นนั้น: eladnava.com/…
Elad Nava

คำตอบ:


307

นำเข้าUserNotificationsกรอบและเพิ่มUNUserNotificationCenterDelegateใน AppDelegate.swift

ขออนุญาตผู้ใช้

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
}

รับโทเค็นอุปกรณ์

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

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

ในกรณีที่เกิดข้อผิดพลาด

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

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

ในกรณีที่คุณต้องการทราบสิทธิ์ที่ได้รับ

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
ฉันได้รับข้อผิดพลาดใน swift 2.3: UNUserNotificationCenter ไม่มีสมาชิกปัจจุบัน
Async-

Hay คุณสามารถให้การบันทึกตามวัตถุประสงค์ c
Ayaz

โปรดทราบว่าจะไม่ส่งคืนโทเค็นอุปกรณ์อีกต่อไป อย่างน้อยก็ในกรณีของฉันมันส่งกลับ "32 ไบต์" เท่านั้น
Brian F Leighty

1
@ Async- คุณไม่เห็นกระแส () เพราะใช้งานได้ใน Swift 3 เท่านั้น
Allen

4
@PavlosNicolaou นำเข้ากรอบการแจ้งเตือนผู้ใช้
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
}

ประโยชน์เพิ่มเติมของกรอบงานใหม่นี้คืออะไร? สิ่งที่ผมเห็นที่นี่เป็นวิธีการใช้ 'completionHandler มากกว่าผู้รับมอบสิทธิ์' และการตัดสินใจให้กับคุณได้ทันที: ข้อผิดพลาดที่ได้รับหรือ notGranted .... ใน 6 <iOS <10 ที่คุณต้องทำ application.isRegisteredForRemoteNotifications()เพื่อดูว่ามันเป็นได้รับอนุญาตและใช้วิธีการมอบหมายอื่นในกรณีที่คุณมีข้อผิดพลาด ขวา? มีอะไรอีกไหม
น้ำผึ้ง

ทำไมคำตอบของคุณถึงแตกต่างจากคำตอบที่ยอมรับ เขามีความapplication.registerForRemoteNotifications() หลังของเขาcenter.requestAuthorization
น้ำผึ้ง

1
@น้ำผึ้ง; ที่เพิ่มเข้ามาหากคุณต้องการเปิดใช้งานการแจ้งเตือน "ระยะไกล" เมื่อฉันเขียนคำตอบไม่มีคำตอบอื่นใดและ @OP ไม่ได้ระบุว่าพวกเขาต้องการการสนับสนุนจากระยะไกลหรือในพื้นที่หรือ iOS 10 ดังนั้นฉันจึงเพิ่มมากที่สุดเท่าที่จะทำได้ หมายเหตุ: คุณไม่ควรลงทะเบียนสำหรับ RemoteNotifications จนกว่าผู้ใช้จะให้สิทธิ์การเข้าถึง (มิฉะนั้นการแจ้งเตือนระยะไกลทั้งหมดจะถูกส่งแบบเงียบ ๆ [เว้นแต่นั่นคือสิ่งที่คุณต้องการ] - ไม่มีป๊อปอัป) นอกจากนี้ข้อดีของ API ใหม่คือรองรับไฟล์แนบ กล่าวคือคุณสามารถเพิ่ม GIF และรูปภาพวิดีโอและอื่น ๆ ในการแจ้งเตือนของคุณได้
Brandon

3
ในการปิดคุณจะต้องทำงานที่เกี่ยวข้องกับ UI ใน Main Thread ... DispatchQueue.main.async {... do stuff here ... }
Chris Allinson

1
ประโยชน์ของโซลูชันนี้เมื่อใช้ไม่ได้อยู่ใน AppDelegate เพื่อทำสิ่งเดียวกันในรหัส
Codenator81

27
import UserNotifications  

จากนั้นไปที่ตัวแก้ไขโครงการสำหรับเป้าหมายของคุณและในแท็บทั่วไปมองหาส่วนกรอบงานและไลบรารีที่เชื่อมโยง

คลิก + แล้วเลือก 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])
}

ใช้วิธีการมอบหมายการแจ้งเตือน

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

สำหรับการรับการแจ้งเตือนแบบพุช

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

การตั้งค่าการแจ้งเตือนแบบพุชกำลังเปิดใช้งานคุณสมบัติภายใน Xcode 8 สำหรับแอปของคุณ เพียงแค่ไปที่การแก้ไขโครงการสำหรับเป้าหมายของคุณและจากนั้นคลิกที่ความสามารถของแท็บ มองหาการแจ้งเตือนผลักดันและสลับค่าเป็นON

ตรวจสอบลิงค์ด้านล่างสำหรับวิธีการมอบหมายการแจ้งเตือนเพิ่มเติม

การจัดการการแจ้งเตือนในพื้นที่และระยะไกลUIApplicationDelegate - การจัดการการแจ้งเตือนภายในและระยะไกล

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


20

ฉันมีปัญหากับคำตอบที่นี่ในการแปลงอ็อบเจ็กต์ deviceToken Data เป็นสตริงเพื่อส่งไปยังเซิร์ฟเวอร์ของฉันด้วยเบต้าปัจจุบันของ Xcode 8 โดยเฉพาะอย่างยิ่งที่ใช้ deviceToken.description เช่นเดียวกับใน 8.0b6 ที่จะส่งคืน "32 ไบต์" ซึ่ง ไม่มีประโยชน์มากนัก :)

นี่คือสิ่งที่ได้ผลสำหรับฉัน ...

สร้างส่วนขยายบน Data เพื่อใช้เมธอด "hexString":

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

จากนั้นใช้เมื่อคุณได้รับการติดต่อกลับจากการลงทะเบียนสำหรับการแจ้งเตือนระยะไกล:

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

8
ฉันยังมีปัญหา "32 ไบต์" วิธีแก้ปัญหาที่ยอดเยี่ยมคุณสามารถทำการแปลงในบรรทัดได้โดยไม่ต้องสร้างส่วนขยาย ดังนี้ let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz

1
ไร้สาระว่าไม่มีโซลูชันใดที่มาจากตัว API
Aviel Gross

1
ใช่แล้วมันค่อนข้างแปลกที่ API .. แปลกใจที่พวกเขาไม่ได้แก้ไขเมื่อทำกรอบการแจ้งเตือนใหม่ใน iOS10
tomwilson

17

ใน iOS10 แทนรหัสของคุณคุณควรขอการอนุญาตสำหรับการแจ้งเตือนดังต่อไปนี้: (อย่าลืมเพิ่มUserNotificationsFramework)

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

นอกจากนี้รหัสที่ถูกต้องสำหรับคุณคือ (ใช้ในelseเงื่อนไขก่อนหน้านี้เป็นต้น):

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

สุดท้ายให้แน่ใจว่าPush Notificationจะเปิดใช้งานภายใต้target-> ->Capabilities Push notification(ตั้งค่าไว้On)


1
ดู: หน้า 73 ของApple Doc ที่นี่
tsnkff

2
ขอบคุณมากสำหรับการตอบกลับ! อย่างไรก็ตามการใช้รหัสระบุว่า "Use of unresolved identifier 'UNUserNotificationCenter'"
Asher Hawthorne

และขอบคุณมากสำหรับเอกสาร blablabla! ฉันไม่เห็นสิ่งนั้นในไซต์ของพวกเขาฉันดีใจที่มีอยู่ : D
Asher Hawthorne

4
เดี๋ยวก่อนฉันคิดว่าฉันเข้าใจแล้ว! ต้องนำเข้ากรอบการแจ้งเตือน XD
Asher Hawthorne

1
อ๋อ ฉันจะแก้ไขคำตอบเพื่อเพิ่มสิ่งนี้สำหรับผู้อ่านในอนาคต นอกจากนี้โปรดอ่านเกี่ยวกับการแจ้งเตือนใหม่ขณะนี้มีวิธีที่มีประสิทธิภาพและโต้ตอบได้มากกว่า :)
tsnkff

8

งานนี้สำหรับฉัน อันดับแรกใน AppDelegate

import UserNotifications

แล้ว:

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

ในการรับอุปกรณ์:

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

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

}

5

โปรดทราบว่าคุณควรใช้เธรดหลักสำหรับการดำเนินการนี้

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

2

ขั้นแรกให้ฟังสถานะการแจ้งเตือนของผู้ใช้เช่นregisterForRemoteNotifications()เพื่อรับโทเค็นอุปกรณ์ APN
ประการที่สองขอการอนุญาต เมื่อได้รับอนุญาตจากผู้ใช้ deviceToken จะถูกส่งไปยังผู้ฟังซึ่งAppDelegate;
ประการที่สามรายงานโทเค็นอุปกรณ์ไปยังเซิร์ฟเวอร์ของคุณ

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

จะเพิ่มการแจ้งเตือนหลายรายการได้อย่างไร?
ArgaPK

@ArgaPK ในการส่งการแจ้งเตือนแบบพุชคือสิ่งที่แพลตฟอร์มเซิร์ฟเวอร์ของคุณทำ
DawnSong

0

คำตอบจากast1นั้นง่ายและมีประโยชน์มาก มันได้ผลสำหรับฉันขอบคุณมาก ฉันแค่อยากจะชี้ให้เห็นตรงนี้เพื่อให้คนที่ต้องการคำตอบนี้หาคำตอบได้ง่าย ดังนั้นนี่คือรหัสของฉันจากการลงทะเบียนการแจ้งเตือนในพื้นที่และระยะไกล (พุช)

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

เพียงทำสิ่งต่อไปนี้ในdidFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

ข้อควรจำเกี่ยวกับคำสั่งนำเข้า:

import UserNotifications

ฉันเชื่อว่านี่ควรเป็นคำตอบที่ได้รับการยอมรับ ดูเหมือนว่าที่ถูกต้องที่จะเรียกในความสำเร็จของการจัดการregisterForRemoteNotifications() requestAuthorization()คุณอาจต้องการล้อมรอบregisterForRemoteNotifications()ด้วยif grantedคำสั่ง: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica

-1

ดูรหัสที่แสดงความคิดเห็นนี้:

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

    }
}

แจ้งให้เราทราบหากมีปัญหาใด ๆ !

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.