AndroidManifest.xml is a mandatory configuration file for every Android application that describes its components, permissions, and metadata. The Android system reads this file when installing and launching each app. According to Android Developers, 2025, without a correct manifest, the app cannot be installed on the device. AndroidManifest.xml registers Activity, Service, BroadcastReceiver, and ContentProvider for the operating system.
Key Takeaways
AndroidManifest.xml is the root configuration file in XML format that every Android project must have in the app/src/main directory. The Android system parses it before running any app code — during APK parsing at install time. If the manifest has a syntax error or is missing a required declaration, installation stops with an error message.
The file contains a complete declaration of the app: a list of all components (Activity, Service, BroadcastReceiver, ContentProvider), requested permissions, minimum SDK version, hardware requirements, and theme and style configuration. Every component that can be invoked by the system or other apps must be explicitly declared in the manifest. This is a security requirement: without an explicit declaration, the component is unavailable for invocation.
Without a properly configured manifest, the app cannot be installed via Google Play or sideloading. The system checks the manifest during APK parsing and rejects installation on errors. Google Play also scans the manifest for unsafe configurations: if exported=true on a component without intent-filter, a warning is issued, and if mandatory permissions for targetSdk 34+ are missing, publishing is blocked. Therefore, understanding the manifest structure is a mandatory skill for Android developers.
Every Android app component must be explicitly registered in the manifest. This is a mandatory platform requirement for all four component types. Without registration, the component cannot be created by the system, and attempting to launch it will result in an ActivityNotFoundException or similar exception. Components are registered inside the application tag in an order that does not affect their operation.
The activity tag registers an app screen. The exported attribute determines whether other apps can launch this Activity. Starting from Android 12, missing exported when intent-filter is present causes a build error — this is a security requirement. The entry point is set via intent-filter with action MAIN and category LAUNCHER. Each Activity must have a unique android:name matching the full or relative class name.
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The service tag defines a background service. Starting from Android 8, background services have strict limitations: a foreground service requires a mandatory user-visible notification with an icon, and a bound service lives only while a client is bound to it. Services running in the background without a notification are automatically terminated by the system within a few minutes after the app moves to the background. For long-running tasks, use WorkManager instead of Service.
<service
android:name=".SyncService"
android:exported="false"
android:foregroundServiceType="dataSync" />
The receiver tag declares a receiver for system or custom broadcast messages. Starting from Android 8, most implicit broadcasts are no longer delivered to statically declared receivers in the manifest. Instead, it is recommended to register receivers dynamically via Context.registerReceiver in code. Exceptions include some system broadcasts such as BOOT_COMPLETED, which still require static registration in the manifest.
<receiver
android:name=".ConnectivityReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Every dangerous permission in Android requires a declaration in the manifest via the uses-permission tag. Starting from Android 6, dangerous permissions are requested at runtime through a user dialog, but the manifest declaration remains mandatory. Without it, the requestPermissions method throws a SecurityException. Normal-level permissions such as INTERNET and ACCESS_NETWORK_STATE are granted automatically at install time.
| Permission | Purpose |
|---|---|
| CAMERA | Access to the device camera for photos and videos |
| ACCESS_FINE_LOCATION | Precise geolocation via GPS and network |
| RECORD_AUDIO | Audio recording from the device microphone |
| READ_CONTACTS | Reading contacts from the phonebook |
| POST_NOTIFICATIONS | Sending notifications on Android 13+ |
The uses-permission-sdk-23 tag specifies permissions needed only on Android 6.0+. This allows maintaining compatibility with older versions without requesting non-existent permissions. For example, POST_NOTIFICATIONS is only available on Android 13+, so it must be specified via uses-permission-sdk-33 to avoid an unknown permission error on older devices. The maxSdkVersion attribute in uses-permission allows automatically revoking unnecessary permissions when updating the app on newer Android versions.
Normal-level permissions (INTERNET, ACCESS_NETWORK_STATE) are granted automatically at install time and do not require a runtime request. They are also declared via uses-permission but are not shown to the user in a dialog. To control access to app components from other applications, the permission-protected components mechanism is used: you can specify a custom permission at the Activity or Service level, which will be checked by the system when the component is called from outside. This provides an additional security layer for inter-process communication.
The intent-filter tag in the manifest declares which implicit intents a component can handle. This is the mechanism through which Android connects system or custom actions to the app. An intent filter consists of three elements: action, category, and data. All three can be combined for precise description of which intents the component should receive. The system selects the appropriate component based on the most specific filter.
<activity android:name=".DeepLinkActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="itsectr.com"
android:pathPrefix="/app" />
</intent-filter>
</activity>
The autoVerify attribute enables Android App Links verification: the system contacts the server to confirm domain ownership. Without verification, deep links work through the standard chooser dialog where the user selects which app to open the link with. After successful verification, links open directly in the app without a dialog. Google Search Console also uses autoVerify to index deep links and display them in search results.
Filters with action.VIEW and the DEFAULT and BROWSABLE categories handle links from browsers, emails, and other apps. This is the main mechanism for implementing deep links in Android. To support custom URL schemes such as myapp://, simply specify the scheme without a host. However, Google recommends using HTTPS deep links instead of custom schemes because they are more secure and do not require additional permissions. Custom schemes can be intercepted by any app that registers the same scheme.
The root manifest tag contains package, version, and SDK attributes. The application tag holds global settings: theme, icon, label, and debugging flags. Manifest attributes define versioning at the package level, while application attributes determine the overall appearance and behavior of the app. Values can be resource references via @-syntax or string literals.
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itsectr.myapp"
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34" />
<application
android:label="MyApp"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.MyApp"
android:supportsRtl="true"
android:allowBackup="true">
<!-- App components -->
</application>
</manifest>
The meta-data tag inside application allows storing arbitrary key-value pairs. This is convenient for configuring third-party libraries: API keys, endpoint URLs, and feature flags. Data from meta-data is accessible via PackageManager.getApplicationInfo().metaData at runtime. For example, Firebase and Google Maps use meta-data to pass access keys without hardcoding them in source code. Instead, keys are set in the manifest and can differ for different build flavors.
The android:extractNativeLibs attribute controls extraction of native libraries from the APK. For apps with targetSdk 34+, this attribute must be explicitly specified, otherwise the build may fail with INSTALL_FAILED_INVALID_APK error. If extractNativeLibs=false, native libraries remain inside the APK without unpacking, reducing the installed app size but increasing library loading time. For most modern apps, extractNativeLibs=false is recommended to reduce disk space usage on the user’s device.
The android:networkSecurityConfig attribute allows specifying a network security configuration file. This is especially important for apps with targetSdk 28+, where HTTP traffic is blocked by default. The configuration file defines trusted certificates, domains for HTTP connections, and certificate pinning rules. This replaces the deprecated android:usesCleartextTraffic attribute and provides a more flexible mechanism for managing connection security at the OS level.
The android:largeHeap attribute requests an increased heap size for the app. By default, Android allocates each app a limited amount of memory that depends on the device and OS version. If the app works with heavy images, videos, or large datasets, largeHeap can prevent OutOfMemoryError. However, abusing this attribute is harmful: an app with high memory consumption gets terminated faster by the system when resources are low. Use largeHeap only after profiling and confirming the need.
Frequently Asked Questions
Starting from Android 12, the absence of the exported attribute when intent-filter is present causes a build error. The system requires explicit visibility for every component with intent-filter — this is a security measure to prevent accidental exposure of components to other apps. For an Activity without intent-filter, exported defaults to false.
Yes, but the launcher will display multiple app icons. Each Activity with MAIN/LAUNCHER becomes a separate entry point. This is used to create shortcuts to different sections of the app, for example to go directly to settings or to create a new record. Each icon opens the corresponding Activity directly.
Android merges manifests from libraries with the main app manifest. In case of attribute conflicts, tools:replace or tools:node=“merge” is used to resolve them. This mechanism is automatic: when a library is added via Gradle, its manifest is merged with the main one. To override or replace an attribute from a library, use tools:node=“remove” or tools:replace=“attributeName”.
Typical reasons: the permission is not declared in the manifest via uses-permission, it is a normal-level permission (no runtime request needed), the user selected “Never ask again” and the permission is permanently denied, or the targetSdkVersion is below 23 where permissions are requested at install time. For diagnostics, check the manifest and logs via adb logcat.
The android:debuggable attribute enables app debugging via ADB. For release builds on Google Play, it must be false. If debuggable=true in a release build, an attacker can connect to the app via ADB, read data, and execute arbitrary code. Google Play automatically blocks publishing of builds with debuggable=true.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also