Search code examples
firebaseswiftuifirebase-cloud-messagingwatchkitapple-watch

Problem using FCM in an independent watchOS app


I have added Firebase Cloud Messaging to my independent watchOS app.

I am able to get a FCM token. When I send a push notification from Postman to the watch the response is success: 1, but I am not getting the notification on the watch.

  • The watch is connected to Wi-Fi and the iPhone.
  • I have added the necessary initialisation in AppDelegate.
  • I have created an APN key from Apple Developer website and added it to Firebase Cloud Messaging.
  • I have GoogleService-Info.plist in my Xcode target.
  • I have added background fetch and push notification capabilities to the target.
  • The bundle identifier is same as the GoogleService-Info.plist and the target.

Do I have to manually handle FCM notifications code? Where am I possibly wrong?

import SwiftUI
import Firebase

@main
struct Curiousfly_Watch_Watch_AppApp: App {
  @WKApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
  var body: some Scene {
    WindowGroup {
      AuthenticationView()
    }
  }
}

class AppDelegate: NSObject, WKApplicationDelegate, MessagingDelegate {
  func applicationDidFinishLaunching() {
    FirebaseApp.configure()
    let center = UNUserNotificationCenter.current()
    center.requrestAuthorization(options: [.alert, .sound] { granted, error in 
      if granted {
        WKExtension.shared().registerForRemoteNotification()
      }
    }
    Messaging.messaging().delegate = self
  }

  /// MessagingDelegate
  func messaging(_ messaging: Messaging, didRegisterForRemoteNotifications fcmToken: String?) {
    print("token: " + fcmToken!)
    Messaging.messaging().subscribe(toTopic: "watch") { error in
      if error != nil {
        print("error:" + error.debugDescription)
      }
      else {
        print("Successfully subscribed to topic")
      }
    }
  }
  
  /// WKExtensionDelegate
  func didRegisterForRemoteNotifications(withDeviceToken deviceToken: Data) {
    /// Swizzling should be disabled in Messaging for watchOS, set APNS token manually
    print("Set APNS Token\m")
    Messaging.messaging().apnsToken = deviceToken
  }
}

Solution

  • We had a look at your code, and it generally looks good. Note that you don't need to subscribe to a topic in order to receive FCM notifications, so you can remove the code for subscribing to a topic.

    To send FCM notifications to your independent watchOS app, register it in the Firebase console:

    1. Create a new iOS+ app, using the watchOS app's bundle identifier.
    2. Download the GoogleService-Info.plist file and add it to the independent watch app target.
    3. Skip the sample code (since this is for iOS apps) and use the one listed below to initialise Firebase on watchOS.

    For sending a test message to your independent watchOS app, follow these instructions in our documentation:

    1. Install and run the app on the target device. On your Apple watch, you'll need to accept the request for permission to receive remote notifications.
    2. Make sure the app is in the background on the device.
    3. In the Firebase console, open the Messaging page.
    4. If this is your first message, select Create your first campaign.
      1. Select Firebase Notification messages and select Create.
    5. Otherwise, on the Campaigns tab, select New campaign and then Notifications.
    6. Enter the message text. All other fields are optional.
    7. Select Send test message from the right pane.
    8. In the field labeled Add an FCM registration token, enter the registration token you generated from your watch app.
    9. Select Test.

    Note: Watch out in step 7: do not click on Next. Instead, click on the blue Send test message button on the right hand side of the screen.

    enter image description here

    We've added a sample app to the Firebase Apple SDK, here is the main part of the app for reference:

    import SwiftUI
    import Firebase
    
    @main
    struct SampleStandaloneWatchApp_Watch_AppApp: App {
      @WKApplicationDelegateAdaptor(FCMWatchAppDelegate.self) var appDelegate
      var body: some Scene {
        WindowGroup {
          ContentView()
        }
      }
    }
    
    // MARK: - WKApplicationDelegate
    class FCMWatchAppDelegate: NSObject, WKApplicationDelegate, MessagingDelegate {
      func applicationDidFinishLaunching() {
        FirebaseApp.configure()
        let notificationCenter = UNUserNotificationCenter.current()
        notificationCenter.requestAuthorization(options: [.alert, .sound]) { granted, error in
          if granted {
            WKApplication.shared().registerForRemoteNotifications()
          }
        }
        Messaging.messaging().delegate = self
      }
    
      func didRegisterForRemoteNotifications(withDeviceToken deviceToken: Data) {
        // Method swizzling should be disabled in Firebase Messaging on watchOS.
        // Set the APNS token manually as is done here.
        // More information on how to disable -
        // https://firebase.google.com/docs/cloud-messaging/ios/client#method_swizzling_in
        print("APNS didRegisterForRemoteNotifications. Got device token \(deviceToken)")
        Messaging.messaging().apnsToken = deviceToken
      }
    }
    
    // MARK: - FCM MessagingDelegate
    extension FCMWatchAppDelegate {
      func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        // Use this FCM token to test sending a push using API or Firebase Console
        print("FCM - didReceiveRegistrationToken \(String(describing: fcmToken))")
      }
    }