Monday Aug 24, 2015

New Features : Oracle Mobile Security Suite Integration in Oracle MAF 2.1.3

Introduction 

MAF 2.1.3 provides a tighter integration with Oracle Mobile Security Suite (OMSS) 11.1.2.3.1.This integration offers capabilities like, Android Containerization, Data Leak Protection, Data Encryption, Application Tunneling, Container Authentication and Single Sign-On. Features like Containerization, Data Leak Protection and Data Encryption are already supported on iOS from previous MAF releases.

New Features

1. Support for Android Containerization

Mobile app containerization allows customers to add a standardized security layer to native mobile apps. 

The containerization process is simple, and developers do not need to change a line of code. MAF developers just need to deploy the application to OMSS, in JDeveloper or Eclipse. During the deployment, the app is first compiled and an unsigned version of the app is generated that is intended to be signed with an enterprise distribution certificate for distribution within the company. After deployment, a wrapped APK file is generated which is signed with the signing certificates which are configured in the MAF JDeveloper / Eclipse Preferences, in the Android platform section.


Enable OMSS deployment in JDeveloper 

Enable OMSS deployment in Eclipse 


2. Data Leak Protection on Android

Once a MAF app is containerized with OMSS, IT administrators can apply various data leak protection policies and restrict how and if users can share data within the app

  • Email allowed can restrict the ability to send email from an app.

  • Instant Message allowed can restrict the ability to send Instant Message from an app.

  • Video chat allowed restricts the ability to share information via services such as FaceTime.

  • Social Share allowed restricts the ability to share information via services such as Facebook or Twitter.

  • Print allowed restricts the ability of the user to print.

  • Restrict file sharing restricts the ability of the user to share files outside the secure enterprise workspace.

  • Restrict copy/paste allows copy/paste inside the secure container, containerized apps or between containerized apps, but not to apps outside the secure enterprise workspace.

  • Redirects to container allowed prevents any app outside the Mobile Security Container workspace from redirecting a URL into the container.

  • Save to media gallery allowed prevents images, videos and audio files from being saved to media gallery and photo stores.

  • Save to local contacts allowed prevents contacts inside secure enterprise workspace apps from being saved down to native device contacts app.

  • Redirects from container allowed prevents any vApp from the Mobile Security Container workspace or containerized app from redirecting a URL outside the Mobile Security Container workspace or containerized app.

3. Data Encryption on Android

OMSS Containerization provides the ability to encrypt the data stored offline within MAF android applications. Starting with 2.1.3 this functionality is available for MAF applications as well. Encrypted data storage includes application data, including files, databases, application cache, and user preferences. Developers can use MAF encryption with OMSS containerization without having to worry about double encryption. Within a containerized application, MAF frameworks delegates encryption to the container this ensures that there are no code changes needed based on whether an app is Containerized or not. 

4. Application Tunneling

MAF 2.1.3 release provides support for application tunneling through Oracle Mobile Security Suite on both Android & iOS. Application tunneling provides a secure way to access the corporate resources behind the firewall, within a mobile client, without the need of device level VPN. Tunneling functionality allows administrators to intercept, and manage, all the requests coming from a specific MAF application. Administrators can configure the requests coming from a specific URL to go through a proxy on MSAS server. They can also either completely block the requests, or redirect the requests directly to the internet.You can find more details on how to configure application tunneling in the Web Settings section of Administrative Console Guide for Oracle Mobile Security Suite.

5. Container Authentication & Single Sign-On

When Web SSO authentication type is used in MAF apps with Oracle Access Manager and Oracle WebGate used in the back-end for authentication, the end user is not challenged for credentials in the application after Container authentication. The user identity from the Container is propagated to the App and the back-end services. SSO across multiple apps in the Container is also supported, i.e. user can login once to the Container and access all the apps in the Container with out additional authentication challenges. 

Demo

Here is a quick demo which shows all three features (Android Containerization, Data Leak Protection, and File Encryption) 

Using Oracle MAF Authentication To Access Secure Services From Oracle MCS

Oracle MAF 2.1.3 release makes it easy to authenticate against Oracle Mobile Cloud Service (MCS) and access secure data from services hosted on MCS.  Below are the steps to configure MAF application to authenticate against MCS:

1. Create Login Connection : In maf-application.xml go to security tab and create a login server connection. Select authentication type as "HTTP Basic" as shown below 

create login connection

create login connection

The login server URI is of the form https://<host>:<port>/mobile/platform/users/login . You can obtain the host & port from a Mobile Backend(MBE) settings page in you MCS instance. The above URI can be used for any MBE in the MCS instance.

2.  Configure Custom Header : During authentication MCS requires a custom header with the MBE id to be injected with the request. Configure the header in the Custom Headers tab  as follows:

configure custom header

You can get the MBE Id from the MBE settings page in MCS. The header name should be "Oracle-Mobile-Backend-Id"

3. Configure Security Policy : Now that we have the login connection created, the next step is to create a connection to API end point on MCS.  In the Web Service Security Policies section :

  1. Create a REST/HTTP Connection to an API end point in connections.xml, in the example below it's named "fiftechnician".  
  2. Associate the "fiftechnician" connection with the login connection created in steps 1 & 2. This allows the framework to inject the user identity obtained during authentication for any service calls to the connection.    
  3. In the "Policy" column, double click on the pencil icon to launch a dialog to select the security policy to be used for the connection. Select "oracle/wss_http_token_client_policy". This policy can be used for Basic-Auth protected connections with either HTTP and HTTPS. 
configure security policy

select the correct policy :

configure security policy

The above steps would allow mobile app developers using MAF to securely access data from API hosted on MCS through simple configuration without writing any code and be assured that you are following security best practices.

Tuesday Apr 28, 2015

Oracle MAF 2.1.2 Released

Our mobile development team has been busy continuously improving the framework we provide you. Last month we released Oracle MAF 2.1.1 and this month we are releasing Oracle MAF 2.1.2. This is part of Oracle's commitment to a much faster release cycle for our mobile customers.

This new version is a minor release with no major new features, but it contain several fixes for issues you might have ran into, so check out our 2.1.2 release notes

As always, you should get the extension using the help->check for updates option in JDeveloper. 

Wednesday Apr 22, 2015

New Oracle University MAF Virtual Course : April 29 - May 1st

Looking for a way to skill-up on mobile development? Attend the Oracle Mobile Application Framework: Develop Mobile Apps course (now updated for MAF 2.1) where you'll learn how to develop real-world mobile applications that run in HTML5 on iOS or Android, access data from a variety of data sources including REST, and ensure your mobile application is secure, performant, and engaging.

