FCM in React Native

關於FCM與React Native

FCM是Firebase Cloud Messaging的縮寫,是Google用以取代GCM的服務。

之前在開發React Native的App的時候,一開始以為要將Push Notification取得的Token送到FCM,但試了幾次總是得到invalid token的訊息,因為從React Native內建的PushNotificationIOS,或者是react-native-push-notification套件中取得的token都不是FCM要的。

其實Google有針對IOS的開發者提供Cocoapods,React Native也有相對應的套件:react-native-fcm。react-native-fcm的官方文件其實也的很清楚,不過對於Cocoapods不熟悉的開發者,特別是從網頁開發轉到React Native的人來說,按照官方文件的安裝步驟很有可能出錯。APNs的憑證一樣從Apple Developer中申請下載,然後安裝到FCM的專案中,剩下的就由FCM接手處理。

安裝步驟

以下記錄我的設定流程(IOS),主要依據官方文件上的流程:

  1. npm install react-native-fcm –save // 安裝react-native-fcm
  2. react-native link react-native-fcm // 連結IOS、Android
  3. 安裝Cocoapods
  4. 在專案的ios目錄下新建一個pod檔: pod init
  5. 在上一步的指令中產生的Podfile,加入以下設定:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    target 'firep' do
    # Uncomment this line if you're using Swift or would like to use dynamic frameworks
    use_frameworks!
    # Pods for firep
    pod 'Firebase/Messaging'
    pod 'FirebaseAnalytics'
    pod 'Firebase/Core'
    target 'firepTests' do
    inherit! :search_paths
    # Pods for testing
    pod 'Firebase/Messaging'
    pod 'FirebaseAnalytics'
    pod 'Firebase/Core'
    end
    end
  6. 特別注意use_frameworks!不能被註解掉

  7. pod install // 安裝上述套件
  8. 開啟ios目錄下的AppDelegate.h檔,加入:

    1
    2
    3
    @import Firebase;
    @import UserNotifications;
    @interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
  9. 注意第8點@interface AppDelegate : UIResponder這一行是被取代而不是新建。

  10. 在AppDelegate.m檔加入(加在@implementation AppDelegate與@end之間):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    [FIRApp configure];
    #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
    #endif
    #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
    {
    [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:notification.request.content.userInfo];
    if([[notification.request.content.userInfo valueForKey:@"show_in_foreground"] isEqual:@YES]){
    completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
    }else{
    completionHandler(UNNotificationPresentationOptionNone);
    }
    }
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
    {
    NSDictionary* userInfo = [[NSMutableDictionary alloc] initWithDictionary: response.notification.request.content.userInfo];
    [userInfo setValue:@YES forKey:@"opened_from_tray"];
    [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:userInfo];
    }
    #else
    //You can skip this method if you don't want to use local notification
    -(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self + userInfo:notification.userInfo];
    }
    #endif
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
    [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:userInfo];
    completionHandler(UIBackgroundFetchResultNoData);
    }
  11. 目前為止專案這邊的設定結束,到firebase的官網中建立新的FCM專案。要注意的是APNs的憑證還是要申請,然後安裝到Firebase中。在FCM中取得的GoogleService-Info.plist下載下來,透過Xcode安裝到React Native的IOS專案中。不能單純的將GoogleService-Info.plist放到IOS專案的資料夾,這樣IOS專案無法認得這個檔案,一定要透過Xcode來安裝。安裝的方式可以用開啟或者拖拉的方式將檔案拉進專案。

注意事項

因為Cocoapods的關係,開啟IOS專案不再是開啟AwesomeProject.xcodeproj,而是AwesomeProject.xcworkspace。如果開啟xcodeproj會發生找不到套件的錯誤,也無法繼續開發下去。某些部落格會告訴你必須依照React Native官方的PushNotificationIOS的套件安裝方式,其實透過react-native-fcm根本不需要這個步奏。即便是Local Push Notification也不需要,因為react-native-fcm也提供了對應的api。

使用方法官方文件已經非常清楚明暸,特別注意的是local push notification方面,react-native-fcm有自己的版本,別跟其他的混著用。