Location services permissions in Android
To enable MobileFirst location services for Android, you must define the proper permissions.
The permissions that you require differ for versions earlier than Android 6.0 Marshmallow and versions starting from Android 6.0 Marshmallow onwards.
Before Android 6.0 Marshmallow
In versions of Android earlier than Android 6.0 Marshmallow, the following permissions are required:
- For Geo acquisition:
-
- ACCESS_COARSE_LOCATION
- ACCESS_FINE_LOCATION (when enableHighAccuracy=true)
- For WiFi acquisition:
-
- ACCESS_WIFI_STATE
- CHANGE_WIFI_STATE
For Android 6.0 Marshmallow and later
In Android 6.0 Marshmallow and later, geo acquisition (location) permissions require additional runtime permissions.
- Overview of runtime permissions
-
According to the Android 6.0 Marshmallow permissions model, in addition to defining permissions at installation, users must also allow or deny access to different features at runtime. Before an app accesses location services, it must check whether permission has already been granted and, if needed, request permission. Developers are responsible to perform the check before accessing any of the following methods in the WLDevice interface:
- startAcquisition
- acquireGeoPosition
- stopAcquisition
If permissions have not been requested or not granted, the MobileFirst API does not get a provider and returns an error, WLGeoErrorCodes.PERMISSION_DENIED, along with a message about the requested accuracy level.
- Checking and requesting permissions from the Android 6.0 Marshmallow API
-
- Checking if permissions have been granted
- Two levels of access permission are available from android.Manifest.permission:
- android.Manifest.permission.ACCESS_FINE_LOCATION
- android.Manifest.permission.ACCESS_COARSE_LOCATION
If permission has already been granted, the method returns the value PackageManager.PERMISSION_GRANTED.getContext().checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- Requesting permissions
- To ask the user for permission for the appropriate level of access,
use the inherited requestPermissions method, as
follows:
Calling this Android method displays a dialog box that prompts the app to grant permission and invokes onRequestPermissionsResult when the choice is made. Once this permission has been granted to the system, startAcquisition, stopAcquisition, and acquireGeoPosition are granted access to the location services. If the user denies access, these methods return the WLGeoErrorCodes.PERMISSION_DENIED error. See the sample at https://developer.ibm.com/mobilefirstplatform/documentation/getting-started-7-1/foundation/advanced-client-side-development/location-services-hybrid-applications/ for a full demonstration of how to handle the new Android 6.0 Marshmallow permissions model.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
- Using Android location services in a hybrid Android application environment
- Android 6.0 Marshmallow requires user permissions to be granted
at runtime. Because runtime JavaScript code
in the web framework of the hybrid app does not have access to the
Android API, these permissions must be requested and checked by the
native code before launching Apache Cordova. 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 can be called within the onInitWebFrameworkComplete API
or within any other startup API in the class.
This code requests permission if the permission has not already been granted. If the permission is still not granted, all requests for location services from the web framework fail.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); } }