Titanium

With the XtremePush module for Titanium you can add XtremePush to both iOS and Android apps built with Titanium.

Platform Specific Information

XtremePush supports push notifications for iOS devices via Apples's Push Notification Service (APNs for short). And push notifications for Android devices via Google’s GCM (Google Cloud Messaging for Android) service. This page contains Titanium specific instructions but It is also recommended you read the native documentation for these platforms. 

This includes information on importing the SDKs, initialising the core integration and obtaining and uploading iOS and Android credentials for Push Notifications to the platform.

Advanced features include: tagging of events, custom push notification handling and location services can also be found in the SDKs section.

Note: the max Android level that should be targeted in the app is 25.

XtremePush Titanium SDK Setup

First, download the current Titanium module here. This zip file contains the module.

Next you must add the XtremePush Titanium module to your Titanium installation on your development machine if you have not already done so.

Mac OS X

If you are using Mac OS X copy the modules folder from the distribution zip file into the ~/Library/Application Support/Titanium folder and allow it to merge

Windows

If you are running Windows copy the modules folder from the distribution zip file into the C:\ProgramData\Titanium folder allow it to merge

Linux

If working on the Linux copy the modules folder from the distribution zip file into the ~/.titanium folder allow it to merge

Add Xtremepush to your Project in TitaniumStudio

When you have added the modules to your Titanium SDK installation you can use XtremePush in your project.

Modify the tiapp.xml

Import the XtremePush module into your project by double clicking your projects 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,

XtremePush User Account Home

and selecting XtremPush from the drop down list

XtremePush User Account Home

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

XtremePush User Account Home

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

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

For details on how to connect your iOS app to the xtremepush platform and where to get the XTREME_PUSH_APP_KEY consult the iOS docs here.

If you are adding adding location services make sure to include NSLocationWhenInUseUsageDescription to the plist, in iOS 8.0 and later this is required to Specify the reason for accessing the user’s location information.


<plist>
<dict>
...
<key>NSLocationAlwaysUsageDescription</key>
<string>YOUR APPS reason for using location e.g. We use your 
location to find nearby parking spaces. </string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>YOUR APPS reason for using location e.g. We use your 
location to find nearby parking spaces. </string>
</dict>
</plist>
</ios>

For details on how to connect your Android app to the xtremepush platform and where to get the XTREME_PUSH_APP_KEY and your GOOGLE_PROJECT_NUMBER consult the Android docs here.

You must also add the following permissions, android services, receivers and activities under the application tag as required:

Example manifest showing permissions and services used by Xtremepush


<android xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
        <manifest>
            <uses-sdk android:targetSdkVersion="23"/>
            <!-- 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>
                <!-- REQUIRED FOR INBOX FEATURE -->
                <activity android:configChanges="orientation|screenSize"
                    android:label="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="ie.imobile.extremepush.ui.temptask"/>
                <service android:name="ie.imobile.extremepush.NotificationOnClickHandlerService"/>
                <activity android:exported="false" android:name="ie.imobile.extremepush.ui.WebViewActivity"/>
                <!-- REQUIRED FOR LOCATION SERVICES -->
                <service android:name="ie.imobile.extremepush.location.ProxymityAlertReceiver"/>
                <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: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>
                <receiver android:exported="true"
                    android:name="com.google.android.gms.gcm.GcmReceiver" android:permission="com.google.android.c2dm.permission.SEND">
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                        <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
                        <category android:name="."/>
                    </intent-filter>
                </receiver>
                <service android:exported="false" android:name="ie.imobile.extremepush.google.GCMListenerService">
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                    </intent-filter>
                </service>
                <meta-data android:name="com.google.android.gms.version" android:value="9683000"/>
                <!-- REQUIRED FOR IBEACON -->
                <receiver android:name="org.altbeacon.beacon.startup.StartupBroadcastReceiver">
                    <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: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"/>
                <meta-data
                    android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyDQ_KVhG3gQR5rg89PrjWTQdly0VxibXQI"/>
            </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: {
         locationsEnabled: true
      },
      android: {
         gcmProjectNumber: "YOUR_GCM_PROJECT_NUMBER",
         geoEnabled: false,
         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 would then need to register the app with the XtremePush servers as follows:


Ti.Network.registerForPushNotifications;

//XtremePush Callback Functions
var onRegister = function(e) {
	var success = e.success;
	// always true
	var errorCode = e.code;
	// always 0
	var deviceToken = e.deviceToken;

	Ti.API.debug("xpush app.js_onRegister - Successfully registered with deviceToken " + deviceToken);
};

var onRegistrationError = function(e) {
	var success = e.success;
	// always false
	var errorCode = e.code;
	var error = e.error;
	// localized error message

	Ti.API.debug("xpush app.js_onRegistrationError - Registration error: " + errorCode + " - " + error);
};

var onReceive = function(e) {
	var inBackground = e.inBackground;
	var notification = e.data;
	Ti.API.debug("xpush received while Activity is running: " + notification);

	// Call push handler function with data from message
	// handlePush(notification.alert);
};

Because of Titanium's new 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. Here is a full sample index.js. $.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);
}

//XtremePush Callback Functions
var onRegister = function(e) {
	var success = e.success;
	// always true
	var errorCode = e.code;
	// always 0
	var deviceToken = e.deviceToken;

	Ti.API.debug("xpush app.js_onRegister - Successfully registered with deviceToken " + deviceToken);
};

var onRegistrationError = function(e) {
	var success = e.success;
	// always false
	var errorCode = e.code;
	var error = e.error;
	// localized error message

	Ti.API.debug("xpush app.js_onRegistrationError - Registration error: " + errorCode + " - " + error);
};

var onReceive = function(e) {
	var inBackground = e.inBackground;
	var notification = e.data;
	Ti.API.debug("xpush received while Activity is running: " + notification);

	// Call push handler function with data from message
	// handlePush(notification.alert);
};

$.index.open();

Build your app for iOS or Android and then send your first push using the appropriate instructions:

  • Sending your first push notification

Xtremepush Callback Functions

MessageResponseCallback, deeplinkCallback,  and inboxBadgeCallback are JavaScript functions defined in a JavaScript file of your project. After created you have to define them in the registerXtremePush function as example:

 

messageResponseCallback: messageResponseCallbackFunction,

      inboxBadgeCallback: inboxBadgeCallbackFunction,

      deeplinkCallback: onDeeplinkReceived,

 

They are called to be executed in special cases as explained below:

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 either present | click | dismiss

  • present - when a push notification is receved 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. It does multiple things:

  • 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

note: Every message sent in the campaigns associated with the example below, includes a payload key 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

happens when the badge number updates. The badge number is checked when:

  • New push message arrives
  • Application is started
  • Inbox window is closed

An example is shown below


var inboxBadgeCallbackFunction = function(xp) {
   //do something with message
   alert('Inbox badge update with number: ' + JSON.stringify(xp)); 
};

 

deeplinkCallback

happens when a message with the click action 'Go to deeplink' is clicked. 

An example is shown below:


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

 

Foreground Notification Handling

It is important to define the right 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.

Screen_Shot_2017-11-13_at_11.49.21.png

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

 

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:

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" + 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.

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.