Đăng ký Thông báo đẩy trong Xcode 8 / Swift 3.0?


121

Tôi đang cố gắng làm cho ứng dụng của mình hoạt động trong Xcode 8.0 và đang gặp lỗi. Tôi biết mã này hoạt động tốt trong các phiên bản trước của swift, nhưng tôi cho rằng mã này đã được thay đổi trong phiên bản mới. Đây là mã tôi đang cố chạy:

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

Lỗi mà tôi gặp phải là "Nhãn đối số" (forTypes :, category :) 'không khớp với bất kỳ quá tải nào có sẵn "

Có một lệnh khác mà tôi có thể thử làm cho nó hoạt động không?


2
Tôi đã viết một hướng dẫn về cách làm việc đó: eladnava.com/...
Elad Nava

Câu trả lời:


307

Nhập UserNotificationskhung và thêm UNUserNotificationCenterDelegatevào AppDelegate.swift

Yêu cầu quyền người dùng

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
}

Nhận mã thông báo thiết bị

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

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

Trong trường hợp lỗi

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

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

Trong trường hợp nếu bạn cần biết các quyền được cấp

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
Tôi gặp lỗi trong phiên bản 2.3 nhanh: UNUserNotificationCenter không có thành viên hiện tại
Async-

Hay bạn có thể cung cấp tiết kiệm tại khách quan c
Ayaz

Chỉ cần một ghi chú, không còn trả lại mã thông báo thiết bị. Ít nhất là trong trường hợp của tôi nó chỉ trả về "32 byte"
Brian F Leighty

1
@ Async- Bạn không thấy hiện tại () vì nó chỉ hoạt động trong Swift 3.
Allen

4
@PavlosNicolaou Nhập khuôn khổ Thông báo Người dùng
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
}

Lợi ích bổ sung của khuôn khổ mới này là gì? Những gì tôi thấy ở đây là một phương pháp sử dụng 'completionHandler qua đại biểu' và sau đó đưa ra quyết định được đưa ra cho bạn ngay lập tức: lỗi, cấp, hoặc notGranted .... Trong 6 <iOS <10 bạn phải làm application.isRegisteredForRemoteNotifications()để xem nếu nó là được cấp và sử dụng một phương thức ủy quyền khác trong trường hợp bạn gặp lỗi. Đúng? Còn gì nữa không?
Honey,

tại sao câu trả lời của bạn khác với câu trả lời được chấp nhận? Ông có một application.registerForRemoteNotifications() sau mìnhcenter.requestAuthorization
Mật ong

1
@Mật ong; Điều đó được thêm vào nếu bạn muốn bật thông báo "Từ xa". Khi tôi viết câu trả lời của mình, không có câu trả lời nào khác tồn tại và @OP không chỉ định liệu họ muốn hỗ trợ từ xa hay cục bộ hoặc iOS 10, vì vậy tôi đã thêm nhiều nhất có thể. Lưu ý: Bạn không nên đăng ký Thông báo từ xa cho đến khi người dùng đã cấp quyền truy cập (nếu không, tất cả thông báo từ xa sẽ được gửi âm thầm [trừ khi đó là những gì bạn muốn] - không có cửa sổ bật lên). Ngoài ra, lợi thế của API mới là nó hỗ trợ các tệp đính kèm. Nói cách khác, bạn có thể thêm GIF và các Hình ảnh, Video khác, v.v. vào thông báo của mình.
Brandon

3
Trong việc đóng cửa, bạn sẽ cần phải thực hiện nhiệm vụ giao diện người dùng liên quan trên chủ đề chính ... DispatchQueue.main.async {... làm công cụ ở đây ...}
Chris Allinson

1
Lợi ích của giải pháp này khi sử dụng không appdelegate để làm điều tương tự trong mã
Codenator81

27
import UserNotifications  

Tiếp theo, đi tới trình chỉnh sửa dự án cho mục tiêu của bạn và trong tab Chung, tìm phần Thư viện và Khung được Liên kết.

Nhấp vào + và chọn 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])
}

Sử dụng phương pháp ủy quyền thông báo

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

Để nhận thông báo đẩy

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

Thiết lập thông báo đẩy đang bật tính năng trong Xcode 8 cho ứng dụng của bạn. Chỉ cần đi tới trình chỉnh sửa dự án cho mục tiêu của bạn và sau đó nhấp vào tab Khả năng . Tìm Thông báo đẩy và chuyển giá trị của nó thành BẬT .

Kiểm tra liên kết bên dưới để biết thêm các phương pháp ủy quyền Thông báo

Xử lý thông báo cục bộ và từ xa UIApplicationDelegate - Xử lý thông báo cục bộ và từ xa

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