Sign up today to take the course from the comfort of your own desk and spend April 29-May 1 learning how to build your organization's next great application without having to code for multiple platforms or form factors.

Follow this link to get more info


Tuesday Apr 07, 2015

How to implement iBeacon in MAF 2.1.1

Want to alert your customer to a special loyalty discount offer when they enter the menswear department in one of your retail stores?  Want to present information about a famous artist’s life when a visitor to your museum nears one of the artist’s paintings?  These are just two of the many real-world scenarios made possible by the use of iBeacon technology.

This blog post provides an introduction to iBeacon technology and a description of how to build two different MAF apps – one that pretends to be an iBeacon and another that detects iBeacons and uses the local notifications functionality provided in MAF 2.1.1 to inform the user, even when the app isn’t even running.

To deploy these apps to iOS devices you will need an iOS developer account.

What is a beacon?

A beacon is a device that is intentionally conspicuous to draw attention to a location, such as a lighthouse sitting on the edge of a cliff. 

In in the Internet of Things (or IoT), a beacon is a small electronic device that transmits a regular radio signal according to the Bluetooth v4 Low Energy spec (otherwise known as “BLE”).  A beacon typically does no more than advertise its existence by transmitting a unique identifier and can last for months on a single cell battery.

Any BLE-enabled device, such as a modern smartphone, can detect a beacon by listening for BLE-based transmissions.

Whilst the possibilities appear endless, typical applications for beacons currently include retail stores, exhibition halls, museums, places of employment and homes, where users can be alerted to information pertaining to their current location within a building.

What is (an) iBeacon?

iBeacon is a technology introduced by Apple in iOS 7 that defines a standard for how a beacon identifies itself (or “advertises”) in its BLE transmissions.  Any beacon that implements this standard can be called an iBeacon.

Most beacon manufacturers implement the iBeacon standard by default, whilst some can also be configured to use their own proprietary protocol.  It’s also possible to configure a post-2012 iOS device, or Mac running OS X Mavericks (not Yosemite), to act as an iBeacon.

Whilst the iBeacon technology is included in the iOS Core Location framework since iOS 7, any BLE-enabled device can detect iBeacons and various libraries exist for use on devices running Android 4.3 or above.

How does iBeacon work?

The iBeacon standard defines three properties that determine a beacon’s identity:

  • A proximity UUID (universally unique identifier), which is a 128-bit value that uniquely identifies one or more beacons as a certain type or from a certain organization.
  • A major value, which is a 16-bit unsigned integer that can be used to group related beacons that have the same proximity UUID.
  • A minor value, which is a 16-bit unsigned integer that differentiates beacons with the same proximity UUID and major value.

Every iBeacon must advertise a proximity UUID, whilst the advertisement of major and minor values is optional.  All beacon manufacturers allow customers to modify these values on their purchased beacons.

A typical iBeacon deployment (e.g. within a retail store chain) would see all beacons advertising the same proximity UUID, those in a particular location (e.g. a single store) advertising the same major value, and the minor values being used to uniquely identify each beacon.

When using iOS Location Services, an app wishing to detect iBeacons must start by monitoring for an iBeacon region.  A region is defined by the proximity UUID and optionally major and minor values, and can therefore represent one or more beacons.  Consider an app for a retail store chain that monitors for a region defined only by the proximity UUID.  This app will be notified when any of the retain chain’s beacons are detected.  Alternatively, if the region being monitored is defined by proximity UUID and major value, the app might only be notified when a beacon from a particular store (represented by the major value) is detected.

Once an app has been launched and the user has given permission for the app to monitor for beacons, the app will be notified when the device enters a beacon region that is being monitored, even if the app is not running and even if the device has been restarted.  If the app is not running, iOS launches the app for a short period (around 10 seconds), allowing the app to receive and react to the event.  Typically, the app fires an immediate local notification to notify the user.

When a user’s device enters a beacon region, the app can start ranging for individual beacons within the region to determine its relative proximity to each beacon.  This is used to determine when the user is in the immediate proximity of a particular beacon, so that information related to that beacon can be displayed to the user.  The relative proximity is an approximation that can be affected by physical objects including walls, water and the human body.  Most beacon manufacturers allow customers to modify the transmission power and advertising interval on their purchased beacons, so as to fine-tune the distance at which the relative proximity is considered ‘immediate’.

When iOS Location Services determines that it can no longer detect any beacons in the region, it notifies the app that the beacon region has been exited.  In practice, I’ve found that this takes around 30 seconds, but some bloggers have reported much longer times.

Libraries exist for Android that provide similar functionality to iOS Location Services, but I have not explored these (yet).

How to create an iBeacon client app

If you are an existing MAF app developer, you can follow these steps to create a MAF app that detects iBeacons.

Step 1 – Find a suitable Cordova plugin

The first thing required is a Cordova plugin to provide access to the native iBeacon functionality on iOS and mimic the same on Android.  Typing “beacon” into the Cordova plugin repository produces a few results, with the most downloaded being this plugin.  According to the readme, this plugin is suitable for both iOS and Android apps and provides the ability to fake an iBeacon advertisement on iOS devices.

Open its GitHub page and download it by clicking on the Download ZIP button.

Step 2 – Create a MAF app and add the plugin

Open JDeveloper with MAF 2.1.1 installed, create a new MAF app called BeaconDemo.

Before adding the plugin to your app, you must extract the contents of the downloaded zip file into a location that is on the same drive as your MAF app and into a folder whose path contains no spaces.  I like to extract the plugin into the source tree of the app that's using it, for example within the top-level src folder of the app. 

Open the maf-application.xml file located in Application Resources > Descriptors > ADF META-INF and select the Plugins tab.  Click on the Add Plugin button under Additional Plugins, browse to the location of the extracted plugin and click on Select.  The plugin is now added to your app.

Save all your changes.

Step 3 – Create a JavaScript interface file

The Cordova plugin interface is written in JavaScript, so we need to write some JavaScript that calls this interface.  We will also include some of the business logic in JavaScript.

Create a new JavaScript file by selecting the ViewController node in the Projects window, right click, select New > JavaScript File and enter "beacon.js" as the filename.  Enter the following code into the empty JavaScript file:

