README.md 8.26 KB
Newer Older
Libin Lu's avatar
Libin Lu committed
1 2
[![Join the chat at https://gitter.im/evollu/react-native-fcm](https://badges.gitter.im/evollu/react-native-fcm.svg)](https://gitter.im/evollu/react-native-fcm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Libin Lu's avatar
init  
Libin Lu committed
3 4 5
## Installation

- Run `npm install react-native-fcm --save`
6
- Run `react-native link react-native-fcm` (RN 0.29.1+, otherwise `rnpm link react-native-fcm`)
Libin Lu's avatar
init  
Libin Lu committed
7

8
## Android Configuration
Libin Lu's avatar
init  
Libin Lu committed
9

10 11 12 13 14
- Edit `android/build.gradle`:
```diff
  dependencies {
    classpath 'com.android.tools.build:gradle:2.0.0'
+   classpath 'com.google.gms:google-services:3.0.0'
Libin Lu's avatar
init  
Libin Lu committed
15 16
```

17 18 19 20
- Edit `android/app/build.gradle`:
```diff
  apply plugin: "com.android.application"
+ apply plugin: 'com.google.gms.google-services'
Libin Lu's avatar
init  
Libin Lu committed
21 22
```

23
- Edit `android/app/src/main/AndroidManifest.xml`:
Libin Lu's avatar
init  
Libin Lu committed
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
```diff
  <application
    ...
    android:theme="@style/AppTheme">

+   <service android:name="com.evollu.react.fcm.MessagingService">
+     <intent-filter>
+       <action android:name="com.google.firebase.MESSAGING_EVENT"/>
+     </intent-filter>
+   </service>

+   <service android:name="com.evollu.react.fcm.InstanceIdService" android:exported="false">
+     <intent-filter>
+       <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
+     </intent-filter>
+   </service>

    ...
Libin Lu's avatar
init  
Libin Lu committed
43
```
44

45
### Config for notification and `click_action` in Android
46 47 48 49 50 51 52 53 54 55 56 57 58

To allow android to respond to `click_action`, you need to define Activities and filter on specific intent. Since all javascript is running in MainActivity, you can have MainActivity to handle actions:

Edit `AndroidManifest.xml`:

```diff
  <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:windowSoftInputMode="adjustResize"
+   android:launchMode="singleTop"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
    <intent-filter>
59 60
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
61 62 63 64 65 66
    </intent-filter>
+   <intent-filter>
+     <action android:name="fcm.ACTION.HELLO" />
+     <category android:name="android.intent.category.DEFAULT" />
+   </intent-filter>
  </activity>
67
```
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

Notes:
- `launchMode="singleTop"` is to reuse MainActivity
- replace `"fcm.ACTION.HELLO"` by the `click_action` you want to match


And pass intent into package, edit `MainActivity.java`:

- RN 0.28+:

```diff
  import com.facebook.react.ReactActivity;
+ import android.content.Intent;

  public class MainActivity extends ReactActivity {

+   @Override
+   public void onNewIntent (Intent intent) {
+     super.onNewIntent(intent);
+       setIntent(intent);
+   }       
```

- RN <= 0.27:

```diff
  import com.facebook.react.ReactActivity;
+ import android.content.Intent;

  public class MainActivity extends ReactActivity {

+   @Override
+   protected void onNewIntent (Intent intent) {
+     super.onNewIntent(intent);
+       setIntent(intent);
+   }       
104
```
Libin Lu's avatar
init  
Libin Lu committed
105

106 107 108
Notes:
- `@Override` is added to update intent on notification click

109
## IOS Configuration
Libin Lu's avatar
init  
Libin Lu committed
110

Libin Lu's avatar
Libin Lu committed
111 112
### Pod approach:

113 114 115
Make sure you have Cocoapods version > 1.0

Install the `Firebase/Messaging` pod:
Libin Lu's avatar
Libin Lu committed
116 117 118 119
```
cd ios && pod init
pod install Firebase/Messaging
```
Libin Lu's avatar
init  
Libin Lu committed
120

Libin Lu's avatar
Libin Lu committed
121
### Non Cocoapod approach
122 123 124

1. Download the Firebase SDK framework from [Integrate without CocoaPods](https://firebase.google.com/docs/ios/setup#frameworks)
2. Follow the `README` to link frameworks (Analytics+Messaging)
Libin Lu's avatar
Libin Lu committed
125 126

### Shared steps
Libin Lu's avatar
init  
Libin Lu committed
127

128 129 130 131 132 133 134 135 136 137 138
Edit `AppDelegate.m`:
```diff
+ #import "Firebase.h" // if you are using Non Cocoapod approach
+ #import "RNFIRMessaging.h"
  //...

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
  //...
+   [FIRApp configure];
  }
Libin Lu's avatar
init  
Libin Lu committed
139

140 141 142 143 144
+ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
+   [[NSNotificationCenter defaultCenter] postNotificationName:FCMNotificationReceived object:self userInfo:notification];
+   handler(UIBackgroundFetchResultNewData);
+ }
```
Libin Lu's avatar
init  
Libin Lu committed
145 146

### FCM config file
147

148
In [firebase console](https://console.firebase.google.com/), you can get `google-services.json` file and place it in `android/app` directory and get `GoogleService-Info.plist` file and place it in `/ios/your-project-name` directory (next to your `Info.plist`)
Libin Lu's avatar
init  
Libin Lu committed
149

Libin Lu's avatar
Libin Lu committed
150
## Usage
Libin Lu's avatar
init  
Libin Lu committed
151 152

```javascript
153
import FCM from 'react-native-fcm';
Goran Gajic's avatar
Goran Gajic committed
154

155 156 157
class App extends Component {
  componentDidMount() {
    FCM.requestPermissions(); // for iOS
Goran Gajic's avatar
Goran Gajic committed
158 159 160 161 162 163 164
    FCM.getFCMToken().then(token => {
      console.log(token)
      // store fcm token in your server
    });
    this.notificationUnsubscribe = FCM.on('notification', (notif) => {
      // there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
    });
165 166
    this.refreshUnsubscribe = FCM.on('refreshToken', (token) => {
      console.log(token)
Goran Gajic's avatar
Goran Gajic committed
167 168
      // fcm token may not be available on first load, catch it here
    });
169

Libin Lu's avatar
Libin Lu committed
170 171
    FCM.subscribeToTopic('/topics/foo-bar');
    FCM.unsubscribeFromTopic('/topics/foo-bar');
Goran Gajic's avatar
Goran Gajic committed
172 173 174
  }

  componentWillUnmount() {
175
    // prevent leaking
Goran Gajic's avatar
Goran Gajic committed
176 177 178
    this.refreshUnsubscribe();
    this.notificationUnsubscribe();
  }
179
}
Libin Lu's avatar
init  
Libin Lu committed
180 181
```

182
### Behaviour when sending `notification` and `data` payload through GCM
Libin Lu's avatar
Libin Lu committed
183
- When app is not running when user clicks notification, notification data will be passed into `FCM.initialData`
Libin Lu's avatar
Libin Lu committed
184

Libin Lu's avatar
Libin Lu committed
185 186 187 188 189
- When app is running in background (the tricky one, I strongly suggest you try it out yourself)
 - IOS will receive notificaton from `FCMNotificationReceived` event
    * if you pass `content_available` flag true, you will receive one when app is in background and another one when user resume the app. [more info](http://www.rahuljiresal.com/2015/03/retract-push-notifications-on-ios/)
    * if you just pass `notification`, you will only receive one when user resume the app.
    * you will not see banner if `notification->body` is not defined.
190 191 192 193 194 195 196
 - Android will receive notificaton from `FCMNotificationReceived` event
    * if you pass `notification` payload. it will receive data when user click on notification
    * if you pass `data` payload only, it will receive data when in background

   e.g. fcm payload looks like:

   ```json
Libin Lu's avatar
Libin Lu committed
197 198 199 200 201 202 203 204 205 206 207 208 209
   {
      "to":"some_device_token",
      "content_available": true,
      "notification": {
          "title": "hello",
          "body": "yo",
          "click_action": "fcm.ACTION.HELLO"
      },
      "data": {
          "extra":"juice"
      }
    }
    ```
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

    and event callback will receive as:
    
    - Android
      ```json
      {
        "fcm": {"action": "fcm.ACTION.HELLO"},
        "extra": "juice"
      }
      ```
    
    - iOS
      ```json
      {
        "apns": {"action_category": "fcm.ACTION.HELLO"},
        "extra": "juice"
      }
      ```
228

Libin Lu's avatar
Libin Lu committed
229
- When app is running in foreground
230
 - IOS will receive notification and android **won't** (better not to do anything in foreground for hybrid and send a seprate data message.)
231

232
NOTE: it is recommend not to rely on `data` payload for click_action as it can be overwritten (check [this](http://stackoverflow.com/questions/33738848/handle-multiple-notifications-with-gcm)).
233

Libin Lu's avatar
init  
Libin Lu committed
234
## Q & A
235 236

#### My Android build is failing
Libin Lu's avatar
Libin Lu committed
237
Try update your SDK and google play service
238

239
#### I can't get notification when app is killed
240 241
If you send notification with `data` only, you can only get the data message when app is in foreground or background. Killed app doesn't trigger `FCMNotificationReceived`. Use `notification` in the payload instead.

Libin Lu's avatar
Libin Lu committed
242
#### App running in background doesn't trigger `FCMNotificationReceived` when receiving hybrid notification [Android]
243
These is [an issue opened for that](https://github.com/google/gcm/issues/63). Behavior is not consistent between 2 platforms
244

Libin Lu's avatar
Libin Lu committed
245
#### Android notification is showing a white icon
246 247
Since Lollipop, the push notification icon is required to be all white, otherwise it will be a white circle.

Libin Lu's avatar
Libin Lu committed
248 249 250
#### iOS not receiving notification when the app running in the background
- Try adding Background Modes permission in Xcode->Click on project file->Capabilities tab->Background Modes->Remote Notifications

251 252 253 254 255 256 257
#### I am using Proguard
You need to add this to your `android/app/proguard-rules.pro`:
```
# Google Play Services
-keep class com.google.android.gms.** { *; }
-dontwarn com.google.android.gms.**
```
Libin Lu's avatar
init  
Libin Lu committed
258

259 260
#### Some features are missing
Issues and pull requests are welcome. Let's make this thing better!