20

Tôi đã gặp vấn đề với câu trả lời ở đây trong việc chuyển đổi đối tượng Dữ liệu deviceToken thành một chuỗi để gửi đến máy chủ của tôi với bản beta hiện tại của Xcode 8. Đặc biệt là bản đang sử dụng deviceToken.description như trong 8.0b6 sẽ trả về "32 Byte" không hữu ích lắm :)

Đây là những gì làm việc cho tôi...

Tạo tiện ích mở rộng trên Dữ liệu để triển khai phương thức "hexString":

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

Và sau đó sử dụng nó khi bạn nhận được cuộc gọi lại từ việc đăng ký thông báo từ xa:

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

8
Tôi cũng gặp sự cố "32byte". Giải pháp tuyệt vời, bạn có thể thực hiện chuyển đổi trong dòng mà không cần tạo tiện ích mở rộng. Như thế này: let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz,

1
Vô lý rằng không có giải pháp đến từ các API chính nó
Aviel Gross

1
Vâng nó luôn luôn là khá kỳ lạ rằng API .. ngạc nhiên họ không sửa chữa nó khi thực hiện khuôn khổ thông báo mới trong iOS10
tomwilson

17

Trong iOS10 thay vì mã của bạn, bạn nên yêu cầu ủy quyền thông báo với những điều sau: (Đừng quên thêm UserNotificationsKhung)

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

Ngoài ra, mã chính xác cho bạn là ( elseví dụ: sử dụng trong điều kiện trước đó):

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

Cuối cùng, đảm bảo đã Push Notificationđược kích hoạt trong target-> Capabilities-> Push notification. (bật nó lên On)


1
xem: Trang 73 của Tài liệu Apple tại đây
tsnkff

2
Cảm ơn bạn rất nhiều vì đã trả lời! Sử dụng mã này, tuy nhiên, nó đang nói "Việc sử dụng định danh chưa được giải quyết 'UNUserNotificationCenter'"
Asher Hawthorne

Và cảm ơn bạn rất nhiều về tài liệu, blablabla! Tôi không thấy điều đó trên trang web của họ, tôi rất vui vì nó tồn tại. : D
Asher Hawthorne

4
Chờ đã, tôi nghĩ tôi hiểu rồi! Chỉ cần nhập khung thông báo. XD
Asher Hawthorne

1
Vâng. Tôi sẽ chỉnh sửa câu trả lời của mình để thêm điều này cho người đọc trong tương lai. Ngoài ra, hãy đọc về các thông báo mới, có nhiều cách mạnh mẽ và tương tác hơn bây giờ. :)
tsnkff

8

Vâng, công việc này cho tôi. Đầu tiên trong AppDelegate

import UserNotifications

Sau đó:

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

Để tải devicetoken:

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

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

}

5

Lưu ý, bạn nên sử dụng chuỗi chính cho hành động này.

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

2

Đầu tiên , hãy lắng nghe trạng thái thông báo của người dùng, tức là registerForRemoteNotifications()để nhận mã thông báo thiết bị APN;
Thứ hai , yêu cầu ủy quyền. Khi được ủy quyền của người sử dụng, deviceToken sẽ được gửi đến người nghe, các AppDelegate;
Thứ ba , báo cáo mã thông báo thiết bị cho máy chủ của bạn.

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

làm thế nào để thêm nhiều thông báo?
ArgaPK

@ArgaPK, Để gửi thông báo đẩy là những gì nền tảng máy chủ của bạn thực hiện.
DawnSong

0

Câu trả lời từ ast1 rất đơn giản và hữu ích. Nó làm việc cho tôi, cảm ơn bạn rất nhiều. Tôi chỉ muốn nêu ra ở đây, vì vậy những người cần câu trả lời này có thể tìm thấy nó một cách dễ dàng. Vì vậy, đây là mã của tôi từ việc đăng ký thông báo cục bộ và từ xa (đẩy).

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

Chỉ cần làm như sau trong didFinishWithLaunching::

if #available(iOS 10.0, *) {

    let center = UNUserNotificationCenter.current()

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

Hãy nhớ về câu lệnh nhập:

import UserNotifications

Tôi tin rằng đây phải là câu trả lời được chấp nhận. Có vẻ đúng khi gọi registerForRemoteNotifications()trong trình xử lý hoàn thành của requestAuthorization(). Bạn thậm chí có thể muốn bao quanh registerForRemoteNotifications()với một if grantedtuyên bố: center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in if granted { UIApplication.shared.registerForRemoteNotifications() } }
Bocaxica

-1

Hãy xem mã nhận xét này:

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

    }
}

Hãy cho tôi biết nếu có bất kỳ vấn đề!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.