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 :, categories :)'가 사용 가능한 오버로드와 일치하지 않습니다."입니다.

이 작업을 수행 할 수있는 다른 명령이 있습니까?


2
: 난 그냥 그 수행하는 방법에 대한 가이드 썼다 eladnava.com/...
Elad 나바

답변:


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
나는 빠른 2.3에서 오류가 발생합니다 : UNUserNotificationCenter에는 회원 전류가 없습니다
Async-

헤이 당신은 목표 C에서 저장를 제공 할 수 있습니다
AYAZ

참고로 더 이상 장치 토큰을 반환하지 않습니다. 적어도 제 경우에는 "32 바이트"만 반환합니다.
Brian F Leighty

1
@ Async- Swift 3에서만 작동하기 때문에 current ()가 표시되지 않습니다.
Allen

4
@PavlosNicolaou 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
}

이 새로운 프레임 워크의 추가 이점은 무엇입니까? 내가 여기에서 보는 것은 사용 'completionHandler 위임을 통해'접근 방식이다 후 의사 결정은 바로 당신에게 주어집니다 : 오류, 부여, 또는 notGranted .... 6 <아이폰 OS <10 당신이해야 할 일을했을 application.isRegisteredForRemoteNotifications()이 있는지 확인 권리? 다른 건 없나요?
Honey

귀하의 답변이 허용 된 답변과 다른 이유는 무엇입니까? 그는 그의 application.registerForRemoteNotifications() 애프터center.requestAuthorization
Honey

1
@꿀; "원격"알림을 사용하려는 경우 추가됩니다. 내 답변을 작성할 때 다른 답변이 없었고 @OP는 원격 또는 로컬 또는 iOS 10 지원을 원하는지 여부를 지정하지 않았으므로 가능한 한 많이 추가했습니다. 참고 : 사용자가 액세스 권한을 부여 할 때까지 RemoteNotifications에 등록해서는 안됩니다 (그렇지 않으면 모든 원격 알림이 [원하는 것이 아닌 경우] 팝업이 표시되지 않는 한). 또한 새 API의 장점은 첨부 파일을 지원한다는 것입니다. 즉, 알림에 GIF 및 기타 이미지, 동영상 등을 추가 할 수 있습니다.
Brandon

3
마지막으로 메인 스레드에서 UI 관련 작업을 수행해야합니다 ... DispatchQueue.main.async {... 여기서 작업을 수행합니다 ...}
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 데이터 개체를 Xcode 8의 현재 베타 버전으로 서버에 보낼 문자열로 변환하는 데 문제가있었습니다. 특히 8.0b6에서 "32 바이트"를 반환하는 deviceToken.description을 사용하는 경우 별로 유용하지 않습니다 :)

이것은 나를 위해 일한 것입니다 ...

"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
나는 또한 "32bytes"문제가 있었다. 훌륭한 솔루션은 확장 프로그램을 만들지 않고도 인라인으로 변환 할 수 있습니다. 다음과 같이 : let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
Alain Stulz

1
API 자체에서 오는 솔루션이 없다는 것은 터무니없는
Aviel Gross

1
네, API는 항상 이상했습니다. iOS10에서 새로운 알림 프레임 워크를 수행 할 때 수정하지 않았다는 것에 놀랐습니다
tomwilson

17

코드 대신 iOS10에서 다음과 같은 알림에 대한 승인을 요청해야합니다. ( UserNotifications프레임 워크 를 추가하는 것을 잊지 마세요 )

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에서 활성화되어 있는지 확인하십시오 . (설정 )targetCapabilitiesPush notificationOn


1
다음을 참조하십시오 페이지 73 애플 문서를 여기
tsnkff

2
답장을 보내 주셔서 감사합니다! 코드를 사용하여, 그러나, "해결되지 않은 식별자 'UNUserNotificationCenter'의 사용"말하고
아셀 호손

그리고 문서화 해주셔서 감사합니다, blablabla! 나는 그들의 사이트에서 그것을 보지 못했지만 그것이 존재한다는 것이 기쁩니다. : D
아셀 호손

4
잠깐, 내가 잡은 것 같아! 알림 프레임 워크를 가져 오기만하면됩니다. XD
아셀 호손

1
네. 나는 미래의 독자를 위해 이것을 추가하기 위해 내 대답을 편집 할 것입니다. 또한 새로운 알림에 대해 읽으십시오. 이제 더 강력하고 상호 작용하는 방법이 있습니다. :)
tsnkff

8

이것은 나를 위해 일합니다. AppDelegate에서 1 위

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

devicetoken을 얻으려면 :

  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 문에 대해 기억하십시오.

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.