Trying to update AndroidManifest.xml to stop GPS being required

Currently, my App cannot be installed on Android devices that do not have GPS even though GPS is not actually required for the App to function properly. This is due to the following in the AndroidManfest.xml file:

<uses-feature android:name="android.hardware.location.gps"  />

I need to update the AndroidManifest.xml file during build to the following:

<uses-feature android:name="android.hardware.location.gps" android:required="false" />

I am trying to use “edit-config” options within my config.xml to achieve this as follows:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/uses-feature[@android:name='android.hardware.location.gps']" xmlns:android="http://schemas.android.com/apk/res/android">
   <uses-feature android:name="android.hardware.location.gps" android:required="false" />
</edit-config>

This works fine if the AndroidManifest.xml file already exists and contains the “uses-feature…” setting already, but this fails with the following error if the AndroidManifest.xml file doesn’t exist, this is a problem because I use Ionic AppFlow to build the app so the following error occurs when I try and do a build with AppFlow. I can also make the following error occur locally by removing the Android platform and then re-adding it:

Android project created with cordova-android@8.1.0
Error: Unable to graft xml at selector "/manifest/uses-feature[@android:name='android.hardware.location.gps']" from "C:\Projects\MyApp\platforms\android\app\src\main\AndroidManifest.xml" during config install

Does anyone have a solution to this?

I have also tried using the “custom-config” plugin but this seems to cause other issues such as duplicates of the relevant “uses-feature…” in the AndroidManifest.xml file.

I think part of the problem is that I have multiple plugins that are trying to apply this setting (i.e. “cordova.plugins.diagnostic.modules”, “cordova-plugin-geolocation”, possibly “cordova-plugin-googlemaps” as well?).

I have now resolved this a different way using a hook script as follows, I am sure there is probably a nicer way of doing this if anyone has any suggestions or improvements to my script?

In my config.xml I added the following within the “Android” platform:

<platform name="android">
   .....
   <hook src="scripts/set-gps-not-required.js" type="after_prepare" />
   .....
</platform>

I then created a folder in the root of my project called “scripts” and added the following file named “set-gps-not-required.js”:

#!/usr/bin/env node

module.exports = function(context) {

  var fs = require('fs'),
      path = require('path');

  var platformRoot = path.join(context.opts.projectRoot, 'platforms/android');
  var manifestFile = path.join(platformRoot, 'app/src/main/AndroidManifest.xml');

  console.log("Platform ROOT: " + platformRoot);
  console.log("Manifest file: " + manifestFile);

  // If manifest file exists
  if (fs.existsSync(manifestFile)) {
    console.log("Manifest file exists");

    // Read manifest file
    fs.readFile(manifestFile, 'utf8', function (err, data) {
      if (err) {
        throw new Error('Unable to find AndroidManifest.xml: ' + err);
      }

      // Remove any current GPS settings
      data = data.replace(/<uses-feature android:name="android.hardware.location.gps" \/>/g, '');
      data = data.replace(/<uses-feature android:name="android.hardware.location.gps" android:required="false" \/>/g, '');

      // Add GPS uses-feature (setting to required false)
      data = data.replace("</manifest>", 
        '\t<uses-feature android:name="android.hardware.location.gps" android:required="false" \/>\n</manifest>');

      // Replace manifest file with updated version
      if(data){
        fs.writeFile(manifestFile, data, 'utf8', function (err) {
          if (err) throw new Error('Unable to write AndroidManifest.xml: ' + err);
        })
      }
    });
  } else {
    console.log("Manifest file DOES NOT exist");
  }
};
3 Likes