(function() {

  // Our region identifier
  var uuid = "0AC59CA4-DFA6-442C-8C65-22247851344C";
  var beaconRegion;

  function initialise() {
    beaconRegion = createRegion();
    var delegate = new cordova.plugins.locationManager.Delegate();

    // Callback for enter/exit region whilst monitoring
    delegate.didDetermineStateForRegion = function (pluginResult) {
      var options;
      if (pluginResult.state == "CLRegionStateInside") {
        // Fire local notification and start ranging from there so that ranging only
        // starts if the app is in the foreground, or the user taps on the notification
        options = {"alert":"Welcome! Thank you for entering the " +
                     pluginResult.region.identifier + " region.",
                   "sound":"SYSTEM_DEFAULT",
                   "vibration":"SYSTEM_DEFAULT",
                   "payload":{"id":pluginResult.region.identifier, "inside":true}};
        adf.mf.api.localnotification.add(options,  function() {}, function() {});
      } else if (pluginResult.state == "CLRegionStateOutside") {
        // Stop ranging immediately
        stopRanging();

        // Fire local notification
        options = {"alert":"Goodbye. Thank you for visiting the " +
                     pluginResult.region.identifier + " region.",
                   "sound":"SYSTEM_DEFAULT",
                   "vibration":"SYSTEM_DEFAULT",
                   "payload":{"id":pluginResult.region.identifier, "inside":false}};
        adf.mf.api.localnotification.add(options,  function() {}, function() {});
      }
    };

    // Callback for ranging region
    delegate.didRangeBeaconsInRegion = function(pluginResult) {
      var beacons = pluginResult.beacons;
      for (var i = 0; i < beacons.length; i++) {
        // Add to list of beacons in BeaconManager
        adf.mf.api.invokeMethod("mobile.BeaconManager", "beaconRanged",
                                beacons[i].uuid, beacons[i].major,
                                beacons[i].minor, beacons[i].proximity,
                                function() {}, function() {});
      }
    };

    // Set delegate
    cordova.plugins.locationManager.setDelegate(delegate);

    // Required in iOS 8+
    cordova.plugins.locationManager.requestAlwaysAuthorization();

    // Start monitoring by default each time the app is launched
    startMonitoring();
  }

  function createRegion() {
    // Monitor any beacons in this UUID-based region
    return new cordova.plugins.locationManager.BeaconRegion("FakeBeacon", uuid);
  }

  // Callable externally
  startMonitoring = function() {
    cordova.plugins.locationManager.startMonitoringForRegion(
      beaconRegion).fail(console.error).done();
    adf.mf.api.setValue({"name": "#{applicationScope.region}",
                         "value": beaconRegion.uuid},
                        function() {}, function() {});
    adf.mf.api.setValue({"name": "#{applicationScope.monitoring}", "value": true},
                        function() {}, function() {});
  }

  // Callable externally
  stopMonitoring = function() {
    stopRanging(); // Must stop ranging first
    cordova.plugins.locationManager.stopMonitoringForRegion(
      beaconRegion).fail(console.error).done();
    adf.mf.api.setValue({"name": "#{applicationScope.monitoring}", "value": false},
                        function() {}, function() {});
  }

  // Callable externally
  startRanging = function() {
    cordova.plugins.locationManager.startRangingBeaconsInRegion(
      beaconRegion).fail(console.error).done();
    adf.mf.api.setValue({"name": "#{applicationScope.ranging}", "value": true},
                        function() {}, function() {});
  }

  // Callable externally
  stopRanging = function() {
    cordova.plugins.locationManager.stopRangingBeaconsInRegion(
      beaconRegion).fail(console.error).done();
    adf.mf.api.setValue({"name": "#{applicationScope.ranging}", "value": false},
                        function() {}, function() {});
    // Clear list of beacons
    adf.mf.api.invokeMethod("mobile.BeaconManager", "clearBeacons",
                            function() {}, function() {});
  }

  document.addEventListener("showpagecomplete", initialise, false);

}) ();

Let’s take a look at what this code does:

  • There are four externally callable functions – startMonitoring, stopMonitoring, startRanging and stopRanging, each of which invokes the corresponding plugin API.
  • There are two internal functions – initialize, which is invoked when the framework loads the feature, and createRegion, which creates a new beacon region based on the uuid variable defined at the top of the file. You should enter your iBeacons’ UUID here, or generate your own.  The beacon region identifier “FakeBeacon” can be any string you wish.
  • The initialize function creates and registers two callback functions via a delegate, requests authorization from the user to monitor for beacons at all times, and starts monitoring the defined beacon region.
  • The delegate.didDetermineStateForRegion callback function is invoked when the beacon region is entered or exited, even if the app was not running.  When this happens, it schedules an immediate local notification. To avoid unnecessarily ranging when the user is not actively using this app, ranging is not started here, but within the local notification handler.  For the same reason, ranging is stopped as soon as the device exits the beacon region.
  • The delegate.didRangeBeaconsInRegion callback is invoked when ranging has detected one or more iBeacons.  For each identified beacon, proximity, RSSI and accuracy values will be returned.  We will manage the list of beacons in a Java bean, so the bean’s beaconRanged method is invoked here.
  • Three application-scope variables are used to maintain the monitoring state, ranging state and the identity of the region being monitored or ranged.
  • The stopRanging function also clears the list of beacons by calling the clearBeacons method of the Java bean.

Save all your changes.

Step 4 – Create a local notification handler

There are a couple of steps required to ensure our app can receive local notifications.

Open the LifecycleListenerImpl.java file located in Projects > ApplicationController > application and modify the start method as follows to register an EventListener for local notifications:

public void start() {
  EventSource evtSource = EventSourceFactory.getEventSource(
    EventSourceFactory.NATIVE_LOCAL_NOTIFICATION_EVENT_SOURCE_NAME);
  evtSource.addListener(
new NativeLocalNotificationListener());
}

Create a new Java file by selecting the ApplicationController node in the Projects window, right click, select New > Java Class and enter "NativeLocalNotificationListener" as the name.  Enter the following code into the empty Java file:

package application;

import java.util.HashMap;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.event.Event;
import oracle.adfmf.framework.event.EventListener;
import oracle.adfmf.framework.event.NativeLocalNotificationEvent;
import oracle.adfmf.framework.exception.AdfException;
import oracle.adfmf.json.JSONException;
import oracle.adfmf.json.JSONObject;

public class NativeLocalNotificationListener implements EventListener {

  public NativeLocalNotificationListener() {
  }

