【问题标题】:How to show an alert and play sound when receiving notification in background在后台收到通知时如何显示警报和播放声音
【发布时间】:2018-08-01 09:28:30
【问题描述】:

为了使用 Firebase 云消息服务,我实施了这些程序。 我设置了

FirebaseAppDelegateProxyEnabled 为 NO(swizzling 已禁用)

因为我想通过使用结构“data”而不是“notification”结构来自定义发送到设备的消息。 我可以从调试输出中看到,在这个回调中收到了一条消息:

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

// With swizzling disabled you must let Messaging know about the message, for Analytics
        Messaging.messaging().appDidReceiveMessage(userInfo)
            // Print message ID.
            if let messageID = userInfo[gcmMessageIDKey] {
                print("Message ID: \(messageID)")

        }

    // Print full message.
    print(userInfo)


    // I want to play a sound
    // create a sound ID, in this case its the SMSReceived sound.
    let systemSoundID: SystemSoundID = 1007 // file:// /System/Library/Audio/UISounds/sms-received1.caf
    // to play sound
    AudioServicesPlaySystemSound(systemSoundID)
    if let title = userInfo["title"] as? NSString {

          let myalert = MyAlert(title: "New message received!", message: title as String, preferredStyle: UIAlertControllerStyle.alert)

          myalert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
          myalert.addAction(UIAlertAction(title: "Open app", style: .default, handler: { _ in
          print("The \"OK\" alert occured.")
          }))
          self.window?.rootViewController?.present(myalert, animated: true, completion: nil)

    }// END if let title = alert["title"]

    completionHandler(UIBackgroundFetchResult.newData)
}

在两种情况下(前后)都会加注。 前台一切正常,但后台没有声音和警报。 我很确定我错过了一些东西,但我不明白什么......也许我需要操作系统的一些“授权”来显示、提醒和播放声音?


编辑 1: 我实现了 UNUserNotificationCenterDelegate 来请求授权:

func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        FirebaseApp.configure()

        // [START set_messaging_delegate]
        Messaging.messaging().delegate = self
        // [END set_messaging_delegate]
        // Register for remote notifications. This shows a permission dialog on first run, to
        // show the dialog at a more appropriate time move this registration accordingly.
        // [START register_for_notifications]
        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()

        // [END register_for_notifications]

        if launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] != nil {
            // show alert
            let myalert = MyAlert(title: "New message!", message: "MyApp" as String, preferredStyle: UIAlertControllerStyle.alert)

            myalert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
            myalert.addAction(UIAlertAction(title: "Open MyApp", style: .default, handler: { _ in
                print("The \"OK\" alert occured.")
            }))
            self.window?.rootViewController?.present(myalert, animated: true, completion: nil)
        }


        return true
    }

【问题讨论】:

  • 1.你不需要这样的cmets。这很明显。 2.您基本上需要请求许可。请参阅here,然后决定在通知到达时显示什么。见here。我不确定您为什么不使用内置系统来显示警报和声音。为什么要创建自己的警报?!
  • 谢谢@Honey 的回答,我已经这样做了,你可以在 EDIT 1 中阅读......
  • @Honey 我没有回答你关于我为什么不创建内置系统(通知结构)的问题。只是因为当应用程序在后台时我无法播放声音!
  • "应用在后台时无法播放声音!"谁说的。如果我没记错的话,您可以创建一个推送通知并将声音包含到其有效负载中+将声音文件添加到应用程序包中。见here。(我删除了我之前的评论。这是不正确的)。如果您需要将声音放在前台,那么您的 wilPresentNotification 中也必须有 completionHandler([.alert, .sound])。见this tutorial

标签: ios swift notifications firebase-cloud-messaging


【解决方案1】:

已解决! 我使用了带有“通知”结构的内置系统,启用了 swizzling(FirebaseAppDelegateProxyEnabled = YES in info.plist),这是我创建的 json 消息:

{
"message":
     {
          "topic":"topic",
          "notification":
               {
                    "body":"body",
                    "title":"title"
               },
          "apns":
               {
                    "payload":
                         {
                              "aps":
                                   {
                                        "sound":"default"
                                   }
                         }
               }
     }
}

这是我使用的 AppDelegate.swift 类...

import UIKit
import StoreKit
import UserNotifications
import Firebase
import AVFoundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate,MessagingDelegate {



var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    self.registerForRemoteNotification()

    //Firebase initialization
    FirebaseApp.configure()
    // To receive registration tokens on app start we need to implement the messaging delegate protocol in
    // a class and provide it to the delegate property after calling FirebaseApp.Configure
    Messaging.messaging().delegate = self

    let token = Messaging.messaging().fcmToken
    print("FCM TOKEN = \(String(describing: token))")

    if let remote = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification]  as? [AnyHashable : Any] {
        self.sendToNewsPage()
    }

    return true
}

func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
    //
    print("Application didRegister notificationSettings")
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Disable swizzling, explicitly map the APNs token to the FCM registration token.
    //Messaging.messaging().apnsToken = deviceToken
    Messaging.messaging().subscribe(toTopic: "topic")
    print("Subcribed to topic")
}

func applicationWillResignActive(_ application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}

func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

func applicationWillEnterForeground(_ application: UIApplication) {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}

func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

// MARK: Remote Notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
    #if DEBUG
        print(userInfo)
    #endif

    let state: UIApplicationState = UIApplication.shared.applicationState
      if state == .active {
        // create a sound ID, in this case its the SMSReceived sound.
        let systemSoundID: SystemSoundID = 1007
        // to play sound
        AudioServicesPlaySystemSound(systemSoundID)

        if let aps = userInfo["aps"] as? NSDictionary {
            if let alert = aps["alert"] as? NSDictionary {
                if let title = alert["title"] as? NSString {

                    let myalert = MyAlert(title: "New message received!", message: title as String, preferredStyle: UIAlertControllerStyle.alert)

                    myalert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
                    myalert.addAction(UIAlertAction(title: "Open ViewController", style: .default, handler: { _ in
                        print("The \"OK\" alert occured.")
                        self.sendToNewsPage()
                    }))
                    self.window?.rootViewController?.present(myalert, animated: true, completion: nil)

                }// END if let title = alert["title"]
            }// END if let alert = aps["alert"]
        }// END if let aps = userInfo["aps"]
    }// END else if state == .active
      else {
            self.sendToNewsPage()
    }
}

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {

    print("Firebase NEW registration token: \(fcmToken)")
    // Note: This callback is fired at each app startup and whenever a new token is generated.

}

func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
    print("Firebase registration token REFRESH: \(fcmToken)")

}

func registerForRemoteNotification()  {
    let application:UIApplication = UIApplication.shared

    if #available(iOS 10.0, *) {
        // For iOS 10 display notification (sent via APNS)
        UNUserNotificationCenter.current().delegate = self

        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: {_, _ in })
    } else {
        let settings: UIUserNotificationSettings =
            UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
        application.registerUserNotificationSettings(settings)
    }

    application.registerForRemoteNotifications()

}

    // We need to implement this code only if swizzling id disabled - (FirebaseAppDelegateProxyEnabled = NO)
//    @available(iOS 10.0, *)
//    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
//
//        completionHandler([.alert, .badge, .sound])
//    }
//
//    @available(iOS 10.0, *)
//    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
//
//        completionHandler()
//    }



//MARK : Notification

func sendToNewsPage() {
    let newsMessage = UIStoryboard(name: "MenuInfo", bundle: nil).instantiateViewController(withIdentifier: "SWRevealViewController")
    self.window?.rootViewController  = newsMessage
}

}

这个 json 让通知在后台播放声音!

【讨论】:

    猜你喜欢
    • 2016-09-27
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 2010-11-05
    • 1970-01-01
    相关资源
    最近更新 更多