DEV Community

Attilio Carotenuto
Attilio Carotenuto

Posted on

Managing the Android Manifest in Unity

The Android Manifest is an XML file that describes an Android game or application, including capabilities, permissions, visual information, hardware features, entry point and so on.

While each Android game has a single manifest, your Unity project will have multiple ones. When building your game, Unity generates a final manifest by merging multiple intermediate files.

In this article I will cover how Unity handles the different manifests, including troubleshooting tips and advanced modification techniques.

Generating the game Manifest

When working on an Android Unity project, Unity will maintain multiple manifests. These include the Library Manifest, the Launcher Manifest, and multiple optional Plug-in Manifests.

The Library Manifest, also called Main Manifest, is the base template used to generate the final manifest. It defines the entry activity, along with theme, permissions and so on.

Unity provides a default one, but you can also create your own, for example if you’d like to have a custom Activity with some extra logic. In this case, you’ll need to add that in the Project Settings, under Player - Publishing Settings.

Image description

The Launcher Manifest defines how the game looks and behaves on device, such as App Name, Icon, install location, supported Screen Density and so on. This is generated based on your Player Settings, so you normally don’t need to tweak it manually.

One exception is when the project is going to be embedded into another project. In that case, you can supply a custom Launcher Manifest in the Project Settings, under Player - Publishing Settings, right below the Main Manifest.

Finally, most Plug-ins and SDK will supply their own manifest, defining additional required permissions and dependencies. You normally don’t need to modify these, as they will get merged into the final manifest as part of the build process, assuming the packages are well designed and up to date. Unfortunately it’s not uncommon to find Plugins that do not play well with other plugins, forcing for example their own custom activity or conflicting dependencies. In that case you’ll need to do a bit of tinkering to make them work together.

In case of conflicts, the Library manifest gets priority over the additional Plugins manifests. This is useful for example when using tools:replace or tools:merge to modify entries from manifests with lower priority.

At build time Unity will use Gradle to generate a final manifest, merging the Library, Launcher, and all the Plugins and SDKs manifests.

Some extra permissions might also be added, depending on the Editor and Project Settings. For example, if you are using the Mobile Notifications package and set a schedule, Unity will add android.permission.SCHEDULE_EXACT_ALARM and related permissions to the manifest at build time.

Image description

Scripts can also cause extra permissions to be added. For example, calls to Handheld.Vibrate will add the VIBRATE permission, while most networking calls, such as UnityWebRequest, Ping, or usage of Unity Analytics, will add the INTERNET permission.

You can inspect the final manifest by expanding the APK or App Bundle, then navigating to the manifest folder.

Alternatively you can use the Android Studio APK Analyzer, by selecting Build - Analyze APK. Despite the name, this also works for App Bundles.

Image description

The folder structure will be different whether you’re building an APK or an App Bundle, and if your game uses Play Asset Delivery packs.

Modifying the Manifest via Scripting

If you are using Unity 6, you can use AndroidProjectFilesModifier to modify your Manifest file after the Gradle project is created, and before Unity goes ahead and completes the build process.

The Setup callback is optional and it’s called before the build starts. It’s used to define which files or external dependencies will be edited or created, but should not make any modifications or create new files directly itself. This instead should happen in OnModifyAndroidProjectFiles.

public class ModifyGradleProjectScript : AndroidProjectFilesModifier
{
    public override AndroidProjectFilesModifierContext Setup()
    {
        var context = new AndroidProjectFilesModifierContext();          
        context.Outputs.AddManifestFile("gamemodule/src/main/AndroidManifest.xml");
        return context;
    }

    public override void OnModifyAndroidProjectFiles(AndroidProjectFiles projectFiles)
    {
        var modifiedManifest = new AndroidManifestFile();
                    modifiedManifest.Manifest.AddUsesPermission("android.permission.RECORD_AUDIO");
        projectFiles.SetManifestFile("gamemodule/src/main/AndroidManifest.xml", modifiedManifest);
    }
}
Enter fullscreen mode Exit fullscreen mode

If instead you’re using Unity 2022 or older, you can use IPostGenerateGradleAndroidProject. Similarly to AndroidProjectFilesModifier, this provides a callback to modify your final Manifest file after the Gradle project is created, before Unity goes ahead and completes the build process. To do so, you can navigate to it using the provided path.

class PostGradleBuildProcessor : IPostGenerateGradleAndroidProject
{
    public int callbackOrder { get { return 0; } }

    public void OnPostGenerateGradleAndroidProject(string path)
    {
            Debug.Log("PostGradleBuildProcessor.OnPostGenerateGradleAndroidProject - Path: " + path);
    }
}
Enter fullscreen mode Exit fullscreen mode

This method is now deprecated.

Note that, since Unity uses an incremental build system, IPostGenerateGradleAndroidProject might not be invoked if no changes to the Manifest or dependencies are made since the latest build, or it could give unexpected results (such as keeping entries that should be removed). If that happens, you can clear the Build Cache and start a clean build. AndroidProjectFilesModifier, on the other hand, is safe to use with incremental builds.

Troubleshooting the merged Manifest

While having Gradle and Unity generate the final manifest is convenient, sometimes it’s hard to understand where certain permissions or changes are coming from.

In order to do so, we can use the Manifest Merger logs.

After a successful build, navigate to /Library/Bee/Android/Prj/[IL2CPP or Mono2x]/Gradle/launcher/build/intermediates/manifest_merge_blame_file/[debug or release]

There, you’ll find a file called manifest-merger-blame-debug-report, which is the Manifest Merger logs. This file decorates each line of the manifest with extra information about the source of that line.

For example, we can see here that unityLibrary:mobilenotifications.androidlib, which is the MobileNotifications package, is adding the RECEIVE_BOOT_COMPLETED into the final manifest.

43  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- Permission will be merged into the manifest of the hosting app. -->
43-->[:unityLibrary:mobilenotifications.androidlib] [path]/Library/Bee/Android/Prj/IL2CPP/Gradle/unityLibrary/mobilenotifications.androidlib/build/intermediates/merged_manifest/release/AndroidManifest.xml:8:5-81
43-->[:unityLibrary:mobilenotifications.androidlib] [path]/Library/Bee/Android/Prj/IL2CPP/Gradle/unityLibrary/mobilenotifications.androidlib/build/intermediates/merged_manifest/release/AndroidManifest.xml:8:22-78
Enter fullscreen mode Exit fullscreen mode

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more