  public
void onMessage(Event event) {
    String payload = event.getPayload();

    if (!"{}".equals(payload)) {
      try {
        HashMap<String, Object> payloadMap =
          ((NativeLocalNotificationEvent)event).getPayloadObject();
        JSONObject jsonPayload = (JSONObject)payloadMap.get(
"payload");
        boolean inside = jsonPayload.getBoolean("inside");

        // If inside, start ranging (If outside, ranging already has been stopped)
        if (inside) {
          AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
"Beacon",
                                                                    "startRanging",
                                                                    new Object[] {});
        }
      } 
catch (JSONException e) {
        System.out.println(
"Local Notification JSON error: " + e.getMessage());
      }
    }
  }

  public void onError(AdfException adfException) {
    System.out.println(
"Local Notification error: " + adfException.getMessage());
  }

  public void onOpen(String token) {
    System.out.println(
"Local Notification opened: " + token);
  }
}

Let’s take a look at what this code does:

  • The local notification will be fired by the JavaScript code when the device enters or exits a beacon region, no matter whether the app was running in the foreground or not.
  • The onMessage method will be invoked immediately if the app is running in the foreground, otherwise it will only be invoked when the user does one of the following:
    • Taps on the notification banner (iOS only)
    • Taps on the “View” button of the notification alert  (iOS only)
    • Taps on the notification in the Notification Center (iOS) or Notification Drawer (Android)
  • The notification triggered by the JavaScript code includes a custom JSON payload that holds a Boolean value for the attribute inside, which defines whether the device is inside or outside the beacon region.
  • If the device is inside the beacon region, the Javascript startRanging function is invoked to start ranging for beacons in this region.

Save all your changes.

Step 5 – Create a bean Data Control

We will model the list of detected beacons in two Java classes (beans) and provide access to certain methods and properties via a Data Control.

Create a new Java file by selecting the ViewController node in the Projects window, right click, select New > Java Class and enter "Beacon" as the name.  Enter the following code into the empty Java file:

package mobile;

import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;

public class Beacon {

  private String uuid;
  private int major;
  private int minor;
  private String proximity;

  private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

  public Beacon(String uuid, int major, int minor, String proximity) {
    this.uuid = uuid;
    this.major = major;
    this.minor = minor;
    this.proximity = proximity;
  }

  public void setUuid(String uuid) {
    String oldUuid = 
this.uuid;
    this.uuid = uuid;
    propertyChangeSupport.firePropertyChange(
"uuid", oldUuid, uuid);
  }

  public String getUuid() {
    return uuid;
  }

  public void setMajor(int major) {
    int oldMajor = this.major;
    this.major = major;
    propertyChangeSupport.firePropertyChange(
"major", oldMajor, major);
  }

  public int getMajor() {
    return major;
  }

  public void setMinor(int minor) {
    int oldMinor = 
this.minor;
    this.minor = minor;
    propertyChangeSupport.firePropertyChange(
"minor", oldMinor, minor);
  }

  public int getMinor() {
    return minor;
  }

  public void setProximity(String proximity) {
    String oldProximity = 
this.proximity;
    this.proximity = proximity;
    propertyChangeSupport.firePropertyChange(
"proximity", oldProximity, proximity);
  }

  public String getProximity() {
    return proximity;
  }

  public String getIdentifier() {
    return 
"Major: " + getMajor() + " Minor: " + getMinor();
  }

  public void addPropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.addPropertyChangeListener(l);
  }

  public void removePropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.removePropertyChangeListener(l);
  }
}

Let’s take a look at what this code does:

  • Beacon has five properties – uuid, major, minor, proximity and identifier, with associated getter and setter methods.
  • Consuming classes can add and remove PropertyChangeListeners, as required, to be notified of changes to these properties.

Create a new Java file by selecting the ViewController node in the Projects window, right click, select New > Java Class and enter "BeaconManager" as the name.  Enter the following code into the empty Java file:

package mobile;

import java.util.ArrayList;
import java.util.List;

import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;

public class BeaconManager {

  private static List<Beacon> beacons = null;
  protected transient static ProviderChangeSupport providerChangeSupport;

  public BeaconManager() {
    if (beacons == null) {
      beacons = new ArrayList<Beacon>();
      providerChangeSupport = new ProviderChangeSupport(this);
    }
  }

  public void startMonitoring(ActionEvent actionEvent) {
    AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
      AdfmfJavaUtilities.getFeatureId(), "startMonitoring", new Object[] {});
  }

  public void stopMonitoring(ActionEvent actionEvent) {
    AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
      AdfmfJavaUtilities.getFeatureId(), "stopMonitoring", new Object[] {});
  }

  public List<Beacon> getBeacons() {
    return beacons;
  }

  public static void beaconRanged(String uuid, int major, int minor, String proximity) {
    for (Beacon beacon : beacons) {
      if (beacon.getMajor() == major && beacon.getMinor() == minor) {
        // Existing beacon, update proximity
        beacon.setProximity(proximity);
        return;
      }
    }

    // No existing beacon found, add new one
    beacons.add(new Beacon(uuid, major, minor, proximity));
    providerChangeSupport.fireProviderRefresh("beacons");
  }

  public static void clearBeacons() {
    beacons.clear();
    providerChangeSupport.fireProviderRefresh("beacons");
  }

  public void addProviderChangeListener(ProviderChangeListener l) {
    providerChangeSupport.addProviderChangeListener(l);
  }

  public void removeProviderChangeListener(ProviderChangeListener l) {
    providerChangeSupport.removeProviderChangeListener(l);
  }
}

Let’s take a look at what this code does:

  • The BeaconManager contains a list of Beacon objects, which can be accessed via a getter method.
  • Four methods are provided for managing the beacons:
    • startMonitoring calls the JavaScript startMonitoring function
    • stopMonitoring calls the JavaScript stopMonitoring function
    • beaconRanged is called by JavaScript to inform the BeaconManager that a beacon has been detected.  If newly found, it is added to the list, otherwise the proximity property is updated.
    • clearBeacons is called by JavaScript to clear the list of beacons
  • Consuming classes can add and remove ProviderChangeListeners, as required, to be notified of changes to the list.
  • The list of beacons and the methods accessing the list are static because each time these methods are invoked from JavaScript, a new BeaconManager object is instantiated.

Save all your changes.

To create the Data Control, select the BeaconManager.java file, which will be located in Projects > ViewController > Application Sources > mobile, right click, select Create Data Control and accept the defaults.  The newly created BeaconManager Data Control will appear in the Data Controls window (you may need to Refresh it).

Save all your changes.

Step 6 – Create the AMX feature

The final step prior to deployment is to create the AMX feature.

