Use the native Firebase SDK (iOS/Android) in Axway Titanium. This repository is part of the Titanium Firebase project.
The whole Firebase support in Titanium is developed and maintained by the community (@hansemannn
and @m1ga
). To keep
this project maintained and be able to use the latest Firebase SDK's, please see the "Sponsor" button of this repository,
thank you!
- Requirements
- Download
- iOS notes
- Android Notes
- API: Methods, Properties, Events
- Example
- Sending push messages
- Build from source
- iOS: Firebase-Core
- iOS: Titanium SDK 10.0.0
- Android: Titanium SDK 9.0.0+, Ti.PlayServices module
- Read the Titanium-Firebase install part if you set up a new project.
To register for push notifications on iOS, you only need to call the Titanium related methods as the following:
// Listen to the notification settings event
Ti.App.iOS.addEventListener('usernotificationsettings', function eventUserNotificationSettings() {
// Remove the event again to prevent duplicate calls through the Firebase API
Ti.App.iOS.removeEventListener('usernotificationsettings', eventUserNotificationSettings);
// Register for push notifications
Ti.Network.registerForPushNotifications({
success: function () { ... },
error: function () { ... },
callback: function () { ... } // Fired for all kind of notifications (foreground, background & closed)
});
});
// Register for the notification settings event
Ti.App.iOS.registerUserNotificationSettings({
types: [
Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
]
});
Big image notification with colored icon/appname | Big text notification with colored icon/appname |
If you use Titanium 12.0.0+ you can use
Ti.Network.registerForPushNotifications({
success: function () { ... },
error: function () { ... }
});
to request Android 13 runtime permissions. All other version < Android 13 will call the success
function right away.
If you have runtime permissions (the success
event mentioned above or Ti.Network.remoteNotificationsEnabled
is true) you can call fcm.registerForPushNotifications()
to request a token. Check the full example below for all steps.
If you use Titanium >=12.0.0 (target SDK 33) you can use Ti.Network.registerForPushNotifications()
to ask for the permission.
You can also request the permission with older SDKs yourself by using the general requestPermissions()
method:
var permissions = ['android.permission.POST_NOTIFICATIONS'];
Ti.Android.requestPermissions(permissions, function(e) {
if (e.success) {
Ti.API.info('SUCCESS');
} else {
Ti.API.info('ERROR: ' + e.error);
});
For a data notification
you have to place a notification icon "notificationicon.png" into the following folder:
[application_name]/[app*]/platform/android/res/drawable/
or
[application_name]/[app*]/platform/android/res/drawable-*
(if you use custom dpi folders)
* = Alloy
To use the custom icon for a notification message
you need to add this attribute within the <application/>
section of your tiapp.xml
:
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notificationicon"/>
Otherwise the default icon will be used.
It should be flat (no gradients), white and face-on perspective and have a transparent background. The icon will only show the outline/shape of your icon so make sure all you e.g. white is transparent otherwise it will just be a square.
Note: You should generate the icon for all resolutions.
22 × 22 area in 24 × 24 (mdpi)
33 × 33 area in 36 × 36 (hdpi)
44 × 44 area in 48 × 48 (xhdpi)
66 × 66 area in 72 × 72 (xxhdpi)
88 × 88 area in 96 × 96 (xxxhdpi)
You can use this script to generate it once you put the icon in drawable-xxxhdpi/notificationicon.png
and have
Image Magick installed. On macOS, you can install it using brew install imagemagick
, on Windows you can download it here.
#!/bin/sh
ICON_SOURCE="app/platform/android/res/drawable-xxxhdpi/notificationicon.png"
if [ -f "$ICON_SOURCE" ]; then
mkdir -p "app/platform/android/res/drawable-xxhdpi"
mkdir -p "app/platform/android/res/drawable-xhdpi"
mkdir -p "app/platform/android/res/drawable-hdpi"
mkdir -p "app/platform/android/res/drawable-mdpi"
convert "$ICON_SOURCE" -resize 72x72 "app/platform/android/res/drawable-xxhdpi/notificationicon.png"
convert "$ICON_SOURCE" -resize 48x48 "app/platform/android/res/drawable-xhdpi/notificationicon.png"
convert "$ICON_SOURCE" -resize 36x36 "app/platform/android/res/drawable-hdpi/notificationicon.png"
convert "$ICON_SOURCE" -resize 24x24 "app/platform/android/res/drawable-mdpi/notificationicon.png"
else
echo "No 'notificationicon.png' file found in app/platform/android/res/drawable-xxxhdpi"
fi
On Android there are two different messages that the phone can process: Notification messages
and Data messages
. A Notification message
is processed by the system, the Data message
is handeled by showNotification()
in TiFirebaseMessagingService
. Using the notification
block inside the POSTFIELDS will send a Notification message
.
Supported data fields:
- "title" => "string"
- "message" => "string"
- "big_text" => "string"
- "big_text_summary" => "string"
- "icon" => "Remote URL"
- "image" => "Remote URL"
- "rounded_large_icon" => "Boolean" (to display the largeIcon as a rounded image when the icon field is present)
- "force_show_in_foreground" => "Boolean" (show notification even app is in foreground)
- "id" => "int"
- "color" => will tint the app name and the small icon next to it
- "vibrate" => "boolean"
- "sound" => "string" (e.g. "notification.mp3" will play /platform/android/res/raw/notification.mp3)
- "badge" => "int" (if supported by the phone it will show a badge with this number)
Supported notification fields:
- "title" => "string"
- "body" => "string"
- "color" => "#00ff00",
- "tag" => "custom_notification_tag", // push with the same tag will replace each other
- "sound" => "string" (e.g. "notification.mp3" will play /platform/android/res/raw/notification.mp3)
To use a custom sound you have to create a second channel. The default channel will always use the default notification sound on the device!
If you send a normal or mixed notification you have to set the android_channel_id
in the notification
node. If you send a data notification the key is called channelId
. Chech extended PHP Android example for a PHP example.
Android: Note for switching between v<=v2.0.2 and >=v2.0.3 if you use notification channels with custom sounds
With versions prior to 2.0.3 of this module, FirebaseCloudMessaging.createNotificationChannel would create the notification sound uri using the resource id of the sound file in the res/raw
directory. However, as described in this android issue, those resource ids can change to reference different files (or no file) between app versions, and that happens the notification channel may play a different or no sound than originally intended.
With version 2.0.3 and later, we now create the uri's using the string filename so that it will not change if resource ids change. So if you are on version <=2.0.2 and are switching to version >=2.0.3, you will want to check if this is a problem for you by installing a test app using version >= 2.0.3 as an upgrade to a previous test app using version <= 2.0.2. Note that you should not uninstall the first app before installing the second app; nor should you reset user data.
If it is a problem you can workaround by first deleting the existing channel using deleteNotificationChannel, and then recreating the channel with the same settings as before, except with a different id. Don't forget that your push server will need to be version aware and send to this new channel for newer versions of your apps.
If you run into errors in combination with firebase.analytics e.g. Error: Attempt to invoke virtual method 'getInstanceId()' on a null object reference
you can add:
<service android:name="com.google.firebase.components.ComponentDiscoveryService" >
<meta-data android:name="com.google.firebase.components:com.google.firebase.iid.Registrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
</service>
to the tiapp.xml
registerForPushNotifications()
appDidReceiveMessage(parameters)
(iOS only)
parameters
(Object)
Note: Only call this method if method swizzling is disabled (enabled by default). Messages are received via the native delegates instead,
so receive the gcm.message_id
key from the notification payload instead.
sendMessage(parameters)
parameters
(Object)messageID
(String)to
(String)timeToLive
(Number)data
(Object)
subscribeToTopic(topic)
topic
(String)
unsubscribeFromTopic(topic)
topic
(String)
setNotificationChannel(channel)
- Android-only
channel
(NotificationChannel Object) UseTi.Android.NotificationManager.createNotificationChannel()
to create the channel and pass it to the function. See Titanium.Android.NotificationChannel
Prefered way to set a channel. As an alternative you can use createNotificationChannel()
createNotificationChannel(parameters)
- Android-only
-
parameters
(Object)sound
(String) optional, refers to a sound file (without extension) atplatform/android/res/raw
. If sound == "default" or not passed in, will use the default sound. If sound == "silent" the channel will have no soundchannelId
(String) optional, defaults to "default"channelName
(String) optional, defaults tochannelId
importance
(String) optional, either "low", "high", "default". Defaults to "default", unless sound == "silent", then defaults to "low".lights
(Boolean) optional, defaults tofalse
showBadge
(Boolean) optional, defaults tofalse
Read more in the official Android docs.
deleteNotificationChannel(channelId)
- Android-only
channelId
(String) - same as the id used to create in createNotificationChannel
setForceShowInForeground(showInForeground)
- Android-only
showInForeground
(Boolean) Force the notifications to be shown in foreground.
clearLastData()
- Android-only
- Will empty the stored lastData values.
getToken()
- Android-only
- Returns the current FCM token.
deleteToken()
- Android-only
- Removes the current FCM token.
shouldEstablishDirectChannel
(Number, get/set)
fcmToken
(String, get)
apnsToken
(String, set) (iOS only)
lastData
(Object) (Android only)
The propery lastData
will contain the data part when you send a notification push message (so both nodes are visible inside the push payload). Read before calling registerForPushNotifications()
.
didReceiveMessage
-
message
(Object)iOS Note: This method is only called on iOS 10+ and only for direct messages sent by Firebase. Normal Firebase push notifications are still delivered via the Titanium notification events, e.g.
Ti.App.iOS.addEventListener('notification', function(event) { // Handle foreground notification }); Ti.App.iOS.addEventListener('remotenotificationaction', function(event) { // Handle background notification action click });
didRefreshRegistrationToken
fcmToken
(String)
success
(Android only)
- will fire on Android 13 after you call
registerForPushNotifications
to allow Push notifications
error
(Android only)
error
(String): Error during token registration or user deniedregisterForPushNotifications
subscribe
(Android only)
success
(Boolean): Successfully subscribed
unsubscribe
(Android only)
success
(Boolean): Successfully unsubscribed
tokenRemoved
(Android only)
success
(Boolean): Successfully removed token
if (OS_IOS) {
const FirebaseCore = require('firebase.core');
FirebaseCore.configure();
}
// Important: The cloud messaging module has to imported after (!) the configure()
// method of the core module is called
const FirebaseCloudMessaging = require('firebase.cloudmessaging');
// Called when the Firebase token is registered or refreshed.
FirebaseCloudMessaging.addEventListener('didRefreshRegistrationToken', onToken);
// Called when direct messages arrive. Note that these are different from push notifications.
FirebaseCloudMessaging.addEventListener('didReceiveMessage', function(e) {
Ti.API.info('Message', e.message);
});
if (OS_ANDROID) {
// Android
// create a notification channel
const channel = Ti.Android.NotificationManager.createNotificationChannel({
id: 'default', // if you use a custom id you have to set the same to the `channelId` in you php send script!
name: 'Default channel',
importance: Ti.Android.IMPORTANCE_DEFAULT,
enableLights: true,
enableVibration: true,
showBadge: true
});
FirebaseCloudMessaging.notificationChannel = channel;
// display last push data if available
Ti.API.info(`Last data: ${FirebaseCloudMessaging.lastData}`);
// request push permission
requestPushPermissions();
} else {
// iOS
// Listen to the notification settings event
Ti.App.iOS.addEventListener('usernotificationsettings', function eventUserNotificationSettings() {
// Remove the event again to prevent duplicate calls through the Firebase API
Ti.App.iOS.removeEventListener('usernotificationsettings', eventUserNotificationSettings);
requestPushPermissions();
});
// Register for the notification settings event
Ti.App.iOS.registerUserNotificationSettings({
types: [
Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
]
});
}
function requestPushPermissions() {
// Register for push notifications
Ti.Network.registerForPushNotifications({
success: function(e) {
// Register the device with the FCM service.
if (OS_ANDROID) {
// register for a token
FirebaseCloudMessaging.registerForPushNotifications();
} else {
// iOS
onToken(e);
}
},
error: function(e) {
Ti.API.error(e);
},
callback: function(e) {
// Fired for all kind of notifications (foreground, background & closed)
Ti.API.info(e.data);
}
});
}
function onToken(e) {
// new device is registered
if (OS_ANDROID) {
Ti.API.info("New token", e.fcmToken);
} else {
if (FirebaseCloudMessaging != null) {
Ti.API.info("New token", FirebaseCloudMessaging.fcmToken);
}
}
}
// Check if token is already available.
if (FirebaseCloudMessaging.fcmToken) {
Ti.API.info('FCM-Token', FirebaseCloudMessaging.fcmToken);
} else {
Ti.API.info('Token is empty. Waiting for the token callback ...');
}
// Subscribe to a topic.
FirebaseCloudMessaging.subscribeToTopic('testTopic');
Example to get the the resume data/notification click data on Android:
const handleNotificationData = (notifObj) => {
if (notifObj) {
notifData = JSON.parse(notifObj);
// ...process notification data...
FirebaseCloudMessaging.clearLastData();
}
}
// Check if app was launched on notification click
const launchIntent = Ti.Android.rootActivity.intent;
handleNotificationData(launchIntent.getStringExtra("fcm_data"));
Ti.App.addEventListener('resumed', function() {
// App was resumed from background on notification click
const currIntent = Titanium.Android.currentActivity.intent;
const notifData = currIntent.getStringExtra("fcm_data");
handleNotificationData(notifData);
});
Check https://firebase.google.com/docs/cloud-messaging/server or frameworks like https://github.com/kreait/firebase-php/
You can use Parse with this module: timanrebel/Parse#59 in combination with Firebase. You include and configure both modules and send your deviceToken to the Parse backend.
If you send a push over e.g. Sashido you can either send a normal text or a json with:
{"alert":"test from sashido", "text":"test"}
With the JSON you can set a title/alert and the text of the notification.
cd ios
ti build -p ios --build-only
cd android
ti build -p android --build-only
(c) 2017-Present by Hans Knöchel & Michael Gangolf