Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
255 lines (253 sloc) 13 KB
---
layout: tutorial
title: Location services in hybrid applications
relevantTo: [hybrid]
weight: 9
downloads:
- name: Download MobileFirst project
url: https://github.com/MobileFirst-Platform-Developer-Center/LocationServices/tree/release71
---
<p>This tutorial covers the following topics:</p>
<ul>
<li><a href="#architecture">Architecture</a></li>
<li><a href="#basicAPI">Basic API</a></li>
<li><a href="#acquisitionPolicy">Acquisition policy</a></li>
<li><a href="#triggers">Triggers</a></li>
<li><a href="#events">Events</a></li>
<li><a href="#testingHybrid">Testing hybrid applications</a></li>
<li><a href="#androidPermissions">Location Services permissions in Android</a></li>
<li><a href="#sample">Sample application</a></li>
</ul>
<h2 id="architecture">Architecture</h2>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/location_service_diagram.jpg" /></p>
<p>The application code on the mobile device, in the form of an acquisition policy, controls the collection of data from device sensors.</p>
<p>The collected data is referred to as the device context.</p>
<p>When a change occurs in the device context, such as a change in the geolocation of the device or the fact that it entered a Wi-Fi zone, triggers can be activated.</p>
<p>The triggers specify that an action should occur: either a callback function is called, or an event is sent to the server, based on the device context.</p>
<p>Events are created by triggers and application code, and include a snapshot of the device context at the time of their creation.</p>
<p>Events are buffered on the client, and then transmitted to the server periodically.</p>
<p>The server might process the event later.</p>
<p>During the event transmission process, the device context is synchronized transparently to the server.</p>
<p>To handle the events, the server uses adapter application code.</p>
<p>This code sets up event handlers on the server. These handlers filter event data and pass matching events to a callback function.</p>
<p>The code also accesses the client device context (its location and Wi-Fi network information), and sets an application context.</p>
<p>Server activities and received events are logged, together with the device and application contexts, for future reporting and analytics.</p>
<h2 id="basicAPI">Basic API</h2>
<h3>Client JavaScript</h3>
<p><strong>Note:</strong> Call the following functions after the IBM MobileFirst Platform Foundation framework is initialized (within or after the <code>wlCommonInit()</code> function).</p>
<p>{% highlight javascript %}
WL.Device.startAcquisition(policy, triggers, onFailure)
{% endhighlight %}</p>
<ul>
<li><code>policy</code>: How do you acquire the sensor data?</li>
<li><code>triggers</code>: What do you act on and how?</li>
<li><code>onFailure</code>: How do you handle acquisition failures?</li>
</ul>
<h3>Server JavaScript code</h3>
<p>{% highlight javascript %}
WL.Server.setEventHandlers(eventHandlers);
{% endhighlight %}</p>
<p><code>eventHandlers</code>: What events do you act on and how?</p>
<h2 id="acquisitionPolicy">Acquisition policy</h2>
<p>An acquisition policy defines how acquisition takes place.<br />
{% highlight javascript %}
var policy = {
Geo: WL.Device.Geo.Profiles.LiveTracking(),
Wifi: {
interval: 10000,
accessPointFilters: {
[{
SSID: "Net1"
}, {
SSID: "Net2",
MAC: "*"
}]
}
}
};
{% endhighlight %}</p>
<h3>Geo acquisition policy</h3>
<p>{% highlight javascript %}
Geo: WL.Device.Geo.Profiles.LiveTracking(),
{% endhighlight %}</p>
<p><code>LiveTracking</code> is a preset profile that uses the most accurate settings to track the device.<br />
Additional configuration options:</p>
<ul>
<li><code>RoughTracking</code></li>
<li><code>PowerSaving</code></li>
<li>Custom settings</li>
</ul>
<blockquote><p>For more information, see the topic about setting an acquisition policy, in the user documentation.</p></blockquote>
<h3>Wi-Fi acquisition policy</h3>
<p>{% highlight javascript %}
Wifi: {
interval: 10000,
accessPointFilters: {
[{
SSID: "Net1"
}, {
SSID: "Net2",
MAC: "*"
}]
}
}
{% endhighlight %}</p>
<p>The <code>interval</code> parameter is the polling interval, in milliseconds; Wi-Fi polling is performed at each interval.</p>
<p>The <code>accessPointFilters</code> parameter are access points of interest.</p>
<p>In the example above, the acquisition policy works as follows:</p>
<ul>
<li>Ignores everything except <code>Net</code>1 and <code>Net2</code> – This setting assists in dynamic environments, such as mobile hotspots.
</li>
<li>Considers all <code>Net1</code> access points as one single access point.
</li>
<li>Differentiates <code>Net2</code> access points by their MAC address.
</li>
</ul>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_wifi-policy-example.jpg" /></p>
<blockquote><p>For more information, see the topic about setting an acquisition policy, in the user documentation.</p></blockquote>
<h2 id="triggers">Triggers</h2>
<p>{% highlight javascript %}
var triggers = {
Geo: {
trigger1: {
type: "Enter",
circle: {
longitude: -74.04444,
latitude: 40.689167,
radius: 100
},
callback: libertyAtLast,
eventToTransmit: {
event: {
bring: "me",
your: "huddledMasses"
}
}
}
}
};
{% endhighlight %}</p>
<p>You can setup triggers for the following effects:</p>
<ul>
<li>Geo/Wi-Fi fences: <code>Enter</code>, <code>Exit</code>, <code>Dwell Inside</code>, <code>Dwell Outside</code></li>
<li>Movement: Geo: <code>PositionChange</code>, Wi-Fi: <code>VisibleAccessPointsChange</code></li>
<li>Wi-Fi: <code>Connect</code> / <code>Disconnect</code></li>
</ul>
<p>In this example, <code>trigger1</code> is an <code>Enter</code> trigger which is activated when the device enters the defined circle (longitude, latitude, and radius).</p>
<p>When a trigger activates, it can call a callback function and/or create an event to be sent to the server.</p>
<blockquote><p>For more information, see the topic about triggers, in the user documentation.</p></blockquote>
<h2 id="events">Events</h2>
<h3>Client side</h3>
<p>Events are generated by triggers (as explained in section <a href="#triggers">Triggers</a>).<br />
{% highlight javascript %}
eventToTransmit: {
event: {
bring: "me",
your: "huddledMasses"
}
}
{% endhighlight %}</p>
<p>You can also generate events manually by calling this API:<br />
{% highlight javascript %}
WL.Client.transmitEvent(event,immediate);
{% endhighlight %}</p>
<h3>Server side</h3>
<p>In the adapter code, create event handlers:</p>
<p>{% highlight javascript %}
WL.Server.createEventHandler(filter, handlerFunction);
{% endhighlight %}</p>
<p>Events that match the <code>filter</code> parameter are passed to <code>handlerFunction</code>.<br />
Filter examples:</p>
<ul>
<li><code>{status: "platinum"}</code> – Handle platinum members only</li>
<li><code>{hotel: { country: "USA" } }</code> – Hotels in the USA</li>
<li><code>{}</code> – All events</li>
</ul>
<p>Register the event handlers:<br />
{% highlight javascript %}
WL.Server.setEventHandlers([...]);
{% endhighlight %}</p>
<blockquote><p>For more information, see the topic about working with geofences and triggers, in the user documentation.</p></blockquote>
<h2 id="testingHybrid">Testing hybrid applications</h2>
<p>To test your application, you might want to test the various triggers and the error handling logic that your application uses.<br />
The <strong>Mobile Browser Simulator</strong> provides capabilities to simulate sensor data and errors.<br />
To access it, right-click an application environment and select <strong>Run As</strong> > <strong>Preview</strong>.</p>
<h3>Geo testing</h3>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_geotesting.png" /></p>
<p>You can use the Geolocation widget to set a specific position through a manual entry or by a click on the map.</p>
<p>A simple simulation mode is also provided by the <strong>Step</strong> and <strong>Play</strong> buttons, which move the position in the simulated device at the given speed and in the direction of the given heading.</p>
<p>You can also simulate the generation of errors.</p>
<h3>Wi-Fi testing</h3>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_wifitesting.png" /></p>
<p>You can use the Network widget to define simulated access points, configure their signal strengths, and simulate the connection or disconnection to an access point.<br />
You can also simulate the generation of errors.</p>
<h3>Scenarios</h3>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_scenarios.png" /></p>
<p>You can use the Scenario widget to automatically simulate a user moving through an environment in a complex way.<br />
A scenario consists of:</p>
<ul>
<li>The path of the user, and the point when the user reaches each path point
</li>
<li>Wi-Fi access points
</li>
<li>No-GPS coverage zones
</li>
</ul>
<p>To open the scenario editor, click <strong>Edit</strong>.</p>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_scenario-edit-mode.png" style="width:55%"/></p>
<p>Enter a geolocation directly to move the map, or use the arrows to pan and +/- track to zoom.</p>
<ul>
<li>Click <img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_path-icon.png" style="display:inline" /> to define the path of the user.
</li>
<li>Click on the map to add each path point. Double-click to add the last point.<br />
You can drag points to new locations.
</li>
<li>Click on a point to set the user's arrival time to that point, or to delete the whole path.</li>
<li>Click <img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_wifi-icon.png" style="display:inline" /> to add Wi-Fi access points.
</li>
<li>Click on the map and drag to set the area covered by the access point.</li>
<li>Click an existing access point to change its SSID and MAC.<br />
After clicking, drag to move or resize.
</li>
<li>Click <img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_zone-icon.png" style="display:inline" /> to add no-GPS zones.
</li>
<li>Click on the map to add each vertex of the zone. Double-click to add the last point.<br />
After clicking an existing zone, you can drag to move, resize, or rotate.
</li>
</ul>
<p>When a scenario is played, the position of the user is displayed on the map ( <img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_user-icon.png" style="display:inline"/> ) and is automatically updated. The position that is available to the device is shown in the Geolocation widget (and does not change in a no-GPS zone).<br />
Wi-Fi access point visibility and signal strengths are automatically updated. You can see these updates in the Network widget.<br />
You can import and export scenarios to support test reuse.</p>
<h2 id="androidPermissions">Location Services permissions in Android</h2>
<p>Android Marshmallow requires user permissions to be granted at runtime. Since runtime code written in Javascript does not have access to the Android api, these permissions must be requested and checked by the native code before launching the Cordova Web Framework. The file [application name].java in the native folder is responsible for loading the web resources. The code for requesting and checking permissions for Location Services should be called within this file, for example in onInitWebFrameworkComplete.</p>
<p>{% highlight java %}
public void onInitWebFrameworkComplete(WLInitWebFrameworkResult result) {
if (result.getStatusCode() == WLInitWebFrameworkResult.SUCCESS) {
super.loadUrl(WL.getInstance().getMainHtmlFilePath());
} else {
handleWebFrameworkInitFailure(result);
}
if (!(WLClient.getInstance().getContext().checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)== PackageManager.PERMISSION_GRANTED)) {
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 0);
}
}
{% endhighlight %}</p>
<p>This code requests permission if the permission has not already been granted.<br />
If the permission is not subsequently granted all requests for location services from the Web Framework will fail.<br />
for more information, please refer to https://developer.android.com/preview/features/runtime-permissions.html</p>
<h2 id="sample">Sample application</h2>
<p><a href="https://github.com/MobileFirst-Platform-Developer-Center/LocationServices/tree/release71" target="_blank">Click to download</a> the MobileFirst project.</p>
<p>The <code>LocationServices</code> sample demonstrates:</p>
<ul>
<li>Acquiring an initial position
</li>
<li>Using a Geo profile
</li>
<li>Geo triggers for DwellInside, Exit area, and PositionChange
</li>
<li>Transmitting events to the server on DewllInside and Exit area
</li>
<li>Ongoing acquisition
</li>
</ul>
<p><img alt="missing_alt" src="{{ site.baseurl }}/assets/backup/10_04_sample.png" /></p>
You can’t perform that action at this time.