Return to the maf-feature.xml file located in Projects > ViewController > Application Sources > META-INF and click on the Insert Feature button to add a feature called Beacon.

Open the Content tab and click on the Insert Include button to include the JavaScript file we created earlier by entering resources/js/beacon.js as the file location.

Click on the Create button in the Content tab to create an AMX file called beacon.amx.  Using the BeaconManager Data Control found in the Data Controls window and the AMX components found in the Components palette, create an AMX page similar to the following:

<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
          xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
  <amx:panelPage id="pp1">
    <amx:facet name="header">
      <amx:outputText value="Beacon Demo" id="ot1"/>
    </amx:facet>
    <amx:facet name="secondary">
      <amx:commandButton actionListener="#{bindings.startMonitoring.execute}"
                         text="Start"
                         disabled="#{!bindings.startMonitoring.enabled}" id="cb1"
                         rendered="#{applicationScope.monitoring != true}"/>
      <amx:commandButton actionListener="#{bindings.stopMonitoring.execute}" text="Stop"
                         disabled="#{!bindings.stopMonitoring.enabled}" id="cb2"
                         rendered="#{applicationScope.monitoring == true}"/>
    </amx:facet>
    <amx:outputText value="Not monitoring a region." id="ot2"
                    rendered="#{applicationScope.monitoring != true}"/>
    <amx:outputText value="Monitoring region: #{applicationScope.region}." id="ot3"
                    rendered="#{applicationScope.monitoring == true &amp;&amp;
                                applicationScope.ranging != true}"/>
    <amx:outputText value="Ranging region: #{applicationScope.region}." id="ot4"
                    rendered="#{applicationScope.ranging == true}"/>
    <amx:outputText value="Beacons located:" id="ot5"
                    rendered="#{applicationScope.ranging == true}"/>
    <amx:listView var="row" value="#{bindings.beacons.collectionModel}"
                  fetchSize="#{bindings.beacons.rangeSize}"
                  styleClass="adfmf-listView-insetList"
                  showMoreStrategy="autoScroll" bufferStrategy="viewport"
                  id="lv1" rendered="#{applicationScope.ranging == true}">
      <amx:listItem showLinkIcon="false" id="li1">
        <amx:tableLayout width="100%" id="tl1">
          <amx:rowLayout id="rl2">
            <amx:cellFormat width="10px" rowSpan="2" id="cf2"/>
            <amx:cellFormat width="100%" id="cf3"
                            height="#{deviceScope.device.os=='Android'?'36':'32'}px">
              <amx:outputText value="#{row.identifier}" id="ot7"/>
            </amx:cellFormat>
          </amx:rowLayout>
          <amx:rowLayout id="rl1">
            <amx:cellFormat width="100%" id="cf1"
                            height="#{deviceScope.device.os=='Android'?'22':'19'}px">
              <amx:outputText value="#{row.proximity}"
                              styleClass="adfmf-listItem-captionText" id="ot6"/>
            </amx:cellFormat>
          </amx:rowLayout>
        </amx:tableLayout>
      </amx:listItem>
    </amx:listView>
  </amx:panelPage>
</amx:view>

Let’s take a look at what this code does:

  • Start and Stop buttons enable you to start or stop monitoring for the beacon region, depending on whether monitoring is active, by calling the startMonitoring and stopMonitoring methods on the BeaconManager Data Control.
  • The page displays the current state of monitoring or ranging the beacon region, using the application-scope variables that are updated by the JavaScript code.
  • Whilst ranging, the page displays the list of detected beacons managed by the BeaconManager Data Control, along with their estimated proximity.

Save all your changes.

Step 7 – Deploy the app

The app must be deployed to a BLE-enabled device.  I have verified it on various iOS devices, but have not yet verified it on an Android device.

In order to deploy to an iOS device, you must configure a suitable provisioning profile and signing identity in JDeveloper  > Preferences > Mobile Application Framework > iOS Platform.

You must also configure an appropriate bundle ID in the maf-application.xml file.  Return to this file, which is located in Application Resources > Descriptors > ADF META-INF, select the Application tab and enter an Id that matches your provisioning profile.

Deselect Show Navigation Bar on Application Launch, save all your changes and deploy the app to a BLE-enabled device.

Before launching the app, ensure you have Bluetooth enabled, as well as Location Services if running on iOS.  When you launch the app on iOS, you will be prompted to allow the app to access your location even when you are not using the app, which you should allow.

The app will start monitoring for the defined region immediately.  If you have access to beacons (or a fake beacon) with the same UUID that you have configured in the beacon.js file, you will be notified when you enter a region containing those beacons.  If the app is running in the foreground when this occurs, ranging will commence and you will see a screen similar to the following:


How to create a fake iBeacon app

If you don’t have any beacons lying around for testing, you can create a MAF app that pretends to be an iBeacon by following these steps.

Step 1 – Find a suitable Cordova plugin

Already done!  Just reuse the plugin you have already downloaded.

Step 2 – Create a MAF app and add the plugin

Open JDeveloper with MAF 2.1.1 installed, create a new MAF app called FakeBeacon and add the plugin as you did for the BeaconDemo app.  Save all your changes.

Step 3 – Create a JavaScript interface file

Create a new JavaScript file called beacon.js as you did for the BeaconDemo app and enter the following code into the empty JavaScript file and save your changes:

(function() {

  // Our region identifiers
  var uuid = "0AC59CA4-DFA6-442C-8C65-22247851344C";
  var major = 1;
  var minor = 100;

  function initialise() {
    var delegate = new cordova.plugins.locationManager.Delegate();

    // Event when advertising starts (there may be a short delay after the request)
    delegate.peripheralManagerDidStartAdvertising = function(pluginResult) {
      console.log('StartAdvertising: ' + JSON.stringify(pluginResult.region));
    };

    // Event when bluetooth transmission state changes
    delegate.peripheralManagerDidUpdateState = function(pluginResult) {
      console.log('UpdateState: ' + JSON.stringify(pluginResult.region));
    };

    // Set delegate
    cordova.plugins.locationManager.setDelegate(delegate);

    // Set initial beacon identifiers in EL
    adf.mf.api.setValue({"name": "#{applicationScope.uuid}", "value": uuid},
                        function() {}, function() {});
    adf.mf.api.setValue({"name": "#{applicationScope.major}", "value": major},
                        function() {}, function() {});
    adf.mf.api.setValue({"name": "#{applicationScope.minor}", "value": minor},
                        function() {}, function() {});
  }

  function createRegion() {
    // Read the values input by the user
    adf.mf.el.getValue("#{applicationScope.major}",
                       function(req, res) { major = res[0]['value'] }, function() {});
    adf.mf.el.getValue("#{applicationScope.minor}",
                       function(req, res) { minor = res[0]['value'] }, function() {});
    return new cordova.plugins.locationManager.BeaconRegion("FakeBeacon", uuid,
                                                            major, minor);
  }

  // Callable externally
  startAdvertising = function() {
    // Verify the platform supports transmitting as a beacon
    cordova.plugins.locationManager.isAdvertisingAvailable().then(function(isSupported){
      if (isSupported) {
        cordova.plugins.locationManager.startAdvertising(
          createRegion()).fail(console.error).done();
      } else {
        alert("Advertising not supported");
      }
    }).fail(console.error).done();
  }

  // Callable externally
  stopAdvertising = function() {
    cordova.plugins.locationManager.stopAdvertising().fail(console.error).done();
  }

  document.addEventListener("showpagecomplete", initialise, false);

}) ();

