Where in the world is your cell phone?
With Cordova, you can write your app in JavaScript, build an Android apk and sell it on Google Play. This article shows you how to use GeoLocation (GPS) from Javascript.
We show you the tricks that official documentation misses: adding the required permissions to Android manifest and managing life cycle (pause and resume).
Beta: this document is beta quality – different versions of the program have run on a physical phone, official Android SDK emulator with KVM on Linux and BlueStacks simulator on Windows. But the exact steps and specific source code listed here have not been tested after writing.
Prequisites
You should have a working Cordova environment and an Android emulator. Basic knowledge of command line interface, HTML, CSS and Javascript is required.
Overview
To use geolocation, you should create a new project and add the geolocation plugin. Then you can set watch (navigator.geolocation.watchPosition) on GPS. Your geoWin() function will be called automatically. This is explained in the official Cordova 5.1.1 documentation for geoLocation and also later in this article.
But the official instructions don’t work! At the time of writing, the official documentation misses crucial steps on Android. We’ll explain them here, so you’ll have GPS working in soon.
To allow geolocation, you must manually add permissions to Android manifest. After this, geolocation starts to work.
But it will drain your users’ battery! You must handle program life cycle. This means you clear the watch when user navigates out of the app (onPause), then set a new watch when user comes back (onResume).
Source code is available: Download geolocation-cordova-android-karvinen-2015.zip
Create a New Project
$ cordova create geo com.terokarvinen.student.geo $ cd geo/ $ cordova platform add android
Test that you can run the example app, e.g. ‘cordova emulate’, ‘cordova run’.
Add the required plugin
$ cordova plugin add cordova-plugin-geolocation
For convinience, we use jQuery to modify some text on the page. Download minified (compressed) jQuery 2 from jQuery download page and save it to geo/www/js/jquery-min.js.
geo/www/index.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *"> <meta name="format-detection" content="telephone=no"> <meta name="msapplication-tap-highlight" content="no"> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width"> <link rel="stylesheet" type="text/css" href="css/index.css"> <title>Teros Geo</title> </head> <body> <h1>Teros Geo</h1> <p id="status">Loading...</p> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript" src="js/geo.js"></script> </body> </html>
geo/www/js/geo.js
// debug function d(s) { console.log(s); $("#status").text(s); } // geo function geoWin(pos) { d("geoWin(): "+pos.coords.latitude+", "+pos.coords.longitude); } function geoFail(error) { d("geoFail(): "+error.code+": "+error.message); } function startGeoWatch() { d("startGeoWatch()"); opt = {timeout: 1000, enableHighAccuracy: true}; watchGeo = navigator.geolocation.watchPosition(geoWin, geoFail, opt); } function stopGeoWatch() { d("stopGeoWatch()"); navigator.geolocation.clearWatch(watchGeo); } // life cycle function onPause() { d("onPause()"); stopGeoWatch(); } function onResume() { d("onResume()"); startGeoWatch(); } // init function onDeviceReady() { d("onDeviceReady()"); document.addEventListener("pause", onPause, false); document.addEventListener("resume", onResume, false); startGeoWatch(); } function main() { document.addEventListener('deviceready', onDeviceReady, false); } // Based on geo.js by Tero Karvinen 2015 http://TeroKarvinen.com // main & globals var watchGeo=null; main();
geo/platforms/android/AndroidManifest.xml
You must manually add permissions to Android manifest. The permissions are ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_LOCATION_EXTRA_COMMANDS and optionally ACCESS_MOCK_LOCATION.
<?xml version='1.0' encoding='utf-8'?> <manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.terokarvinen.geo" xmlns:android="http://schemas.android.com/apk/res/android"> <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name" android:supportsRtl="true"> <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="@android:style/Theme.Black.NoTitleBar" android:windowSoftInputMode="adjustResize"> <intent-filter android:label="@string/launcher_name"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="22" /> </manifest>
Testing Geolocation
When you see coordinates on screen, you have succeeded.
On a physical cell phone: go outside, wait for a while. If you don’t immediately get a reading, try to see if other apps, such as built-in map, see your location.
On official Android SDK emulator on Linux and Windows: Connect to the emulator with ‘telnet’ or netcat ‘nc’. Host is obviously localhost, the port number is listed with ‘adb devices’. For example ‘nc localhost 5554’. Once you have the control interface open, try ‘help’. You can set mock location with ‘geo fix 40.3730345 -3.9193921’. Remember to test with a real, physical phone later.
On BlueStacks on Windows (consider upgrading to Linux): Click the location marker icon on the bottom of BlueStacks window, drag the map so that red marker points your wished location, click “Set location”. Remember to test with a real, physical phone later.
Hope you enjoy your location.
Download
Feeling lazy? You can download the essential files. Create a new project normally, add android platform and geolocation plugin. Then extract this zip file and copy it over the project.
Download geolocation-cordova-android-karvinen-2015.zip
Troubleshooting
If you see some coordinates on your app, go pat yourself on the back. But if you need troubleshooting, here is an obvious trick.
Logging, showing messages related to Cordova
$ adb logcat chromium:D SystemWebViewClient:D *:S
console.log(s);
$(“#status”).text(s);
}
function onDeviceReady() {
d(“onDeviceReady()”);
}
function geoWin(pos) {
d(“geoWin(): “+pos.coords.latitude+”, “+pos.coords.longitude);
}
function geoFail(error) {
d(“geoFail(): “+error.code+”: “+error.message);
}
function startGeoWatch() {
d(“startGeoWatch()”);
opt = {timeout: 1000, enableHighAccuracy: true};
watchGeo = navigator.geolocation.watchPosition(geoWin, geoFail, opt);
}
function main() {
document.addEventListener(‘deviceready’, onDeviceReady, false);
startGeoWatch();
}
// main & globals
var watchGeo=null;
main();