Titanium

Use the Xtremepush SDK to integrate your Titanium apps with the platform

With the Xtremepush module for Titanium, you can add Xtremepush to both iOS and Android apps quickly.

Make sure your mobile apps are added to Xtremepush, following the guides for Android and iOS.

Add the Xtremepush Titanium files

Download the Titanium module from the Titanium SDK releases page.

Copy the modules folder from the download into the directory shown below for your respective system, and allow it to merge.

~/Library/Application Support/Titanium
C:\ProgramData\Titanium
~/.titanium

Modify the tiapp.xml

Import the Xtremepush module into your project by opening your project's tiapp.xml in TitaniumStudio. You can add the module via the TiApp editor UI by clicking the green add button next to the list of modules,

950

and selecting Xtremepush from the drop down list

600

you will see Xtremepush in the list of modules if you have successfully added it.

431

You can also add the module by editing tiapp.xml via the raw XML editor.

Note: For android apps, due to Xtremepush's dependency on play-services, you will also need to add the ti.playservices module, in the same way you added the Xtremepush module outlined above.

iOS

<modules>
...
<module platform="android">com.xtremepush.xtremepush</module>
<module platform="iphone">com.xtremepush.xtremepush</module>
</modules>

You must follow the steps under Add description for CoreBluetooth in the Integrate the iOS SDK guide, to add the required CoreBluetooth description.

If you are also enabling push notifications, you will need to set up your Apple push certificates and add the notifications handling methods described in the iOS push notifications guide.

If you are adding adding location services, you will need to add the usage descriptions by following the iOS location permissions guide. If you are using beacons you will also need to add the bluetooth usage message described in the beacons section in the same guide.

Additionally you will need to add the bluetooth flag to your register.json in the iOS node:

ios: {
    locationsEnabled: true,
    beaconsEnabled: true,
},

Android

Follow the steps in the guide for Android push notifications to get the configuration values and google-services.json file.

In native android, or another framework that uses the gradle build tool you can add a plugin which automatically migrates values from the google-services.json file to the app resources. Titanium requires the configuration values to be manually set from the configuration file.

In your project, edit the file platform/android/res/values/values.xml, creating it if it does not already exist:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <! -- Present in all applications -->
    <string name="google_app_id" translatable="false">1:312123...:android:...</string>

    <! -- Present in applications with the appropriate services configured 
    <string name="gcm_defaultSenderId" translatable="false">312123...</string>
    <string name="default_web_client_id" translatable="false">312123...-860....apps.googleusercontent.com</string>
    <string name="google_api_key" translatable="false">AIza..</string>
    <string name="project_id" translatable="false">my_project...</string>
    ...

</resources>

The values for the keys in the XML can be found in the google-services.json file in these locations:

XML keyLocation in google-services.json
google_app_id{YOUR_CLIENT}/client_info/mobilesdk_app_id
gcm_defaultSenderIdproject_info/project_number
default_web_client_id{YOUR_CLIENT}/oauth_client/client_id (client_type == 3)
ga_trackingId{YOUR_CLIENT}/services/analytics-service/analytics_property/tracking_id
firebase_database_urlproject_info/firebase_url
google_api_key{YOUR_CLIENT}/api_key/current_key
google_crash_reporting_api_key{YOUR_CLIENT}/api_key/current_key
project_idproject_info/project_id

Now you add the Xtremepush module and ti.playservices to your app:

491

Edit the tiapp.xml file to add the following to the android section:

<android xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
        <manifest>
            <uses-sdk android:targetSdkVersion="26"/>
            <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
            <!-- REQUIRED for XtremePush -->
            <uses-permission android:name="android.permission.INTERNET"/>
            <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
            <!-- Keeps the processor from sleeping when a message is received. -->
            <uses-permission android:name="android.permission.WAKE_LOCK"/>
            <!-- REQUIRED PERMISSIONS for GCM (Push Notifications) -->
            <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
            <!-- GCM requires a Google account. -->
            <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
            <!-- This app has permission to register with GCM and receive message -->
            <permission android:name=".permission.C2D_MESSAGE" android:protectionLevel="signature"/>
            <uses-permission android:name=".permission.C2D_MESSAGE"/>
            <!-- The two elements above ensure that only this application can receive the messages and registration result -->
            <!-- OPTIONAL XtremePush settings-->
            <!-- REQUIRED FOR GEO-LOCATION-->
            <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
            <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
            <!-- REQUIRED FOR IBEACON -->
            <uses-permission android:name="android.permission.BLUETOOTH"/>
            <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
            <!-- REQUIRED IF you support iBeacon and your app must support devices that don't support BLE -->
            <uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
            <application>
                <activity android:configChanges="orientation|screenSize"
                    android:label="@string/title_activity_inbox"
                    android:name="ie.imobile.extremepush.ui.InboxActivity" android:theme="@style/Theme.Transparent"/>
                <activity android:exported="false"
                    android:name="ie.imobile.extremepush.ui.OnclickPushActivity" android:taskAffinity=""/>
                <service android:name="ie.imobile.extremepush.NotificationOnClickHandlerService"/>
                <activity android:exported="false" android:name="ie.imobile.extremepush.ui.WebViewActivity"/>
                <activity android:exported="false"
                    android:label="Locations are not available"
                    android:name="ie.imobile.extremepush.ui.LocationDialogActivity" android:theme="@android:style/Theme.Dialog"/>
                <!-- REQUIRED FOR GEO LOCATION SERVICES -->
                <service android:name="ie.imobile.extremepush.location.GeoLocationService"/>
                <!-- REQUIRED FOR IBEACON -->
                <service android:enabled="true" android:exported="false" android:isolatedProcess="false" android:label="beacon" android:name="org.altbeacon.beacon.service.BeaconService"/>
              <service android:enabled="true" android:exported="false" android:name="org.altbeacon.beacon.BeaconIntentProcessor"/>
                <service android:name="ie.imobile.extremepush.beacons.BeaconLocationService"/>
                <!-- REQUIRED FOR GCM, LOCATION AND BEACON -->
                <receiver android:name="ie.imobile.extremepush.receivers.CoreBroadcastReceiver">
                    <intent-filter>
                        <action android:name="ie.imobile.extremepush.BEACON_SERVICE_STARTED"/>
                        <category android:name="."/>
                    </intent-filter>
                    <intent-filter>
                        <action android:name="android.intent.action.BOOT_COMPLETED"/>
                        <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
                        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
                    </intent-filter>
                </receiver>
                <service
                    android:name="ie.imobile.extremepush.beacons.XPBeaconJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
                <service
                    android:name="ie.imobile.extremepush.util.ImageHandlerJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
                <receiver android:exported="true" android:name="ie.imobile.extremepush.beacons.BeaconLocationReceiver"/>
                <receiver android:exported="true" android:name="ie.imobile.extremepush.location.GeoLocationBroadcastReceiver"/>
                <receiver android:exported="true" android:name="ie.imobile.extremepush.location.ProxymityAlertReceiver"/>
                <receiver android:name="ie.imobile.extremepush.receivers.XP_App_Update_Receiver">
                    <intent-filter>
                        <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
                        <category android:name="."/>
                    </intent-filter>
                </receiver>
                <service android:name="ie.imobile.extremepush.google.XPFirebaseMessagingService">
                    <intent-filter>
                        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
                    </intent-filter>
                </service>
                <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>
            </application>
        </manifest>
    </android>

Enable in Alloy application

If you are using Alloy, then you would add the following to your alloy.js file:

// Initialise XtremePush
Ti.Network.registerApp;
Alloy.Globals.xtremepush = require("com.xtremepush.xtremepush");
Alloy.Globals.xtremepush.registerApp(
   {
      appKey: "YOUR_APP_KEY",
      debugLogsEnabled: true,
      impressionsBatchingEnabled: true,
      impressionsStoreLimit: 999,
      inappMessagingEnabled: true,
      inboxBadgeCallback: inboxBadgeCallbackFunction,
      inboxEnabled: true,
      messageResponseCallback: messageResponseCallbackFunction,
      deeplinkCallback: onDeeplinkReceived,
      tagsBatchingEnabled: true,
      tagsStoreLimit: 888,
      startSessionEnabled: true,
      sessionsStoreLimit: 777,
      attributionsEnabled: true,
      foregroundNotificationsEnabled: true,    
      ios: {
         //if using location
         locationsEnabled: true,
         //if sandbox
         sandboxModeEnabled: true
      },
      android: {
         gcmProjectNumber: "YOUR_GCM_PROJECT_NUMBER",
         //if using geo
         geoEnabled: false,
         //if using beacon
         beaconsEnabled: true
      }
   });

You can see in the registration above there are three callback functions (messageResponseCallback, InboxBadgeCallback, deeplinkCallback). Examples of how to use these is shown later.

In your controller JavaScript file index.js you need to register the app with the Xtremepush servers:

Ti.Network.registerForPushNotifications;

Because of Titanium's handling of Windows and TabGroups as activities in Android, there are a number of additional options which can be set in your index.js file. In this example, $.index is the app's main TabGroup and $.b1-14 are example buttons which show some of the options available in the module.

Ti.Network.registerForPushNotifications;

var handlePush = function(exampleDataForProcessing) {
	// Handle received push data
	alert(exampleDataForProcessing);
};

var handlePushList = function(data) {
	// Handle received push data
	var pushArray = data.notifications;
	for (var i=0; i < pushArray.length; i++)
	{
		Ti.API.debug(pushArray[i]);
		handlePush(pushArray[i].alert);
	}
};

$.button0.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the trigger event button");
    Alloy.Globals.xtremepush.hitEvent("InAppCampaign");
});

$.button1.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the hit tag button");
    Alloy.Globals.xtremepush.hitEvent("tagTest");
});

$.button2.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the hit impression button");
    Alloy.Globals.xtremepush.hitImpression("ExampleImpression");
});

$.button3.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the release all button");
    Alloy.Globals.xtremepush.sendTags();
    Alloy.Globals.xtremepush.sendImpressions();
});

batching = false;
$.button4.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the toggle batching button");
	batching = !batching;
	Ti.API.debug(batching);
    Alloy.Globals.xtremepush.setTagsBatchingEnabled(batching);
    Alloy.Globals.xtremepush.setImpressionsBatchingEnabled(batching);
});

$.button5.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the getPushList button");
    Alloy.Globals.xtremepush.getPushNotifications({
    	success: handlePushList,
    	offset: 0,
    	limit: 1,
    	read: 0
    });
});

$.button6.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the markRead button");
	Alloy.Globals.xtremepush.markPushAsRead($.pushid.value);
});

$.button7.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the openInbox button");
    Alloy.Globals.xtremepush.openInbox();
});

$.button8.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the Report Message Clicked button with lastPushId = " + lastPushId);
    Alloy.Globals.xtremepush.reportMessageClicked(lastPushId);
});

$.button9.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the Report Message Clicked button with lastPushId = " + lastPushId +" and action 'test'");
	var obj = {id: lastPushId, action: "test"};
    Alloy.Globals.xtremepush.reportMessageClicked(obj);
});

$.button10.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the Report Message Dismissed button with lastPushId = "+lastPushId);
    Alloy.Globals.xtremepush.reportMessageDismissed(lastPushId);
});

$.button11.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the Show Notification button");
    Alloy.Globals.xtremepush.showNotification(lastPushId);
});

$.button12.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the set External Id button");
    Alloy.Globals.xtremepush.setExternalId($.pushid.value);
});

$.button13.addEventListener('click', function(e) {
	Titanium.API.debug("You clicked the set Hit Event With Value button");
	
	var stringOrHash = {0: "number0", 1: "number1"};
	//var stringOrHash = "numbers";
	var obj = {title: "tagString", value: stringOrHash};
    Alloy.Globals.xtremepush.hitEventWithValue(obj);
});

// Declare XtremePush in alloy.js as shown here:
// Alloy.Globals.xtremepush = require("com.xtremepush.xtremepush");

var OS_ANDROID = Ti.Platform.getOsname() === "android";
if (OS_ANDROID) {
	var onRotation = function(e){
		var rotation = false;
		switch(e.orientation) {
	    case Ti.UI.LANDSCAPE_RIGHT:
	        Ti.API.info("LANDSCAPE_RIGHT");
	        rotation = true;
	        break;
	    case Ti.UI.LANDSCAPE_LEFT:
	        Ti.API.info("LANDSCAPE_LEFT");
	        rotation = true;
	        break;
	    case Ti.UI.UPSIDE_PORTRAIT:
	        Ti.API.info("UPSIDE_PORTRAIT");
	        rotation = true;
	        break;
	    case Ti.UI.PORTRAIT:
	        Ti.API.info("PORTRAIT");
	        rotation = true;
	        break;
	    default:
	        Ti.API.info("Unknown!!");
	    }
	    if(rotation)
	    	Alloy.Globals.xtremepush.onRotation();
	};
	
	$.index.orientationModes = [ 
	    Titanium.UI.PORTRAIT, 
	    Titanium.UI.UPSIDE_PORTRAIT,
	    Titanium.UI.LANDSCAPE_LEFT,
	    Titanium.UI.LANDSCAPE_RIGHT
	];
	
	Ti.Gesture.addEventListener('orientationchange', onRotation);
}