Let’s take a look at what this code does:

  • There are two externally callable functions – startAdvertising and stopAdvertising, each of which invokes the corresponding plugin API.
  • There are two internal functions – initialize, which is invoked when the framework loads the feature, and createRegion, which creates a new beacon region based on the uuid, major and minor variables defined at the top of the file. The value for uuid should be the same as you specified in the BeaconDemo app.
  • The initialize function creates and registers a Delegate object with two callback functions (which are only included for debug logging) and initializes three application-scope variables.
  • The application-scope variables are used on the AMX page we will create.

Step 4 – Create a managed bean

We will use a managed bean to provide the interface between the AMX code and the JavaScript functions.

Create a new Java file called BeaconBean.java by selecting the ViewController node in the Projects window, right click, select New > Java Class and enter “BeaconBean” as the name.  Enter the following code into the empty Java file and save your changes:

package mobile;

import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;

public class BeaconBean {

  private boolean advertising;
  private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

  public BeaconBean() {
  }

  public void setAdvertising(boolean advertising) {
    boolean oldAdvertising = this.advertising;
    this.advertising = advertising;
    propertyChangeSupport.firePropertyChange("advertising",
                                             oldAdvertising,
                                             advertising);
  }

  public boolean isAdvertising() {
    return advertising;
  }

  public void startAdvertising(ActionEvent actionEvent) {
    AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
      AdfmfJavaUtilities.getFeatureId(), "startAdvertising", new Object[] {});
    setAdvertising(true);
  }

  public void stopAdvertising(ActionEvent actionEvent) {
    AdfmfContainerUtilities.invokeContainerJavaScriptFunction(
      AdfmfJavaUtilities.getFeatureId(), "stopAdvertising", new Object[] {});
    setAdvertising(false);
  }

  public void addPropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.addPropertyChangeListener(l);
  }

  public void removePropertyChangeListener(PropertyChangeListener l) {
    propertyChangeSupport.removePropertyChangeListener(l);
  }
}

Let’s take a look at what this code does:

  • Two methods are provided for managing the advertising of iBeacon data:
    • startAdvertising calls the JavaScript startAdvertising function
    • stopAdvertising calls the JavaScript stopAdvertising function
  • The advertising attribute holds the advertising status and can be accessed by getter and setter methods.
  • Consuming classes can add and remove PropertyChangeListeners, as required, to be notified of changes to the advertising status.

Step 5 – Create the AMX feature

The final step prior to deployment is to create the AMX feature.

Return to the maf-feature.xml file and click on the Insert Feature button to add a feature called Beacon.

Open the Content tab and click on the Insert Include button to include the JavaScript file we created earlier by entering "resources/js/beacon.js" as the file location.

Click on the Create button in the Content tab to create an AMX file called beacon.amx.

Here's where I should point out, if you haven't noticed already, that the Java bean we created earlier isn't yet "managed" by anything.  To turn it into a managed bean, open the adfc-mobile-config.xml file, which is located in Projects > ViewController > Web Content, select the Overview tab, select the Managed Beans tab and select Add.  Enter “BeaconBean” as the name, “mobile.BeaconBean” as the class and select application as the scope, then save all your changes.

Returning to beacon.amx, use the AMX components found in the Components palette to create an AMX page similar to the following and save all your changes:

<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
          xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
  <amx:panelPage id="pp1">
    <amx:facet name="header">
      <amx:outputText value="Fake Beacon" id="ot1"/>
    </amx:facet>
    <amx:inputText label="UUID" id="it1" readOnly="true"
                   value="#{applicationScope.uuid}"/>
    <amx:inputText label="Major" id="it2" readOnly="#{BeaconBean.advertising == true}"
                   value="#{applicationScope.major}" inputType="number"/>
    <amx:inputText label="Minor" id="it3" readOnly="#{BeaconBean.advertising == true}"
                   value="#{applicationScope.minor}" inputType="number"/>
    <amx:commandButton text="Start advertising" id="cb1"
                       actionListener="#{BeaconBean.startAdvertising}"
                       rendered="#{BeaconBean.advertising != true}"/>
    <amx:commandButton text="Stop advertising" id="cb2"
                       actionListener="#{BeaconBean.stopAdvertising}"
                       rendered="#{BeaconBean.advertising == true}"/>
  </amx:panelPage>
</amx:view>

Let’s take a look at what this code does:

  • The page displays the UUID, major value and minor value of the fake beacon, which are stored in application-scope variables. 
  • The major and minor values can be edited by the user when the app is not advertising.
  • Start Advertising and Stop Advertising buttons enable you to start or stop advertising as a fake beacon, depending on whether advertising is active, by calling the startAdvertising and stopAdvertising methods on the BeaconBean managed bean.

Step 7 – Deploy the app

The app must be deployed to a BLE-enabled iOS device.  Use the same iOS provisioning profile and signing identity as you did for the BeaconDemo app.

Configure an appropriate bundle ID in the maf-application.xml file as you did for the BeaconDemo app.  Deselect Show Navigation Bar on Application Launch, save all your changes and deploy the app to a BLE-enabled device.

Before launching the app, ensure you have Bluetooth enabled.  While the app is running, if it is not advertising, you can modify the major and minor values for your fake beacon.  The app looks similar to the following:


Conclusion

This post demonstrates how easily you can create a MAF app that detects iBeacons and notifies the user when a particular iBeacon region has been entered.

Detecting the beacons is the easy part, but how will you provide relevant information to your users in a real-world scenario, such as those mentioned?

