The manifest, and what it declares
Before Android runs a single line of your Kotlin, it reads one XML file to find out what your app is: its name and icon, which screen opens from the launcher, which other apps may start it, and what it intends to do with the network, the camera or your location. That file is AndroidManifest.xml. Get it wrong and the build fails, the icon never appears, or the app crashes the moment it tries to fetch a price.
The starter's manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Twenty lines. Read them from the outside in.
<manifest> is the root, and declares the android: XML namespace that every attribute below uses. Older projects also had a package="..." attribute here; the package now comes from namespace in app/build.gradle.kts, and the build adds it for you, as you will see in the merged manifest.
<application> describes the app as a whole:
| Attribute | What it does here |
|---|---|
android:icon="@mipmap/ic_launcher" |
The launcher icon, pointing at res/mipmap-anydpi/ic_launcher.xml. |
android:label="@string/app_name" |
The name under the icon, "Mandi Bhav", read from strings.xml. |
android:theme |
The platform theme behind your Compose UI. It mostly decides the window background before Compose draws. |
android:supportsRtl="true" |
Layouts mirror for right-to-left languages such as Urdu. |
android:allowBackup="true" |
Android may back up the app's data to the user's Google account. |
The @mipmap/... and @string/... syntax is a resource reference: "look this up in res/". You will meet it properly in the resources lesson.
<activity> declares a screen-hosting component. android:name=".MainActivity" is shorthand: the leading dot means "relative to the namespace", so it expands to com.riztechacademy.mandibhav.MainActivity. Every activity in the app must be declared like this; the next lesson shows what happens when one is not.
The launcher intent filter
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
An intent is a message asking Android to do something, such as "start the main screen of this app". An intent filter is an activity raising its hand: "I can handle intents that look like this". These two lines together mean:
MAIN: this is an entry point to the app, not a screen reached from inside it.LAUNCHER: show it in the phone's app drawer.
When Kavita taps the Mandi Bhav icon, the launcher sends exactly that intent, and Android starts the activity that declared it. Remove the filter and the app still builds and installs, but there is no icon to tap and Android Studio has no default activity to run. Put the filter on two activities and the app shows two icons, which is occasionally deliberate and usually a mistake.
android:exported, and why Android 12 insists on it
android:exported answers one question: may other apps start this component? true means yes. false means only your own app can.
The launcher is another app, so the launcher activity must be exported="true". A screen that only your app opens, such as a price-detail screen, should be exported="false", because an exported activity is a door any app on the phone can knock on, with any data it likes in the intent.
Before Android 12, if you left the attribute out, Android guessed: any activity with an intent filter was exported. That guess made screens public that developers never meant to be. Apps targeting Android 12 (API 31) and higher must now say it explicitly whenever there is an intent filter. Delete the attribute from the starter and build:
AndroidManifest.xml:12:9-18:20 Error:
android:exported needs to be explicitly specified for element
<activity#com.riztechacademy.mandibhav.MainActivity>. Apps targeting
Android 12 and higher are required to specify an explicit value for
`android:exported` when the corresponding component has an intent
filter defined.
* What went wrong:
Execution failed for task ':app:processDebugMainManifest'.
> Manifest merger failed : android:exported needs to be explicitly specified ...
Notice the task name, processDebugMainManifest, and the words "Manifest merger". The manifest is not used as you wrote it. More on that below.
Permissions are declarations
In a few modules Mandi Bhav downloads mandi prices, and an app cannot open a network connection without declaring the INTERNET permission. The line goes inside <manifest>, above <application>:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
...
<uses-permission> is a declaration: "this app intends to use the network". What happens next depends on the kind of permission:
| Kind | Examples | What the user sees |
|---|---|---|
| Normal | INTERNET, ACCESS_NETWORK_STATE |
Nothing. Granted automatically at install. |
| Dangerous (runtime) | ACCESS_FINE_LOCATION, CAMERA, POST_NOTIFICATIONS |
A dialog, which your code must request at the right moment, and which the user can refuse. |
So INTERNET costs you one line and no dialog. Location, which the nearest-market feature will need later, is a dangerous permission: the manifest line is necessary but not sufficient, and the course has a whole lesson on asking for it without the user refusing.
The trap is forgetting the line. Without it nothing fails at build time; the first network call fails at run time with a SecurityException mentioning a missing INTERNET permission, often wrapped inside a networking library's error so that it reads like a connectivity problem. A farmer on patchy rural data and an app with no permission look identical from the outside. When "no network" happens on Wi-Fi in your own office, check the manifest first.
Do not add permissions you do not use. Each one is listed on the Play Store page, and a price app that asks for contacts will rightly be uninstalled.
The merged manifest
Your manifest is twenty lines. The one inside the APK is not. Every library you depend on can ship its own manifest, and the build merges them all, together with values from build.gradle.kts. After ./gradlew assembleDebug, the result is at:
app/build/intermediates/merged_manifests/debug/processDebugManifest/AndroidManifest.xml
Here is part of it for the starter:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.riztechacademy.mandibhav"
android:versionCode="1"
android:versionName="0.1" >
<uses-sdk
android:minSdkVersion="26"
android:targetSdkVersion="36" />
<application
android:allowBackup="true"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
android:debuggable="true"
...>
<activity
android:name="com.riztechacademy.mandibhav.MainActivity"
android:exported="true" >
...
</activity>
<activity
android:name="androidx.compose.ui.tooling.PreviewActivity"
android:exported="true" />
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="com.riztechacademy.mandibhav.androidx-startup"
android:exported="false" >
...
</provider>
Things you never wrote have appeared:
package,versionCode,versionName,minSdkVersionandtargetSdkVersion, all copied fromapp/build.gradle.kts. This is why you set them in Gradle and not in the manifest.android:debuggable="true", because this is the debug build.PreviewActivity, fromui-tooling, which the starter adds withdebugImplementation; it lets Android Studio run a@Previewon a device. It is not in the release manifest.- A
providerand areceiverfrom AndroidX libraries that initialise themselves at startup.
The merge log beside it, app/build/outputs/logs/manifest-merger-debug-report.txt, lists every library manifest that took part: 51 of them for this small starter, from androidx.core to androidx.profileinstaller.
In Android Studio, open your AndroidManifest.xml and click the Merged Manifest tab at the bottom of the editor. It shows the same result, colour-coded by which manifest each line came from, and lists any merge errors with a suggested fix.
When a library does something you did not expect, such as adding a permission, the merged manifest is where you find out. It is also where the Play Store's view of your app comes from.
Check your work
What does the leading dot in .MainActivity mean? Relative to the namespace: it expands to com.riztechacademy.mandibhav.MainActivity.
Which two intent-filter lines put an app in the launcher? The MAIN action and the LAUNCHER category.
What does android:exported="false" mean? Only your own app can start that component.
Why must the launcher activity be exported? The launcher is a different app, so it must be allowed to start it.
Why did Android 12 make exported mandatory? The old default exported any component with an intent filter, which made screens public by accident.
Does INTERNET show the user a dialog? No; it is a normal permission, granted at install.
Where does minSdkVersion in the merged manifest come from? From minSdk in app/build.gradle.kts.
Where is PreviewActivity from, and is it in the release build? From the ui-tooling library, added with debugImplementation. Practice 5 confirms it: the release merged manifest has neither PreviewActivity nor android:debuggable.
Practice 6: who objects to minSdk = 21? The merger fails with uses-sdk:minSdkVersion 21 cannot be smaller than version 23 declared in library [androidx.navigationevent:navigationevent-android:1.0.0]. You never added that library; activity-compose brought it in. The suggestions are a compatible library, a higher minSdk, or tools:overrideLibrary, which the message itself warns "may lead to runtime failures". Lowering minSdk means checking every library you depend on, directly or not.
Practice
- Find each
<application>attribute in the starter and say, without looking, what it does. Then check the table. - Build the app and open the merged manifest file. Find three elements that are not in your source manifest and name the library each came from, using the Merged Manifest tab or the merger report.
- Add the
INTERNETpermission and build. Confirm it appears in the merged manifest. - Break it on purpose: delete
android:exported="true"and build. Read the error and find the task name in it. Restore the attribute. - Build the release variant with
./gradlew assembleReleaseand openapp/build/intermediates/merged_manifests/release/processReleaseManifest/AndroidManifest.xml. IsPreviewActivitythere? Isandroid:debuggable? - Harder: change
minSdkto 21 inapp/build.gradle.ktsand build. A library in the merge will object to the lower value. Read which one, and what it suggests, then putminSdkback to 26 and write one sentence on why loweringminSdkis never a single-line change.
Official documentation
- Android Developers — App manifest overview — Every top-level element, and what the build fills in from Gradle.
- Android Developers — activity element — The full attribute reference, including
android:exportedand the Android 12 rule. - Android Developers — Manage manifest files — Merge priorities, the Merged Manifest view, and the
tools:markers for overriding a library's entries. - Android Developers — Permissions on Android — Install-time and runtime permissions, and which group each permission is in.
Next: activities, and why a modern Compose app usually has exactly one.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Selected students who finish a course can join our internship, with real-world projects and code review from a working engineer.
About the internship