This package helps to show:
Current version is for Android only.
There are 3 types of notifications:
When app is in background only plain data notifications can be customized (firebase onMessageRecieve() is fired only for them). That is why from a backend part you should send push notifications only with data attributes. Example:
{
data: {
title: "push notification title",
message: "push notification body",
media: "https://example.com/image.png", // optional
url: "https://google.com" // optional
}
}
More info here. Twilio example here (NOTICE: you should set twilio parameters: account id, auth token, service id, device fcm token).
npm install @cryptoticket/react-native-push-notification --save
google-services.json
file to android/app
folder<project>/build.gradle
:buildscript {
// ... other settings
dependencies {
// ... other dependencies
classpath 'com.google.gms:google-services:4.3.2' // add this line with latest version
}
}
<project>/<app-module>/build.gradle
:apply plugin: 'com.google.gms.google-services' // add this line
<!-- start notification settings -->
<meta-data
android:name="com.cryptoticket.reactnativepushnotification.default_activity"
android:value="com.example.MainActivity" />
<meta-data
android:name="com.cryptoticket.reactnativepushnotification.default_channel_id"
android:value="my_channel_id" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@android:color/black" />
<service
android:name="com.cryptoticket.reactnativepushnotification.CustomFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver android:name="com.cryptoticket.reactnativepushnotification.PushNotificationBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="com.cryptoticket.reactnativepushnotification.action.CLOSE_NOTIFICATION"/>
<action android:name="com.cryptoticket.reactnativepushnotification.action.OPEN_URL"/>
<action android:name="com.cryptoticket.reactnativepushnotification.action.PRESS_ON_NOTIFICATION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<!-- end notification settings -->
Manifest explanation:
id
param should be passed in Intent extras.url
param should be passed in Intent extras.import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const channelId = "my_channel_id";
const channelName = "my_channel_name";
const channelDesc = "my_channel_desc";
const channelImportance = PushNotificationAndroid.CHANNEL_IMPORTANCE_DEFAULT;
PushNotificationAndroid.createChannel(channelId, channelName, channelDesc, channelImportance);
Returns device FCM token.
Example:
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const token = await PushNotificationAndroid.getDeviceToken();
console.log(token); // 7rilPUr_OJBvggou...
Cancels scheduled notification by notification id. Scheduled notification can be created if you pass showAt
param to show()
method.
Example:
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const notificationId = 1;
PushNotificationAndroid.cancelScheduledNotification(notificationId);
Creates a notification channel. For android >= 8 (SDK >= 26) channels are required when you show a push notification. NOTICE: you should call this method on app init and pass channel id from your manifest file.
Example:
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const channelId = "my_channel_id";
const channelName = "my_channel_name";
const channelDesc = "my_channel_desc";
const channelImportance = PushNotificationAndroid.CHANNEL_IMPORTANCE_DEFAULT;
PushNotificationAndroid.createChannel(channelId, channelName, channelDesc, channelImportance);
Shows a push notification. You can use this method locally. This method is also called when remote notification is received.
media
or url
data attributes then PushNotificationAndroid.TEMPLATE_EVENT will be used.Example (default notification with title and message):
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const notificationId = 1;
const template = PushNotificationAndroid.TEMPLATE_COMMON;
const channelId = 'my_channel_id';
const data = {
title: "my title",
message: "my message"
};
const priority = PushNotificationAndroid.PRIORITY_DEFAULT;
const badgeNumber = 10;
const showAt = 0;
PushNotificationAndroid.show(notificationId, template, channelId, data, priority, badgeNumber, showAt);
Example (custom notification template with checkmark button, media image, url that will be opened on notification content click, title and message):
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const template = PushNotificationAndroid.TEMPLATE_EVENT;
const channelId = 'my_channel_id';
const data = {
title: "title", // optional (can be null)
message: "my message", // optional (can be null)
media: "http://red-msk.ru/wp-content/uploads/2019/02/canva-photo-editor-22.png", // optional (can be null)
url: "https://google.com" // optional (can be null)
};
const priority = PushNotificationAndroid.PRIORITY_DEFAULT;
const badgeNumber = 10;
const showAt = 0;
PushNotificationAndroid.show(notificationId, template, channelId, data, priority, badgeNumber, showAt);
Example (scheduled notification which should be shown after 60 seconds have passed):
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
import moment from 'moment';
const notificationId = 1;
const template = PushNotificationAndroid.TEMPLATE_COMMON;
const channelId = 'my_channel_id';
const data = {
title: "my title",
message: "my message"
};
const priority = PushNotificationAndroid.PRIORITY_DEFAULT;
const badgeNumber = 10;
const showAt = moment().utc().unix() + 60;
PushNotificationAndroid.show(notificationId, template, channelId, data, priority, badgeNumber, showAt);
All new notification templates are added in native code. Let’s add a weather notification template which shows current temperature (with a single text view).
notification_template_weather.xml
inside android/src/main/res/layout
folder with the following content:<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="64dp">
<TextView
android:id="@+id/textViewTemperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
We show a single text view with id textViewTemperature
.
NOTICE: by default android notification height is 64dp so you should follow this rule.
NOTICE: not all layouts and widgets are supported in a custom push notification template. More info here.
Templates
object in PushNotificationModule.kt
file:object Templates {
val COMMON = 0
val EVENT = 1
val WEATHER = 2 // your new template
}
getConstants()
method in PushNotificationModule.kt
file so that your template could be accessible from React Native:override fun getConstants(): MutableMap<String, Any> {
val constants = mutableMapOf<String, Any>()
// ... other constants
constants.put("TEMPLATE_WEATHER", Templates.WEATHER) // your new template
return constants
}
show()
method in PushNotificationModule.
:@ReactMethod
fun show(notificationId: Int, template: Int, channelId: String, data: ReadableMap, priority: Int = NotificationCompat.PRIORITY_DEFAULT, badgeNumber: Int = 0, showAt: Int = 0) {
// ... other templates
if(template == Templates.WEATHER) {
val remoteViews = RemoteViews(reactApplicationContext.packageName, R.layout.notification_template_weather)
// assign "temperature" notification data attribute to "textViewTemperature" TextView in xml template
remoteViews.setTextViewText(R.id.textViewTemperature, data.getString("temperature"))
builder.setContent(remoteViews)
}
// ... show notification code
}
CustomFirebaseMessagingService.kt
service so that remote notifications could use your template. Add the following code to the onMessageReceived()
method:override fun onMessageReceived(remoteMessage: RemoteMessage) {
// ... other code
// if notification has "temperature" data attribute then use WEATHER template
if(!remoteMessage.data.get("temperature").isNullOrEmpty()) {
templateId = PushNotificationModule.Templates.WEATHER
}
module.show(notificationId, templateId, channelId, rnMap)
}
import { PushNotificationAndroid } from '@cryptoticket/react-native-push-notification';
const notificationId = 1;
const template = PushNotificationAndroid.TEMPLATE_WEATHER;
const channelId = 'my_channel_id';
const data = {
temperature: "+24 degrees"
};
const priority = PushNotificationAndroid.PRIORITY_DEFAULT;
const badgeNumber = 10;
const showAt = 0;
PushNotificationAndroid.show(notificationId, template, channelId, data, priority, badgeNumber, showAt);
By default main app screen is opened when user presses on any notification. With this package you can add the ability to open app via deep link on notification press. For example, if you receive content_id
in notification data attributes then on notification press you can open app by deep link (ex: app://content/1
) and inside your app handle this link as you need.
MainActivity
section to AndroidManifest.xml
file:<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="app" android:host="content" />
</intent-filter>
</activity>
Now your app should be able to handle deep links, for example app://content/1
. You can open app from deep link via adb console command adb shell am start -W -a android.intent.action.VIEW -d "app://content/1" com.example
(use your app package name).
onNotificationPress()
function:package com.example;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.cryptoticket.reactnativepushnotification.PushNotificationBroadcastReceiver;
public class CustomPushNotificationBroadcastReceiver extends PushNotificationBroadcastReceiver {
@Override
public void onNotificationPress(Context context, Intent intent) {
boolean shouldHandleDeepLink = true;
if(shouldHandleDeepLink) {
// list all notification data attributes
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Log.d("CUSTOM RECEIVER", key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
}
}
// open app by deep link
Intent mainIntent = new Intent(Intent.ACTION_VIEW);
mainIntent.setData(Uri.parse("app://content/1"));
mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mainIntent);
} else {
// open main app activity by default
super.onNotificationPress(context, intent);
}
}
}
So you may check notification data attributes and depening on them open app from deep link or use the default behavior which opens app’s main screen.
AndroidManifest.xml
:<!-- start optional notification settings -->
<meta-data
android:name="com.cryptoticket.reactnativepushnotification.default_broadcast_receiver"
android:value="com.example.CustomPushNotificationBroadcastReceiver" />
<!-- end optional notification settings -->
receiver
name in AndroidManifest.xml
.Old:
<receiver android:name="com.cryptoticket.reactnativepushnotification.PushNotificationBroadcastReceiver" android:exported="true">
New:
<receiver android:name=".CustomPushNotificationBroadcastReceiver" android:exported="true">
example
folder run:npm install
google-services.json
and add it to example/android/app
folder.You may get this error on app build if one of your npm dependencies uses glide. Solution is here. You should add the following code to your android/build.gradle
:
project.ext {
excludeAppGlideModule = true
}
By default twilio wraps notification body(message) in twi_body
param. This package expects param message
to be a notification body, not twi_body
. Solution: copy twi_body
notification attribute to message
attribute on remote notification receive.
Create a new class and extend existing CustomFirebaseMessagingService
:
package com.example;
import com.cryptoticket.reactnativepushnotification.CustomFirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;
/**
* Extends react-native-push-notification message service.
*/
public class MainMessagingService extends CustomFirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
/**
* By default twilio sends notification body message in "twi_body" param.
* Our lib needs notification message param to be called "message",
* so we copy "twi_body" to "message" in remote message data map.
*/
if(remoteMessage.getData().containsKey("twi_body")) {
remoteMessage.getData().put("message", remoteMessage.getData().get("twi_body"));
}
// call parent method
super.onMessageReceived(remoteMessage);
}
}
Delete the default firebase service from the manifest:
<service
android:name="com.cryptoticket.reactnativepushnotification.CustomFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Add your custom service (which modifies twilio notification params) to the manifest:
<service
android:name=".MainMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Author: cryptoticket
Source Code: https://github.com/cryptoticket/react-native-push-notification
#react-native #react #mobile-apps