Understanding the Android manifest file and its key elements

The Android manifest is a compact XML file that tells the operating system what an app contains, what it needs, and how other apps may interact with it. Every Android application relies on a manifest, even when developers rarely open it after creating a new project.

This file matters during installation, app launch, permission review, and security checks. Android reads manifest declarations before running many components, so a small attribute can affect whether an app works correctly on a Pixel in Sydney, a Samsung handset in Melbourne, or a budget device used on regional networks.

The manifest also provides useful context for release management. It records the application identity, supported Android versions, required device features, declared permissions, and entry points such as activities and services. These declarations influence how an app appears in Google Play and whether it can be installed on a particular device.

Modern Android development has made manifest behaviour more security-focused. Attributes such as android:exported, permission protection levels, package visibility rules, and foreground service declarations deserve careful attention. Treating the file as boilerplate can lead to failed builds, inaccessible screens, or unnecessary access to personal data.

What the manifest file does

The primary manifest is normally stored at app/src/main/AndroidManifest.xml. It uses XML elements and attributes to describe application metadata to Android rather than implementing business logic. You would not place database queries, layout code, or network requests in this file.

At the root is the <manifest> element, which contains the app’s namespace and declarations such as permissions. Inside it, the <application> element defines shared settings, including the application icon, label, theme, backup behaviour, and registered components.

Gradle can merge manifest files from the main source set, build variants, and imported libraries. This is convenient, but it can make the final packaged manifest different from the file you edit. Android Studio’s Merged Manifest view helps identify where a permission or component declaration originated.

Application identity and version settings

Older projects commonly placed the package name in the manifest. Current Android projects generally define the namespace in Gradle and use applicationId as the installable identity. The application ID is what distinguishes one published app from another in Google Play, while the namespace organises generated code.

The manifest may include android:label, android:icon, android:roundIcon, android:theme, and android:supportsRtl. Labels and icons are visible to users, so Australian developers should test branding in both English and accessibility settings rather than assuming a label will fit every launcher.

Version information is now normally controlled through Gradle’s versionCode and versionName. A higher version code is required for updates, while the version name is the human-readable value shown in distribution channels. Keep these settings consistent across internal testing, staged releases, and the Australian Google Play market.

Components that make an app work

Activities represent user-facing screens. The launcher activity usually has an <intent-filter> containing MAIN and LAUNCHER, allowing Android to display it as the app’s entry point. Deep links can use additional filters to respond to web URLs or custom schemes.

Services perform work without a traditional screen, although current Android versions impose strict limits on background execution. A foreground service needs a visible notification and, on recent releases, an appropriate foreground service type. For scheduled work such as reminders, review the AlarmManager scheduling guide alongside battery and exact-alarm rules.

Broadcast receivers respond to system or application events, while content providers expose structured data through controlled interfaces. These components should be registered only when needed. A receiver that is exported accidentally can accept messages from other applications, and an overly broad provider can expose sensitive records.

Permissions and device capabilities

The <uses-permission> element requests access to protected features. Examples include ACCESS_FINE_LOCATION, CAMERA, RECORD_AUDIO, and POST_NOTIFICATIONS. Declaring a permission in the manifest is only the first step for dangerous permissions; the app must also request runtime approval at an appropriate moment.

Permission design should reflect local expectations and Australian privacy obligations. A shopping app serving customers in Brisbane should not request location access merely to display products, while a bushfire information app may have a clear reason to provide location-based alerts. Explain the benefit before showing the system prompt and offer useful functionality when access is declined.

The <uses-feature> element describes hardware or software capabilities, such as a camera, Bluetooth, or GPS. Setting android:required="false" can keep an app available to users on devices without that feature. This is important in the local market, where users have a broad mix of flagship phones, low-cost Android models, tablets, and older handsets.

Manifest element Main purpose Typical caution
<manifest> Root container and permission declarations Keep identity settings aligned with Gradle
<application> Shared app configuration Avoid unsafe global settings
<activity> User-facing screen Declare exported access deliberately
<service> Background or foreground work Follow modern execution limits
<receiver> Receives broadcast events Restrict external broadcasts
<provider> Shares structured data Protect authorities and URI access
<uses-permission> Requests protected capability Ask only for necessary access
<intent-filter> Describes supported actions and links Avoid overly broad matching
<queries> Declares visible app interactions Add only required package visibility

Intent filters and exported components

An intent filter tells Android which actions, categories, or data patterns a component can handle. A browser link, share target, file opener, and launcher entry point can all use filters. Multiple filters may be appropriate, but each one should describe a specific interaction instead of accepting every possible intent.

android:exported determines whether another application can launch a component. Android 12 and later require an explicit value for components with intent filters. Set it to true only when external access is part of the design; otherwise use false and keep internal screens private.

Deep links need additional care because a matching URL can open the app from messages, websites, or search results. Prefer verified Android App Links for domains you control, validate incoming data, and avoid trusting parameters simply because the manifest matched them.

Metadata, queries, and compatibility

The <meta-data> element stores key-value information read by the operating system or an SDK. Maps, analytics tools, notification services, and other libraries may use metadata for API keys or configuration. Secrets should not be treated as safe merely because they are placed in XML; packaged resources can be inspected.

The <queries> element manages package visibility from Android 11 onwards. If an app needs to check whether a compatible browser, payment application, or document handler is installed, declare the relevant interaction. Avoid broad visibility declarations because they increase complexity and may raise privacy concerns during store review.

Compatibility settings include minSdk, targetSdk, and supported screen or configuration behaviour. These are generally defined in Gradle, while manifest declarations express runtime requirements. Test on common Australian carrier conditions, including variable connectivity outside Melbourne and Sydney, rather than relying only on a fast development Wi-Fi connection.

Merging, testing, and release checks

Library manifests are merged into the application manifest during the build. A dependency may add a provider, permission, receiver, or metadata entry without an obvious change in your own XML. If the app suddenly requests an unexpected permission, inspect the merged output and use manifest merger tools to remove or replace declarations where appropriate.

Automated tests should verify that the launcher opens correctly, permissions appear at the intended point, deep links resolve safely, and exported components reject unauthorised input. Browser and web-flow checks can complement Android tests; teams that maintain broader integration coverage may find Thucydides web tests useful when validating connected user journeys.

Before publishing, inspect the generated APK or app bundle, review the manifest in Android Studio, and test release builds rather than only debug builds. Check notification behaviour, backup rules, foreground service types, and device feature filtering. A release aimed at Perth or Adelaide should behave predictably on both current Android versions and the older devices still common in the market.

A well-maintained manifest is a security boundary, compatibility record, and launch map in one file. Keep declarations minimal, make external access explicit, and match every permission to a genuine user benefit. Apply these checks to your next Android build before uploading it to Google Play, and use the merged manifest as the final source of truth for what the app will actually ship.