big_text:'i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large, i am large',
55A6E80F734FA3F596B96C04/* Pods-SimpleFcmClientTests.debug.xcconfig */={isa=PBXFileReference;includeInIndex=1;lastKnownFileType=text.xcconfig;name="Pods-SimpleFcmClientTests.debug.xcconfig";path="Pods/Target Support Files/Pods-SimpleFcmClientTests/Pods-SimpleFcmClientTests.debug.xcconfig";sourceTree="<group>";};
64204739CA77D9B1EB1F0788/* Pods-SimpleFcmClientTests.release.xcconfig */={isa=PBXFileReference;includeInIndex=1;lastKnownFileType=text.xcconfig;name="Pods-SimpleFcmClientTests.release.xcconfig";path="Pods/Target Support Files/Pods-SimpleFcmClientTests/Pods-SimpleFcmClientTests.release.xcconfig";sourceTree="<group>";};
73B4AFC1AC5C6373F8074CBC/* Pods-SimpleFcmClient.debug.xcconfig */={isa=PBXFileReference;includeInIndex=1;lastKnownFileType=text.xcconfig;name="Pods-SimpleFcmClient.debug.xcconfig";path="Pods/Target Support Files/Pods-SimpleFcmClient/Pods-SimpleFcmClient.debug.xcconfig";sourceTree="<group>";};
CF6939675D5A4A68FBE567C0/* Pods-SimpleFcmClient.release.xcconfig */={isa=PBXFileReference;includeInIndex=1;lastKnownFileType=text.xcconfig;name="Pods-SimpleFcmClient.release.xcconfig";path="Pods/Target Support Files/Pods-SimpleFcmClient/Pods-SimpleFcmClient.release.xcconfig";sourceTree="<group>";};
...
...
@@ -289,6 +315,7 @@
isa=PBXFrameworksBuildPhase;
buildActionMask=2147483647;
files=(
3A7531B520323B2400888478/* libRCTAnimation.a in Frameworks */,
3A6D62911E2044AB00D0D2C7/* libz.tbd in Frameworks */,
146834051AC3E58100842450/* libReact.a in Frameworks */,
00C302E51ABCBA2D00DB3ED1/* libRCTActionSheet.a in Frameworks */,
...
...
@@ -302,6 +329,7 @@
139FDEF61B0652A700C62182/* libRCTWebSocket.a in Frameworks */,
FAE94A218EB64E38BF8D8E9B/* libRNFIRMessaging.a in Frameworks */,
6976C617E52062E3EE272128/* libPods-SimpleFcmClient.a in Frameworks */,
B5EEA6C40DAD43C696D4A7EE/* libAirMaps.a in Frameworks */,
shellScript="diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript="diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript="diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript="diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- Edit `MainActivity.java`. This fixes [a bug](https://stackoverflow.com/questions/14853327/intent-not-restored-correctly-after-activity-is-killed-if-clear-top-and-single-t/18307360#18307360)
```diff
+ import android.content.Intent;
...
public class MainActivity extends ReactActivity {
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
}
```
### Config for notification and `click_action` in Android
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:
...
...
@@ -197,13 +211,17 @@ Install the `Firebase/Messaging` pod:
pod install
```
NOTE: you don't need to enable `use_frameworks!`. if you have to have `use_frameworks!` make sure you don't have `inherit! :search_paths`
NOTE: there is a working example in `master` branch
### Non Cocoapod approach
1. Download the Firebase SDK framework from [Integrate without CocoaPods](https://firebase.google.com/docs/ios/setup#frameworks).
1. Follow the instruction on [Integrate without CocoaPods](https://firebase.google.com/docs/ios/setup#frameworks).
- Import libraries, add Capabilities (background running and push notification), upload APNS and etc etc etc...
2. Put frameworks under `ios/Frameworks` folder
2. Follow the `README` to link frameworks (Analytics+Messaging)
2. Put frameworks under `ios/Frameworks` folder, and drag those files into your xcode solution -> Frameworks
3. Put `firebase.h` and `module.modulemap` under `ios/Frameworks` folder, no need to drag into solution
4. Modify your project's `User Header Search Paths` and add `$(PROJECT_DIR)/Frameworks`
@@ -294,139 +312,8 @@ NOTE: `com.evollu.react.fcm.FIRLocalMessagingPublisher` is required for presenti
## Usage
[Check example project](https://github.com/evollu/react-native-fcm/blob/master/Examples/simple-fcm-client/app/App.js#L68)
```javascript
import {Platform} from 'react-native';
import FCM, {FCMEvent, RemoteNotificationResult, WillPresentNotificationResult, NotificationType} from 'react-native-fcm';
// this shall be called regardless of app state: running, background or not running. Won't be called when app is killed by user in iOS
FCM.on(FCMEvent.Notification, async (notif) => {
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
if(notif.local_notification){
//this is a local notification
}
if(notif.opened_from_tray){
//iOS: app is open/resumed because user clicked banner
//Android: app is open/resumed because user clicked banner or tapped app icon
}
// await someAsyncCall();
if(Platform.OS ==='ios'){
//optional
//iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application.
//This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
//notif._notificationType is available for iOS platfrom
// initial notification contains the notification that launchs the app. If user launchs app by clicking banner, the banner notification info will be here rather than through FCM.on event
// sometimes Android kills activity when app goes to background, and when resume it broadcasts notification before JS is run. You can use FCM.getInitialNotification() to capture those missed events.
// initial notification will be triggered all the time even when open app by icon so send some action identifier when you send notification
FCM.getInitialNotification().then(notif => {
console.log(notif)
});
}
componentWillUnmount() {
// stop listening for events
this.notificationListener.remove();
}
otherMethods(){
FCM.subscribeToTopic('/topics/foo-bar');
FCM.unsubscribeFromTopic('/topics/foo-bar');
FCM.presentLocalNotification({
id: "UNIQ_ID_STRING", // (optional for instant notification)
title: "My Notification Title", // as FCM payload
body: "My Notification Message", // as FCM payload (required)
sound: "default", // as FCM payload
priority: "high", // as FCM payload
click_action: "ACTION", // as FCM payload
badge: 10, // as FCM payload IOS only, set 0 to clear badges
number: 10, // Android only
ticker: "My Notification Ticker", // Android only
auto_cancel: true, // Android only (default true)
large_icon: "ic_launcher", // Android only
icon: "ic_launcher", // as FCM payload, you can relace this with custom icon you put in mipmap
big_text: "Show when notification is expanded", // Android only
sub_text: "This is a subText", // Android only
color: "red", // Android only
vibrate: 300, // Android only default: 300, no vibration if you pass 0
wake_screen: true, // Android only, wake up screen when notification arrives
group: "group", // Android only
picture: "https://google.png", // Android only bigPicture style
ongoing: true, // Android only
my_custom_data:'my_custom_field_value', // extra data you want to throw
lights: true, // Android only, LED blinking (default false)
show_in_foreground // notification when app is in foreground (local & remote)
});
FCM.scheduleLocalNotification({
fire_date: new Date().getTime(), //RN's converter is used, accept epoch time and whatever that converter supports
id: "UNIQ_ID_STRING", //REQUIRED! this is what you use to lookup and delete notification. In android notification with same ID will override each other
//these clears notification from notification center/tray
FCM.removeAllDeliveredNotifications()
FCM.removeDeliveredNotification("UNIQ_ID_STRING")
//these removes future local notifications
FCM.cancelAllLocalNotifications()
FCM.cancelLocalNotification("UNIQ_ID_STRING")
FCM.setBadgeNumber(1); // iOS and supporting android.
FCM.getBadgeNumber().then(number=>console.log(number)); // iOS and supporting android.
FCM.send('984XXXXXXXXX', {
my_custom_data_1: 'my_custom_field_value_1',
my_custom_data_2: 'my_custom_field_value_2'
});
FCM.deleteInstanceId()
.then( () => {
//Deleted instance id successfully
//This will reset Instance ID and revokes all tokens.
})
.catch(error => {
//Error while deleting instance id
});
}
}
```
### Build custom push notification for Android
Firebase android misses important feature of android notification like `group`, `priority` and etc. As a work around you can send data message (no `notification` payload at all) and this repo will build a local notification for you. If you pass `custom_notification` in the payload, the repo will treat the content as a local notification config and shows immediately.
...
...
@@ -543,6 +430,26 @@ FCM.send('984XXXXXXXXX', {
The `Data Object` is message data comprising as many key-value pairs of the message's payload as are needed (ensure that the value of each pair in the data object is a `string`). Your `Sender ID` is a unique numerical value generated when you created your Firebase project, it is available in the `Cloud Messaging` tab of the Firebase console `Settings` pane. The sender ID is used to identify each app server that can send messages to the client app.
### Sending remote notifications with category on iOS
If you want to send notification which will have actions as you defined in app it's important to correctly set it's `category` (`click_action`) property. It's also good to set `"content-available" : 1` so app will gets enough time to handle actions in background.
So the fcm payload should look like this:
```javascript
{
"to": "some_device_token",
"content_available": true,
"notification": {
"title": "Alarm",
"subtitle": "First Alarm",
"body": "First Alarm",
"click_action": "com.myapp.MyCategory" // The id of notification category which you defined with FCM.setNotificationCategories
},
"data": {
"extra": "juice"
}
}
```
## Q & A
#### Why do you build another local notification
...
...
@@ -552,18 +459,12 @@ Yes there are `react-native-push-notification` and `react-native-system-notifica
- The PushNotificationIOS by react native team is still missing features that recurring, so we are adding it here
#### My Android build is failing
Try update your SDK and google play service. If you are having multiple plugins requiring different version of play-service sdk, use force to lock in version
Try update your SDK and google play service.
If you are having multiple plugins requiring different version of play-service sdk, skip conflicting group. The example project shows for how to colive with react-native-maps
@@ -645,3 +546,65 @@ Issues and pull requests are welcome. Let's make this thing better!
#### Credits
Local notification implementation is inspired by react-native-push-notification by zo0r
## Sending remote notification
How to send a push notification from your server? You should `POST` to this endpoint:
https://fcm.googleapis.com/fcm/send
You need to set the headers of `Content-Type` to `application/json` and `Authorization` to `key=******` where you replace `******` with the "Legacy server key" from here the Firebase dashbaord. Get this information by first going to:
1. https://console.firebase.google.com/
2. Click on "Gear" icon and click "Project Settingss". Screenshot: https://screenshotscdn.firefoxusercontent.com/images/35b93de8-44e1-49af-89d7-140b74c267c7.png
3. Click on "Cloud Message" tab and find "Legacy server key" here. Screenshot: https://screenshotscdn.firefoxusercontent.com/images/c52ec383-783d-47d3-a1e6-75249fb6f3fb.png