Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 28 Next »

Technical Documentation


 The Phunware Mobile Engagement SDK allows you to easily integrate location based messaging and notifications into your app.  


When your app first starts up, you need to initialize the Mobile Engagement SDK using the Engagement.Builder.  This is where you provide your AppId, Access Key, and Signature Key from the Maas Portal.  All production apps should use the production environment.

GCM Registration

When setting up your app, you also need to register with GCM in order to receive push notifications from the Mobile Engagement backend. To do so, follow the steps that can be found in Googles official documentation at:

Note: All manfiest changes required in the setup have been done in the SDK's AndroidManfiest file.


By default, the Phunware Mobile Engagement SDK will log to the Android system log and a log file, and will not log in production environments.  This is entirely configurable using the builder's addLogger(Logger logger) method.

You can easily create your own Logger implementation that will do whatever you'd like with log messages, or use one of the built in Loggers.

public class CrashReportingLogger {

  @Override public void v(String tag, String message, Throwable t) {
    // no op

  @Override public void i(String tag, String message, Throwable t) {
    // no op

  @Override public void d(String tag, String message, Throwable t) {
    // no op

  @Override public void w(String tag, String message, Throwable t) {
    // no op

  @Override public void e(String tag, String message, Throwable t) {
    CrashReportingLibrary.logError(tag, message, throwable);

  @Override public void wtf(String tag, String message, Throwable t) {
    CrashReportingLibrary.logError(tag, message, throwable);

This allows you to easily use or discard log messages as you see fit.


The Phunware Mobile Engagement SDK is broken up into 3 managers, LocationManagerMessageManager and AttributeManager.  Once the Engagement SDK has been initialized, these can be accessed using static accessors on the LocationMessaging class.

MessageManager messages = Engagement.messageManager();

If you ensure the Mobile Engagement SDK is initialized in your Application's onCreate method, then you'll be able to access the managers from anywhere within your app (except ContentProviders).


The LocationManager is your entry point into the Location components of the Mobile Engagement SDK.  Through it you can start or stop the Location services, access current geozone state, and register for notifications when geozone state changes.

Starting and Stopping Location Services

By default, the Mobile Engagement SDK will monitor geozones and notify the server when the user enters or leaves them.  App developers may want to allow users to opt out of location tracking, or user may deny the app location permissions on newer versions of Android, so it's important that app developers are able to start and stop the service.

To manage the location state, simply call Engagement.locationManager().start() or Engagement.locationManager().stop().  This setting will be persisted across app restarts and device reboots.

If your app targets API level 21 or higher, you will need to manage permissions at runtime.  This means disabling the LocationManager until the user grants the ACCESS_FINE_LOCATION permission.

public class MainActivity extends AppCompatActivity {
  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
  private void checkPermissions() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
      // Stop the LocationManager until we have permission
      if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
        // Show an explanation to the user of why the permission is important
      } else {
            new String[]{ Manifest.permission.ACCESS_FINE_LOCATION },
  public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
    switch(requestCode) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
          // The user granted permission, so start the LocationManager

The same starting and stopping of the LocationManager can be applied if you explicitly allow the user to opt out of location services.

Access Geozone State

The LocationManager can be used to get the current state of Geozones.  This can allow you to use the known Geozones to populate a map of locations, or determine whether the user is currently inside a location.

All calls to get Geozone information from the LocationManager are asynchronous, so you need to provide a Callback and display appropriate UI.

public class MyStoreFragment extends Fragment {
  @Override public void onActivityCreated(Bundle savedInstanceState) {
    final long geozoneId = getArguments().getLong(GEOZONE_ID);
    // Show the loading view until data has been loaded
    // Load details about the selected Geozone
    Engagement.locationManager().getGeozone(geozoneId, new Callback<Geozone>() {
        @Override public void onSuccess(Geozone data) {
        @Override public void onFailed(Throwable e) {
          Log.e(TAG, "Failed to load geozone detail.", e);
    // Check if the user is currently inside the geozone, and update UI accordingly
    Engagement.locationManager().getInsideGeozones(new Callback<List<Geozone>>() {
        @Override public void onSuccess(List<Geozone> data) {
        @Override public void onFailed(Throwable e) {
          Log.e(TAG, "Failed to load inside geozones.", e);

Register for Geozone State Changes

You may want to register to be notified when the user enters or leaves geozones, or when new geozones are added or removed from the list.  There are two ways to do this with the Phunware Mobile Engagement SDK, depending on whether you need to be notified when your app is in the foreground or background.

Foreground Geozone Notifications

To be notified of geozone state changes when your app is in the foreground, for instance to update a your app's view state when the user enters a location, you can add one or more LocationListeners to the LocationManager.  This listener will be notified any time the state of Geozones changes while it is still registered.

public class InStoreCouponView extends View implements LocationListener {
  private Long geozoneId;
  @Override public void onAttachedToWindow() {
  @Override public void onDetachedFromWindow() {
  @Override public void onZoneEntered(Long id) {
    if (id == geozoneId) {
  @Override public void onZoneExited(Long id) {
    if (id == geozoneId) {

Be sure to remove the LocationListener when it is no longer needed to avoid leaks.

Background Geozone Notifications

It's also possible to register for notifications of Geozone events when the app isn't running.  This can be useful if you want to process events with a service or add local notifications.

In order to receive background notifications of Geozone events, you simply need to register an IntentService in your manifest that responds to at least one of the following intent filters:


Your IntentService will then be started and notified for any Geozone events you are interested whether your app is running or not.


The MessageManager allows you to interact directly with the LocationMessaging messages, including retrieving and modifying messages, and registering to be notified of message updates.

The Public Interface

To retrieve an instance of MessageManager, simply call `LocationMessaging.messageManager()` after initializing the LocationMessaging library.

public interface MessageManager {
	void addMessageListener(@NonNull MessageListener);
	void removeMessageListener(@NonNull MessageListener);
	void getMessages(Callback<List<Message>> callback);
    void getAllMessages(Callback<List<Message>> callback);
    void getUnreadMessages(Callback<List<Message>> callback);
	void findMessageById(@NonNull String id, Callback<Message> callback);
	void setMessageDeleted(@NonNull String id, Callback<Message> callback);
	void setMessageRead(@NonNull String id, Callback<Message> callback);

Listening for Message Events

The MessageManager accepts multiple MessageListener objects which can be notified of events, like when a message is received, deleted or updated.  This allows app developers to manage foreground components when message status changes, like updating an unread message count, or changing the display of messages in a list based on their status.

public interface MessageListener {
	void onMessageAdded(MessageManager manager, Message message);
	void onMessageDeleted(MessageManager manager, Message message);
	void onMessageUpdated(MessageManager manager, Message message);

Receiving Background Events

All of the same events that can be consumed by a listener can also be consumed by a service so that app developers don't need to keep anything retained in memory to receive updates.  By defining a non-exported service, app developers can have the app woken up when message events happen.

<manifest ...>
    <service android:name=".MyMessageListenerService" android:exported="false">
        <action android:name="com.phunware.locationmessaging.MESSAGE_ADD" />
        <action android:name="com.phunware.locationmessaging.MESSAGE_DELETE" />
        <action android:name="com.phunware.locationmessaging.MESSAGE_UPDATE" />

Setting exported to false means that the service is not accessible to any other apps on the system, reducing potential security vulnerabilities and ensuring the an app developer's app only receives messages destined for it.

The app developer can define any or all of the following actions:

  • com.phunware.locationmessaging.MESSAGE_ADD
  • com.phunware.locationmessaging.MESSAGE_DELETE
  • com.phunware.locationmessaging.MESSAGE_UPDATE

By only subscribing to events that the developer cares about, we limit the amount of code that is needlessly run.

While the service implementation will be a standard Android IntentService, the SDK will provide a convenient abstract class that will take care of determining the appropriate action and also retrieving the Message from the Intent.
public class MyMessageListenerService extends MessageListenerService {
  public MyMessageListenerService() {
  @Override public void onMessageAdded(Message message) {
	// ...

  @Override public void onMessageDeleted(Message message) {
	// ...

  @Override public void onMessageUpdated(Message message) {
	// ...

Customizing Notifications

User notifications are entirely handled by the SDK, so you don't need to worry about when to show what notifications.  There are times, however, when you may want to customize the notification message, perhaps to personalize it or make it more relevant to the user.  This can be accomplished by implementing a bound service.

 <manifest ...>
    <service android:name=".MyNotificationEditService" android:exported="false">
        <action android:name="com.phunware.engagement.EDIT_NOTIFICATION" />
public class MyNotificationEditService extends NotificationCustomizationService {
  @Override public void editNotification(Notification.Compat.Builder notificationBuilder) {



The AttributeManager allows you to interact directly with the Mobile Engagement attributes, including retrieving and modifying attributes, and retrieving attribute metadata.
public interface AttributeManager {
    void getAttributeMetadata(Callback<List<AttributeMetadataItem>> callback);
    void getProfileAttributes(Callback<ProfileAttribute> callback);
    void updateProfileAttribute(Map<String, Object> attributes,
            Callback<ProfileAttribute> callback);


Deep Linking

Deep linking into the SDK can be done taking advantage of met data sent on a campaign. For example:

First, register your intent filter in the AndroidManifest.xml where you want your intents to come in:

    android:label="@string/app_name" >
    	<action android:name="android.intent.action.VIEW" />
    	<category android:name="android.intent.category.DEFAULT" />
    	<data android:mimeType="engagement/message" />


Then, inside of the Activity that you want to receive these intents, handle the message metadata as you see fit.

Example meta data linking
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
switch (getIntent().getAction()) {
    case Intent.ACTION_VIEW:
        trans.replace(, new ConfigFragment());

        Message intentMessage = getIntent().getParcelableExtra(MessageManager.EXTRA_MESSAGE);,
		// Get metadata off of message to find out where to link to
		// It's important to know that we can send more than one MessageMetadata object on a message so when
		// we call intentMessage.metaData, we get a list of metadata objects. For this example,
		// we will just grab the first for examples sake
		MessageMetadata deepLinkMessageMetadata = intentMessage.metaData.get(0);
		// In this example, we assume the value is the fully qualified class name that matches
		// the intent filter of the activity we want to start such as 'packagename.classname'. 
		// If using this way make sure you fully qualify a valid class name.
		String metaDataValue = deepLinkMessageMetadata.value();

		Intent intent = new Intent(this, Class.forName(metaDataValue));
		// Handle default case

  • No labels