$.index.open();

👍

Make sure you set the user ID

It is recommended that at this stage you use our SDK method to set user IDs by following our dedicated guide to ensure devices can be associated and targeted in your campaigns by your own unique identifier.

Setting Notification Icon in Android

There is a key that can be set in register.json called setIcon. If set, the program will attempt to find and use iconfilenamewithoutextension.png in the platform/android/res/drawable directory and will also search for a color entry with the same name in any of the XML files in the platform/android/res/values directory to use as a background colour behind the icon.

setIcon: "iconFileNameWithoutExtension",

Android encourages you to set an icon that is in-keeping with their design guidelines. Further information ca be found in the guide for Android notification icons.

Xtremepush callback functions

messageResponseCallbackdeeplinkCallback, and inboxBadgeCallback are JavaScript functions defined in a JavaScript file of your project. After creating, you have to define them in the registerXtremePush function:

messageResponseCallback: messageResponseCallbackFunction,

inboxBadgeCallback: inboxBadgeCallbackFunction,

deeplinkCallback: onDeeplinkReceived,

messageResponseCallback

var messageResponseCallbackFunction = function(xp) {   
   if(xp.response.type === "present"){
   		alert("receive");
   } else if (xp.response.type === "click"){
   		alert("click");
   } else if (xp.response.type === "dismiss"){
   		alert("dismiss");
   }  
};

The response.type variable shown above can be one of specific values:

  • present - when a push notification is received and the app is in the foreground
  • click - when a message is clicked
  • dismiss - when a message is dismissed

Below is a complete example of custom notification handling, which:

  • shows a custom dialog when a push message is received in foreground,
  • opens an article page when a message is clicked,
  • saves information when one of the message buttons is clicked.

(Each message sent in the campaigns associated with the example, include a custom payload for articleId)

var messageResponseCallbackFunction = function(xp) {   
	Ti.API.info(''+JSON.stringify(xp));
    if (xp.response.type === "present") {
        openArticle(xp.message.articleId);

        //when the user clicks on a message 
    } else if (xp.response.type === "click") {
        //default click action
        if (!xp.response.hasOwnProperty('action')) {
            openArticle(xp.message.articleId);

            //action for specific button click
        } else {
            if (xp.response.action === "like") {
                likeArticle(xp.message.articleId);
            } else if (xp.response.action === "share") {
                shareArticle(xp.message.articleId);
            }
        }
        //show alert if dismiss button click
    } else if (xp.response.type === "dismiss") {
        alert("message dismiss");
    } 
};

inboxBadgeCallback

This is called when the badge number updates. The badge number is checked when:

  • new push message arrives
  • application is started
  • inbox window is closed
var inboxBadgeCallbackFunction = function(xp) {
   //do something with message
   alert('Inbox badge update with number: ' + JSON.stringify(xp)); 
};

deeplinkCallback

This is called when a message with the click action Go to deeplink is clicked. 

var onDeeplinkReceived = function(xp) {
    alert('onDeeplinkReceived called in alloy.js with data:'+JSON.stringify(xp));
};

Foreground notification handling

It is important to define the correct behaviour for the situation when a push notification is received in foreground. You don't want to interrupt the user workflow, but still be delivering important information to the user.

The default behaviour on both iOS and Android is to show OS style notification. But this can be changed, by adding the payload with key foreground and value false to your campaign.

607

Now when the push is received, should the app be in the foreground, the notification will not be displayed.

If you wish to change the default behaviour to not show notifications when app is open, in the register function you can use the following:

foregroundNotificationsEnabled: false

Retrieving your Xtremepush ID

Now that your app is configured for mobile analytics and sending push notifications the final basic feature of Xtremepush is retrieving your Xtremepush ID. This can be accomplished by calling the deviceInfo method:

Alloy.Globals.xtremepush.deviceInfo

This method returns your device's ID as obtained from Xtremepush server. If your device has not received an ID then it has not successfully registered and there is an issue with your integration. If for example you want to quickly output the the device ID to the debug area in TitaniumStudio you would use it like this:

Ti.API.debug("deviceInfo" + Alloy.Globals.xtremepush.deviceInfo);

If you successfully retrieve the ID it can be used to identify your device on the platform and to send a push notification to just that device.

User management

Set primary user on platform: 

Alloy.Globals.xtremepush.setUser("");

Set temporary user on platform:

Alloy.Globals.xtremepush.setTempUser("");