When a beacon region is entered, or a user’s proximity to a particular beacon is closer than a defined limit, your MAF app could trigger a local notification, display a popup dialog or navigate to a page containing the relevant information.  MAF provides APIs for each of these scenarios and there are sample apps provided within each MAF release demonstrating how to use these APIs.

To keep your MAF app up-to-date, your app could connect to a REST-based service when launched, and download a current list of beacon identifiers and all relevant information.

For more information about these and other topics, please refer to the Oracle A-Team Chronicles, in particular this article on iBeacon and this article on the Mobile Persistence Accelerator (which includes REST-JSON and REST-XML wizards for MAF).

Tuesday Mar 31, 2015

How to implement push notifications in MAF 2.1.1

Push notifications are a fantastic way to notify your users of relevant information in a timely fashion, even when your mobile app is running in the background or not running at all.

The MAF 2.1.1 extension provides two sample applications – PushDemo, which demonstrates how to receive push notifications in a MAF app, and PushServer, which demonstrates how to send push notifications to a MAF app.

This blog post will provide an introduction to push notifications and a detailed description of how to configure the PushDemo and PushServer sample applications, as a vehicle for learning about push notifications. Readers can use the lessons learned to implement push notifications in their own applications.

How push notifications work

Although technically different, the logical push notifications architecture is similar for mobile apps running on both Android and iOS, with Google and Apple each providing a cloud-based Push Notifications service that acts as the go-between your server application and your mobile app.

The flow of push notifications is also similar: including a registration process followed by the sending of a notification to one or more devices, as follows:


Each time a push-enabled mobile app starts, it registers with the Apple Push Notifications service (APNs) or Google Cloud Messaging (GCM), based on the device type.  The registration request includes an identifier. Successful registration results in a registration token being returned that uniquely identifies this mobile app running on this device.

The push notification will originate from a server application, so the mobile app must register with the server application, providing enough information for the server application to be able to uniquely identify the user associated with the app on this device. This registration with the server application would typically be done following successful authentication of the user and must include the registration token.

Having completed the registrations, when an event occurs later on that requires a push notification to be sent to one or more users, the server application reviews all the registrations and sends a push notification to the user’s registered device(s) via APNs, GCM, or both. Each push notification message includes the unique registration token for the target device.

Required push notifications setup

APNs

Apple requires you to create an explicit App ID that enables push notifications and a corresponding client SSL certificate. 

The App ID is used to create a provisioning profile that is embedded into your mobile app.  This provisioning profile informs APNs that your mobile app is a trusted app.

The client SSL certificate is used by your server application when communicating with APNs.   It informs APNs that your server application is a trusted application and that it is permitted to send push notifications to your mobile app.

For more information refer to Apple Push Notification Service and Configuring Push Notifications.

GCM

Google requires you to create a Google API project and obtain an API Key.

The project number is used by your mobile app as the Sender ID when registering with GCM. It indicates to GCM which server application (or server applications, since more than one Sender ID can be specified) is permitted to send push notifications to your mobile app.

The API Key is used by your server application as the Sender Auth Token when communicating with GCM. It gives your server application access to Google services and ensures that push notifications originating from your server application are targeted to your mobile app.

For more information refer to Google Cloud Messaging Overview and Getting Started on Android.

About the PushDemo sample app

The PushDemo sample app is a MAF app that works in conjunction with the PushServer sample app to demonstrate registration for, sending and receipt of push notifications. (More details about the sample apps provided within each MAF release and where to find them are provided here.)

The PushDemo sample app has three functions:

  • Each time you launch the PushDemo sample app, it automatically registers with GCM or APNs, as appropriate for your device, and receives a registration token.
  • It provides a registration page for you to initiate registration with a running instance of the PushServer sample app.  In a real-world app, this step would normally be automatically handled by the client app following a user login, or retrieval of stored user details.
  • It provides a page for displaying the message received when a push notification is received by the PushDemo sample app.

About the PushServer sample app

The PushServer sample app is a server application that uses a GCM client library provided by Google (refer to the Android Developer site for details of how to install it) for connecting to the GCM server, and sample code for connecting to APNs as described on the Apple Developer site.

GCM and APNs have different policies regarding push notification error handling and de-registration of devices.  The PushServer sample app does not provide any special handling, but you should be aware of these policies when designing your server application if it will support push notifications. To review these policies, refer to Implementing GCM Server and Provider Communication with Apple Push Notification Service.

There are two components to the PushServer sample app:

  • A registration servlet that enables an instance of the PushDemo sample app running on a mobile device to register with the server application.  The registration request includes the registration token received from GCM or APNs, the mobile app’s Bundle ID, the user ID entered into the registration page of the mobile app and the device type.  These are stored in a database on the server for later sending of push notifications to the user’s mobile device.
  • A push notification page displays the registered devices and enables you to enter a message to push to a selected device.

How to configure and run the PushServer sample app

Apple and Google registration

To implement push notifications, the app must be registered with Apple and/or Google, depending on the device(s) you wish to use for testing.

If you are an Oracle employee, this has already been done for you and you can retrieve the necessary signing artifacts by clicking on the link “How to use the PushDemo sample app” found on the internal MAF uptake guide wiki.

Otherwise for customers, you will need to register your app with Apple and/or Google and retrieve the necessary signing artifacts, as described above under Required Push Notifications Setup.

Database setup

The PushServer sample app requires a database for storing the mobile device registration details. A dummy database connection called “pushServerDB” is provided in the connections.xml.

If you are an Oracle employee intending to run the server application on the Oracle intranet, you can configure the PushServer sample app to connect to a hosted database as described on the internal MAF uptake guide wiki.

Otherwise for customers, you must install a database, create the required schema using the pushschema.sql script found in the PushServer sample app’s Model/database folder and modify the properties of the “pushServerDB” database connection in the connections.xml file as follows.  If your database is not an Oracle database, you may also need to modify certain properties of the Application Modules that are configured in the bc4j.xcfg file.  The configuration steps are described below.

Server application configuration

