Use the native Firebase SDK (iOS/Android) in Axway Titanium. This repository is part of the Titanium Firebase project.
- Requirements
- Download
- iOS notes
- Android Notes
- API: Methods, Properties, Events
- Example
- Build from source
- The Firebase Core module.
The options
googleAppID
andGCMSenderID
are required for Android, orfile
(e.g.GoogleService-Info.plist
) for iOS. - iOS: Titanium SDK 7.3.0+ (if you use SDK < 7.3.0, please use Ti.FirebaseCloudMessaging v1.1.0)
- Android: Titanium SDK 7.0.0+, Ti.PlayServices module
- Read the Firebase-Core install part if you set up a new project.
To register for push notifications on iOS, startin in 2.0.0, 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
Merge the following keys to the <android>
section of the tiapp.xml in order to use GCM (not needed for FCM).
<android xmlns:android="http://schemas.android.com/apk/res/android">
<manifest>
<application>
<service android:name="MY_PACKAGE_NAME.gcm.RegistrationIntentService" android:exported="false" />
<receiver android:name="com.google.android.gms.measurement.AppMeasurementReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.google.android.gms.measurement.UPLOAD" />
</intent-filter>
</receiver>
<service android:name="MY_PACKAGE_NAME.gcm.GcmIntentService" android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service android:name="MY_PACKAGE_NAME.gcm.GcmIntentService" android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.SEND" />
</intent-filter>
</service>
<service android:name="MY_PACKAGE_NAME.gcm.GcmIDListenerService" android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
</application>
</manifest>
</android>
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
You need to add the google_app_id to /app/platform/android/res/values/strings.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="google_app_id">1:11111111111:android:aaaaaaaaa</string>
</resources>
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 a 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.
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/notification_icon.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/notification_icon.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/notification_icon.png"
convert "$ICON_SOURCE" -resize 48x48 "app/platform/android/res/drawable-xhdpi/notification_icon.png"
convert "$ICON_SOURCE" -resize 36x36 "app/platform/android/res/drawable-hdpi/notification_icon.png"
convert "$ICON_SOURCE" -resize 24x24 "app/platform/android/res/drawable-mdpi/notification_icon.png"
else
echo "No 'notification_icon.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 > Android O you need to create a second channel. The default channel will always use the default notification sound on the device!
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.
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.
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).
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)
error
(Android only)
error
(String): Error during token registration
// Import core module
var core = require('firebase.core');
// Configure core module (required for all Firebase modules).
core.configure({
GCMSenderID: '...',
googleAppID: '...', // Differs between Android and iOS.
// file: 'GoogleService-Info.plist' // If using a plist (iOS only).
});
// Important: The cloud messaging module has to imported after (!) the configure()
// method of the core module is called
var fcm = require('firebase.cloudmessaging');
// Called when the Firebase token is registered or refreshed.
fcm.addEventListener('didRefreshRegistrationToken', function(e) {
Ti.API.info('Token', e.fcmToken);
});
// Called when direct messages arrive. Note that these are different from push notifications.
fcm.addEventListener('didReceiveMessage', function(e) {
Ti.API.info('Message', e.message);
});
// Android-only: For configuring custom sounds and importance for the generated system
// notifications when app is in the background
if (OS_ANDROID) {
// fcm.createNotificationChannel({
// sound: 'warn_sound',
// channelId: 'default',
// channelName: 'General Notifications',
// importance: 'high'
// })
var channel = Ti.Android.NotificationManager.createNotificationChannel({
id: 'default',
name: 'Default channel',
importance: Ti.Android.IMPORTANCE_DEFAULT,
enableLights: true,
enableVibration: true,
showBadge: true
});
// if you use a custom id you have to set the same to the `channelId` in you php send script!
fcm.notificationChannel = channel;
}
// Register the device with the FCM service.
fcm.registerForPushNotifications();
// Check if token is already available.
if (fcm.fcmToken) {
Ti.API.info('FCM-Token', fcm.fcmToken);
} else {
Ti.API.info('Token is empty. Waiting for the token callback ...');
}
// Subscribe to a topic.
fcm.subscribeToTopic('testTopic');
if (OS_ANDROID){
// display last data:
Ti.API.info("Last data: " + fcm.lastData);
}
To test your app you can use this PHP script to send messages to the device/topic:
<?php
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = [
'to' => '/topics/testTopic', // or device token
'notification' => [
'title' => 'TiFirebaseMessaging',
'body' => 'Message received'
],
'data' => [
'key1' => 'value1',
'key2' => 'value2'
]
];
$headers = [
'Authorization: key=SERVER_ID_FROM_FIREBASE_SETTIGNS_CLOUD_MESSAGING', 'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
echo $result;
curl_close($ch);
?>
Run it locally with php filelane.php
or put it on a webserver where you can execute PHP files.
<?php $url = 'https://fcm.googleapis.com/fcm/send';
$fields = array (
'to' => "TOKEN_ID",
// 'to' => "/topics/test",
/* 'notification' => array (
"title" => "TiFirebaseMessaging",
"body" => "Message received 📱😂",
"timestamp"=>date('Y-m-d G:i:s'),
),*/
'data' => array(
"test1" => "value1",
"test2" => "value2",
"timestamp"=>date('Y-m-d G:i:s'),
"title" => "title",
"message" => "message",
"big_text"=>"big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text big text even more text ",
"big_text_summary"=>"big_text_summary",
"icon" => "http://via.placeholder.com/150x150",
"image" => "http://via.placeholder.com/350x150", // won't show the big_text
"force_show_in_foreground"=> true,
"color" => "#ff6600",
"channelId" => "default" // or a different channel
)
);
$headers = array (
'Authorization: key=API_KEY',
'Content-Type: application/json'
);
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec ( $ch );
echo $result."\n";
curl_close ( $ch );
?>
cd ios
appc run -p ios --build-only
Note: When building for Android, make sure you have the firebase.core module installed globally (
~/Library/Application Support/Titanium/modules/android/firebase.core
). Otherwise, the firebase-iid library will not be referenced properly.
cd android
appc run -p android --build-only
(c) 2017-Present by Hans Knöchel & Michael Gangolf