# Receive Push Messages

The iOS SDK can receive push messages through FCM (which uses APNs). To set up a Firebase Project to user FCM, refer to the [FCM iOS documentation](https://firebase.google.com/docs/cloud-messaging/ios/client) and follow it completely. Make sure to also [configure APNs with FCM](https://firebase.google.com/docs/cloud-messaging/ios/certs).

Once you have done that, add your `GoogleService-Info.plist` to the root of your xcode project.

To register your FCM token with Mitter, do the following:

```
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    print("APNs token retrieved: \(deviceToken.base64EncodedString())")

    InstanceID.instanceID().instanceID { (result, error) in
        if let error = error {
            print("Error fetching remote instange ID: \(error)")
        } else if let result = result {
            print("Remote instance ID token: \(result.token)")

            self.mitter.registerFcmToken(token: result.token) {
                result in
                switch result {
                case .success(let deliveryEndpoint):
                    print("Endpoint is: \(deliveryEndpoint.serializedEndpoint)")
                case .error:
                    print("Unable to register endpoint!")
                }
            }
        }
    }

    // With swizzling disabled you must set the APNs token here.
    // Messaging.messaging().apnsToken = deviceToken
}
```

To receive Messages when the app is in the background and then add it into the Channel view, do the following:

```
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

    // Receive displayed notifications for iOS 10 devices.
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        let messageString = userInfo["data"] as! String
        let messagingPipelinePayload = mitter.parseFcmMessage(data: messageString)

        processFcmMessage(pipelinePayload: messagingPipelinePayload)

        // Change this to your preferred presentation option
        completionHandler([])
    }
}
```

To receive messages directly from FCM (and not via APNs push), do the following:

```
extension AppDelegate : MessagingDelegate {
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")

        let dataDict:[String: String] = ["token": fcmToken]
        NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }
    // [END refresh_token]
    // [START ios_10_data_message]
    // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
    // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
        let messagingPipelinePayload = mitter.parseFcmMessage(data: remoteMessage.appData["data"] as! String)
        processFcmMessage(pipelinePayload: messagingPipelinePayload)
    }
    // [END ios_10_data_message]
}
```

Here is the function (used in the above snippets) that will add the parsed FCM message into the Channel View. Add it to your `AppDelegate`. Refer to the upcoming sections on the structure of the storyboard and `ChannelWindowViewController`:

```
func processFcmMessage(pipelinePayload: MessagingPipelinePayload?) {
    if mitter.isMitterMessage(pipelinePayload) {
        let payload = mitter.processPushMessage(pipelinePayload!)

        switch payload {
            // Handle the new message payload: Add it to the Channel Window View Controller
            case .NewMessagePayload(let message, let channelId):
                if let navController = window?.rootViewController as? UINavigationController {
                    // Get the second controller, which is the ChannelWindowViewController according to the storyboard
                    if let channelWindowViewController = navController.viewControllers[1] as? ChannelWindowViewController {
                        channelWindowViewController.newMessage(channelId: channelId.domainId, message: message)
                    }
                }
            // Ignore all other payloads
            default:
                print("Nothing to print!")
        }
    }
}
```