Follow these steps to configure the server application:

  1. Open the PushServer sample app in JDeveloper 12.1.3 with MAF 2.1.1 extension.
  2. Modify the dummy database connection as follows:
    1. Expand Application Resources > Connections > Database to reveal pushServerDB.
    2. Right-click on pushServerDB and select Properties.
    3. Enter all the required properties for the database you intend to use.
    4. Verify the entered details by clicking on Test Connection.
    5. Save the entered details by clicking on OK.
  3. If you are using a non-Oracle database, you may need to update certain properties of the configured Application Modules as follows:
    1. Open Projects > Model > Application Sources > oracle.adfmf.demo > push > model > RegistrationModule > RegistrationModel.xml.
    2. Open the Configurations tab.
    3. Click on the link for bc4j.xcfg.
    4. For each listed Application Module, select it and click on the Edit icon, open on the Properties tab, modify the relevant properties and click OK.  For example, to connect to a MySQL database, change the jbo.SQLBuilder property to “SQL92”.
  4. Open the MessageBean.java file under Projects > ViewController > Application sources > oracle.adfmf.demo > push.
  5. Set the GOOGLE_APIKEY variable to your Google project’s API Key.
  6. Set the IOS_KEYFILE variable to the full path to your iOS keystore (.p12 file).
  7. Set the IOS_KEYPWD variable to the password you set on your iOS keystore.
  8. If you will run the server application on a corporate intranet, such as the Oracle network, set the PROXY_HOST and PROXY_PORT variables appropriately.
  9. Otherwise, leave both the PROXY_HOST and PROXY_PORT variables set to null.
  10. Save all your changes.

WebLogic Server configuration

The server application must be deployed to a running WebLogic Server (WLS) instance.  The most convenient option for developers is to configure and run the embedded WLS within JDeveloper as follows:

  1. If you are on a corporate intranet, such as the Oracle network, configure the JDeveloper proxy settings in Preferences > Web Browser and Proxy > Proxy Settings.
  2. Start an instance of the embedded WLS in JDeveloper via Run > Start Server Instance.
  3. You will be prompted to enter and confirm a password.  At this point, you may also change the listening address or port.  I recommend you keep the default settings, which should be to listen on All Available Addresses using port 7101, with port 7102 for SSL.
  4. Once the WLS has started, open http://localhost:7101/console in your preferred browser.  This is the WLS console.
  5. Login to the WLS console as user “weblogic” and the password you entered in step 3.
  6. Turn off hostname verification in the WLS console via Domain Configurations > Environment > Servers > Default Server > Configuration > SSL > Advanced. By setting “Hostname Verification” to None.
  7. Click on Save.

Deploy the server application

Deploy both components of the server application within JDeveloper as follows:

  1. Expand Projects > ViewController > Application Sources > oracle.adfmf.demo > Push to reveal RegistrationServlet.java.
  2. Right-click on RegistrationServlet.java and select Run.
  3. You can ignore the error reported by the servlet, since it was launched without any parameters.
  4. Expand Projects > ViewController > Web Content to reveal pushregistration.jspx.
  5. Right-click on pushregistration.jspx and select Run.

How to configure and run the PushDemo sample app

Client app configuration

Configure the PushDemo sample app as follows:

  1. Open the PushDemo sample app in JDeveloper 12.1.3 with MAF 2.1.1 extension.
  2. Open the adf-config.xml file found in Application Resources > Descriptors > ADF META-INF.
  3. Select the Source tab and enter your Google project number into the value for the gcmSenderId property.
  4. Open the connections.xml file also found in Application Resources > Descriptors > ADF META-INF.
  5. Modify the url for the PushServiceConn connection by changing “127.0.0.1” to the relevant value for your server application, based on the network that will be shared by your server application and your mobile client app.
  6. Save all your changes.

Deploy the client app

Follow these steps to deploy and run the PushDemo app:

  1. Configure JDeveloper with the name of your push-enabled iOS provisioning profile and corresponding signing identity in Preferences > Mobile Application Framework > iOS Platform.
  2. Deploy the PushDemo app to your Android or iOS device, or Android emulator (you must use a “Google APIs” target).  Push notifications do not work on the iOS simulator.
  3. Ensure that your mobile device can access the Internet via a mobile data plan or wifi network.  Note for Oracle employees that push notifications are blocked on the “clear” wifi network, even with VPN enabled.  If you have no access to a mobile data plan or corporate wifi connection, you can setup a local wifi on the machine that is running the server application and connect to that.
  4. Launch the app and it will automatically register with APNs or GCM, as appropriate. 
  5. Switch to the Register feature and it should advise that registration was successful.
  6. If you have not registered your device with the server application previously, you will need to do this now.  If you are running your server application on a corporate intranet, such as the Oracle network, you will need to establish a VPN connection on your mobile device before communicating with the server application. 
  7. To register your device, enter a unique User ID into the client app and tap on the Register button.  A success or error message will be displayed below the Register button. 
    1. Note: The server application does not handle duplicate entries for one device and APNs or GCM may return a different token, so you may need to delete the old entry for your device from the database and try again.
  8. If you are using an Android device and you have established a VPN connection, you must close this VPN connection now to ensure that you can receive push notifications.
  9. Switch to the Message feature, which will display any message received via push notifications.

How to send a push notification to the PushDemo sample app

When you deployed the server application's Push Registration page, it should have been displayed in your default browser.  You can send a push notification to the PushDemo sample app running on your mobile device from this page as follows:

  1. Select the entry for your mobile device.
  2. Enter a message into the Message field.
  3. Click the Push Message button.

Your mobile device should receive the push notification as follows:

  • If the PushDemo sample app is running in the foreground, the message you entered should be displayed on the Message feature’s main page.
  • Otherwise, your mobile device’s operating system should display the push notification in the standard manner. On Android, a notification banner is presented for a short time and the notification can be viewed in the Notification Drawer. On iOS, depending on your notification settings, a banner or alert may be displayed and the notification can be viewed in the Notification Center.
  • If you tap on a notification displayed by your device’s operating system, the PushDemo sample app should be launched and/or moved to the foreground and the message should be displayed on the Message feature’s main page.

Conclusion

The PushDemo sample app demonstrates how to register for and receive push notifications using MAF 2.1.1. It works in conjunction with the PushServer sample app that demonstrates techniques for registering with GCM and APNs and sending push notifications using these services.

By following the steps described above, you should be able to send push notifications from a deployed instance of the PushServer sample app to your mobile device with the PushDemo sample app installed.

Based on the information and links provided in this blog post and the hands-on experience gained from configuring and using the provided sample apps, you should be able to implement push notifications in your own server application and MAF-based mobile app.

About

This blog is is dedicated to announcements,tips and tricks and other items related to developing, integrating, securing, and managing mobile applications using Oracle's Mobile Platform. It is created and maintained by the Oracle Mobile product development team.

Archive of past entries

Even More Mobile Development Blogs

Oracle A-Team Site - Mobile Related Entries

Code samples from the Community

Fusion Middleware Blogs

Search

Archives
« September 2015
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today