The AndroidManifest — your app's ID card
One small XML file is the only part of your app Android reads before running anything. Learn what every line of it declares, why minSdk is no longer in it, and what the manifest merger does with the libraries you use.
The one file Android reads first
Your app is thousands of lines of Kotlin. Android has read none of them.
Before your app runs, and in fact at the moment it is installed, Android reads exactly one file to find out what this app is: AndroidManifest.xml. Everything the system knows about you — your name, your icon, which screen opens first, what you are allowed to ask for — comes from that file and nowhere else.
Get it wrong and your app will not appear on the home screen, or will refuse to start, or will be denied something it needs, and none of those failures will point at your Kotlin. So it is worth nine minutes.
Think about a shop opening on a high street.
Before a single customer arrives, the owner files a form with the council. Trading name. Which door is the public entrance. What they intend to sell. Whether they need a licence for anything special, like alcohol or late opening.
The council never reads the shop's recipes. It reads the form. If the form says the public entrance is round the back, that is where customers will be sent — regardless of what the shop would prefer.
The is that form, and Android is the council.
The whole file
This is the complete manifest from Dice Duel, the first app you build in Part 5. Not a simplified version — this is the real file, all twenty-six lines.
That is the entire file. There is no hidden extra part — this manifest is enough to describe a complete, installable, publishable Android app.
What is not in the manifest any more
If you look at an Android tutorial written before about 2018, you will see a <uses-sdk> block in the manifest holding minSdkVersion and targetSdkVersion, plus versionCode and versionName up on the <manifest> tag.
Those have all moved into app/build.gradle.kts:
1defaultConfig {
2 applicationId = "com.nativeworks.diceduel"
3 minSdk = 26
4 targetSdk = 35
5 versionCode = 1
6 versionName = "1.0"
7}They still end up in the manifest — the injects them during the build — but you write them in one place, in Kotlin, where they can differ between a debug and a release build. Lesson 2.7 is entirely about those SDK numbers, and comes back in Part 6.
This is why copying a manifest snippet off an old forum post so often fails. If you paste a <uses-sdk> block into a modern project, the build tells you to remove it — because Gradle is now the source of truth for that number.
Permissions
Anything genuinely sensitive has to be declared, in public, in this file. If it is not in the manifest, your app simply cannot do it — there is no way to ask at runtime for something you never declared.
Focus Flow, the third app in this course, asks for exactly one:
1<uses-permission
2 android:name="android.permission.POST_NOTIFICATIONS" />Declaring a is only half the job. For sensitive ones, you must also ask the user at runtime, and they may say no — your app has to still work when they do. Lesson 5.17 does this properly.
The habit worth forming now: declare the fewest permissions you can. Every one of them is shown to the user before they install, and a list of five for a dice game is a list of five reasons not to bother.
Your manifest is not the manifest that ships
Here is a genuinely surprising fact. The file above is not what ends up inside your .
Every you depend on ships its own tiny manifest. Compose needs a couple of declarations. The lifecycle library installs a startup component. A build step called the combines yours with every one of theirs into a single merged manifest, and that is what gets packaged.
You can read the whole merge decision, in order, in a real file the build writes:
app/build/outputs/logs/manifest-merger-debug-report.txtOpen it and you will find lines like this — this is genuine output from building Dice Duel:
1MERGED from [androidx.activity:activity-compose:1.9.3]
2MERGED from [androidx.compose.ui:ui-android:1.7.6]
3MERGED from [androidx.lifecycle:lifecycle-process:2.8.7]Thirty-odd libraries, each contributing a line or two. It is the best possible answer to "where did that thing in my manifest come from?" — and the first place to look when the merger refuses to merge, which is the most common failure in this whole lesson.
- Open Pocket Studio, tap Projects, open your Part 0 app.
- Tap Editor, open the file tree, and tap
app/src/main/AndroidManifest.xml. Read it against the walkthrough above — your file will be almost identical, with a different theme name. - Change the app's visible name. Open
app/src/main/res/values/strings.xmland edit the text inside<string name="app_name">to something new. - Tap Build, press Run, then look at your home screen. The label under the icon has changed — because the manifest pointed at the resource instead of holding the text.
- Now break it on purpose. In the manifest, change
android:name=".MainActivity"toandroid:name="MainActivity"— delete the dot. - Press Run and read the failure. Put the dot back.
- Finally, open
app/build/outputs/logs/manifest-merger-debug-report.txtin the file tree and scroll it. EveryMERGED fromline is a library adding something to your manifest.
xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag, then tools:replace="android:label" on <application>. That declares "mine wins".<intent-filter> but never said whether other apps may start it. Android used to guess; since Android 12 guessing is banned because the guess was a security hole.android:exported="true" to the launcher activity. Any activity that is only started from inside your own app should have android:exported="false".minSdk in app/build.gradle.kts to at least the number the library demands, or find an older version of that library. This course uses minSdk = 26, which most modern libraries accept.strings.xml was renamed or emptied.app/src/main/res/values/strings.xml and confirm there is a line <string name="app_name">…</string>. The name in the manifest must match it exactly, capitals included.Error: — that is the real problem. Fixing it usually clears the rest.AndroidManifest.xmlis the only part of your app Android reads before running it. It declares your name, icon, theme, screens and .@string/…and@mipmap/…point at instead of holding values, which is what makes renaming and translating possible.- An is invisible to Android unless it is declared here, and needs
android:exported="true"plus a MAIN/LAUNCHER to get an icon. minSdk,targetSdkandversionCodemoved out of this file and intoapp/build.gradle.kts.- The combines your file with every library's, and writes a full report you can read.
- Next: the
resfolder — how strings, colours and pictures are stored so Android can swap them for dark mode, for another language, or for a bigger screen.