Github link: https://github.com/no-dap/capacitor-notification-extensions
Capacitor plugin with some features
- Background-handled data notification
- Client-side notification filtering (SQLite based)
- Custom boolean filters
- Time based filters
- Force-fire
localNotificationReceived
event listener which is not working properly
in LocalNotification plugin
Those features all works fine irrelevant with the app's state(on foreground, on background, or not on process).
Works fine with Capacitor 2.x
Not compatible with Capacitor 3.x
Use SQLite via Helper(from capacitor sqlite plugin)
npm i capacitor-notification-extensions --save
- Add NotificationExtension class to your MainActivity.
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
add(YourAwesomePlugins.class);
...
add(NotificationExtension.class);
add(LocalNotificationExtension.class);
}});
}
}
- Add meta data and intent filter to manifest inside application tag and add db_name to string values.
- AndroidManifest.xml
<?xml version='1.0' encoding='utf-8'?>
<manifest>
<application...>
...
<activity ...>
<intent-filter>
<action android:name="com.woot.notification.extensions.intent.action.Launch" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<meta-data android:name="com.woot.notification.extensions.local_database_name" android:value="@string/db_name" />
</application>
</manifest>
- strings.xml
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="db_name">TODO</string>
</resources>
- Add silent notification to your AppDelegate
class AppDelegate: UIResponder, UIAppicationDelegate {
...
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
NotificationCenter.default.post(name: Notification.Name("SilentNotification"), object: nil, userInfo: userInfo)
}
...
}
- Add some data to your Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<plist version="1.0">
<dict>
...
<key>LocalDatabase</key>
<string>TODO</string>
...
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
...
</dict>
</plist>
Have no plans to support yet.
If you are new on firebase messaging, I recommend reading this documentation first to understand about two concepts of notification message.
NotificationExtension class is child of default plugin PushNotification. You can check arguments and return of methods from the link above.
This plugin creates a sqlite table notification_extensions_filter
with its own schema.
Message in both platform shouldn't contain notification
key which makes message as alert message.
- Android
Get data fromyourMessagePayload.data
. (Check how payload parsed) - iOS
Get data fromyourMessagePayload.apns.payload.aps.custom_data
. (Check how payload parsed)
Both platforms' payload should contain keys below.
- isShown: Optional, boolean string('true' or 'false'), always true if not exists.
- body: Optional, string, body of notification message
- title: Optional, string, title of notification message
- filter: Optional, comma-separated string, hide notification if matched filter with false value exists.
- Any other data you that want to use in your application
All key-value based filters which is added or removed by addFilters and removeFilters method will be saved in the local database.
There are two filters that specially checks before show notification, which is time-based filter and logged-in filter.
- logged-in filter
If you add a filter with keyis_logged_in
, this filter will always be checked on a message received even if payload doesn't contain filter key. - time-based filter
If you add a filter with addTimeFilter method, three rows will be generated in the local database. (filter_start_from, filter_end_at, is_time_filter_on)
This filter will always be checked on a message received even if payload doesn't contain filter key.
addTimeFilter method only takes string withHH:mm
format and will raise some validation error if is malformed.
In your js application,
import { Plugins } from '@capacitor/core';
const { NotificationExtension } = Plugins
NotificationExtension.addListener('pushNotificationActionPerformed', (notification: PushNotificationActionPerformed) => {
// Same as PushNotification plugin
// You can deal with your payload
});
NotificationExtension.addListener('pushNotificationReceived', (notification: YourPayloadType) => {
// Same as PushNotification plugin
// Only works when the app is on foreground
});
NotificationExtension.register();
NotificationExtension.addFilters({ filters: ['anyString', 'youPromised', 'withBackend'] });
// Any data notification that contains key named 'filter' with value matched above will be suppressed by plugin.
NotificationExtension.removeFilters({ filters: ['youPromised'] });
// filtering 'youPromised' stop working
NotificationExtension.getFilters().then((result) => {
// result will be { value: ['anyString', 'withBackend'] }
});
NotificationExtension.addTimeFilter({ startFrom: '23:00', endAt: '07:00' });
// every notification that received between 11PM to 7AM will be suppressed
LocalNotification.addListener('localNotificationReceived')
doesn't work in android if you use capacitor 2.x,
this class just a bug fix that only overrides a receiver to notify a message received event to listener.
(This will be solved in capacitor 3.x, merged commit link)
Use this plugin for android only. (This class hasn't implemented for iOS)
import { LocalNotification, Plugins } from '@capacitor/core';
const { LocalNotifications, LocalNotificationExtension } = Plugins;
class YourServiceOrComponent {
constructor() {}
get localNotificationPlugin() {
return this.platform.is('android') ? LocalNotificationExtension : LocalNotifications;
}
yourMethod() {
this.LocalNotificationPlugin.addListener('localNotificationReceived', (localNotification: LocalNotification) => {
// Do what you want
});
}
}
Feel free to ask anything on project issues. Any kind of contributions and bug reports are also welcomed.