how to create a plugin that writes a new activity in Manifes.xml

Hi @emuter

You can build any XML you need. Under the hood Expo uses xml2js to manipulate the XML that ultimately ends up in AndroidManifest.xml.

See the docs here:

XML builder usage

Your config plugin will receive a JavaScript object which represents the AndroidManifest.xml and you will have to find the “application” and insert a new “activity” into it. Then withAndroidManifest will convert the JavaScript object to XML and write it to AndroidManifest.xml.

So off the top of my head, maybe something like this (untested) will work:

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

const customActivity = {
  activity: {
    $: {
      'android:name': 'com.myapp.CustomActivity',
      'android:showWhenLocked': 'true',
      'android:turnScreenOn': 'true',
      'android:launchMode': 'singleTop',
      'android:showOnLockScreen': 'true',
    },
  },
};

function addCustomActivityToMainApplication(androidManifest, attributes) {
  const { manifest } = androidManifest;

  // Check if there are any application tags
  if (!Array.isArray(manifest['application'])) {
    console.warn('withAndroidMainActivityAttributes: No application array in manifest?');
    return androidManifest;
  }

  // Find the "application" called ".MainApplication"
  const application = manifest['application'].find(
    (item) => item.$['android:name'] === '.MainApplication'
  );
  if (!application) {
    console.warn('addCustomActivityToMainApplication: No .MainApplication?');
    return androidManifest;
  }

  // Check if there are any activity tags
  let activities = application["activity"];
  if (!Array.isArray(activities)) {
    console.warn('addCustomActivityToMainApplication: No activity array in .MainApplication?');
    return androidManifest;
  }

  // If we don't find the custom activity, add it
  // If we do find it, assume it's correct
  if (
    !activities.find(
      (item) =>
        item.$["android:name"] === "com.myapp.CustomActivity"
    )
  ) {
    activities.push(customActivity);
  }

  return androidManifest;
}

module.exports = function withAndroidCustomActivity(config, attributes) {
  return withAndroidManifest(config, (config) => {
    config.modResults = addCustomActivityToMainApplication(config.modResults, attributes);
    return config;
  });
};

Of course you could make that more general and take parameters like the name and other attributes from the plugins section of app.json.

I have never tried adding another activity to one of my apps before, so no idea what you need to do other than updating AndroidManifest.xml.

2 Likes