← Home

Edit Android Manifest in Expo managed

December 09, 2021

If you enjoy building mobile apps with Expo like I do, you’ve probably encountered some limitations such as applying native configurations in the managed workflow. A few months ago this was not possible unless you eject to the bare workflow, but luckily since the release of Expo SDK 41 and the introduction of the custom development client, we are finally able to make native changes to the managed workflow.

The easiest way to apply native configuration in the managed workflow is to use Expo Config Plugins. A config plugin is a JavaScript function that reads and edits a native file such as Android manifest, Gradle config, IOS Infoplist, etc. By attaching this function to the Expo config file, the changes will be applied during the prebuild process.

The prebuild process is a phase where Expo generates all native files before building the app binaries, you can check the native files before building your application or your development client using the command expo prebuild

The following example will explains more the use of Expo config plugins.

Using a config plugin to edit Android manifest

In a React Native project if we want for example add or remove permission we simply edit the manifest file that’s located in the android folder, while expo managed workflow doesn’t allow access to this file, we have to build a plugin that modifies it’s content.

Let’s say we want to disable the audio recording permission that is generated by the expo camera library, for example to use only the camera torch, so no need to ask for the audio recording permission.

Let’s create a file for the modifier named android-manifest.plugin.js

const { withAndroidManifest } = require("@expo/config-plugins")

module.exports = function androiManifestPlugin(config) {
  return withAndroidManifest(config, async config => {
    let androidManifest = config.modResults.manifest

    // add the tools to apply permission remove
    androidManifest.$ = {
      ...androidManifest.$,
      "xmlns:tools": "http://schemas.android.com/tools",
    }

    // add remove property to the audio record permission
    androidManifest["uses-permission"] = androidManifest["uses-permission"].map(
      perm => {
        if (perm.$["android:name"] === "android.permission.RECORD_AUDIO") {
          perm.$["tools:node"] = "remove"
        }
        return perm
      }
    )

    return config
  })
}

And her’s how to add the plugin to app config:

{
  "expo": {
    ...
		"plugins": [
      ...
			"./path/to/file/android-manifest.plugin.js"
		]
  }
}

How the modifier works

withAndroidManifest uses android manifest mod to modify AndroidManifest.xml as JSON parsed with xml2js. For example this XML file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

Will be this JS object:

let obj = {
  manifest: {
    $: {
      "xmlns:android": "http://schemas.android.com/apk/res/android",
    },
    "uses-permission": [
      {
        $: {
          "android:name": "android.permission.RECORD_AUDIO",
        },
      },
      {
        $: {
          "android:name": "android.permission.ACCESS_FINE_LOCATION",
        },
      },
    ],
  },
}

withAndroidManifest plugin function require the current configuration as the first param and a callback which is the editor. modResults.manifest is the object representing the android androidManifest file, by returning the modified object we will get a manifest file similar to the following (we can check this with expo prebuild)

<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
>
  ...
  <uses-permission
    android:name="android.permission.RECORD_AUDIO"
    tools:node="remove"
  />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  ...
</manifest>

In future articles, we’ll dig deeper into the other modifiers.


Chafik Gharbi Full-stack web and mobile app developer with JavaScript.