Android Fundamentals with Java

The AndroidManifest

18 min Lesson 6 of 12

The AndroidManifest

Every Android application has exactly one file called AndroidManifest.xml, located at the root of every module. The Android build system merges the manifests of all modules into a single final manifest before packaging the APK. At runtime, the Android OS reads this manifest before launching a single line of your Java code. If a component is not declared here, the system cannot start it. If a permission is not listed here, the OS will deny it. Think of the manifest as the contract between your application and the Android platform.

The Root Element and Package Name

The root element of the file is <manifest>. Its most important attribute is package, which serves as your application's unique identifier on a device and in the Play Store. By convention it mirrors your Java package, for example com.example.myapp.

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.taskmanager"> <!-- permission declarations, application block, ... --> </manifest>
package vs applicationId: In modern Gradle builds the applicationId in build.gradle is what actually ends up in the APK and on the Play Store. If they differ, the Gradle value wins. Keep both in sync to avoid confusion.

Declaring Application Components

Every component your application exposes — Activities, Services, Broadcast Receivers, and Content Providers — must be declared inside the <application> element. The OS will silently fail to start any undeclared component.

Activities

An <activity> element registers one screen. The android:name attribute holds the fully-qualified class name; you may use a leading dot as shorthand for the package name prefix.

<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DetailActivity" android:exported="false" android:parentActivityName=".MainActivity" /> </application>

The <intent-filter> on MainActivity with MAIN action and LAUNCHER category is what places your app icon in the home screen launcher. An app must have exactly one such filter. The android:exported attribute is mandatory on API 31+ and controls whether other applications can start this activity directly.

The android:parentActivityName attribute on DetailActivity wires up the system Up button in the Action Bar automatically — no Java code required for basic navigation.

Services

A <service> element declares a background component. Mark android:exported="false" unless other apps must bind to it.

<service android:name=".SyncService" android:exported="false" />

Broadcast Receivers

Static receivers (declared in the manifest) are started even when the app is not running. Note that Android 8.0+ restricts which implicit broadcasts can be received this way; most receivers must be registered at runtime with registerReceiver() instead.

<receiver android:name=".BootReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>

Content Providers

<provider android:name=".TaskProvider" android:authorities="com.example.taskmanager.provider" android:exported="false" />

The android:authorities string must be globally unique across all apps on the device, so using your package name as a prefix is mandatory.

Declaring Permissions

Android enforces a two-step permission model. First, you declare in the manifest which permissions your app may use. Second, for dangerous permissions (those that touch sensitive user data or device hardware), you must also request them at runtime in Java code using ActivityCompat.requestPermissions().

Normal Permissions

Normal permissions are granted automatically at install time. They cover things like accessing the network or vibrating the device — low-risk actions.

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Dangerous Permissions

Dangerous permissions require a runtime prompt. However, they must still be listed in the manifest — without the manifest declaration the runtime request will always be denied, no matter what Java code you write.

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

The android:maxSdkVersion attribute on READ_EXTERNAL_STORAGE tells the system to stop enforcing it above API 32, because Android 13 introduced granular media permissions (READ_MEDIA_IMAGES, etc.) that replace it.

Declaring Custom Permissions

If your app exposes a component that only trusted partners should reach, define a custom permission and apply it to that component:

<!-- Define the custom permission --> <permission android:name="com.example.taskmanager.permission.READ_TASKS" android:protectionLevel="signature" /> <!-- Protect the provider with it --> <provider android:name=".TaskProvider" android:authorities="com.example.taskmanager.provider" android:exported="true" android:readPermission="com.example.taskmanager.permission.READ_TASKS" />

protectionLevel="signature" means only apps signed with the same developer key can be granted this permission — far stronger than normal or dangerous.

Hardware and Feature Requirements

Use <uses-feature> to declare that your app requires specific hardware. The Play Store uses this to filter out incompatible devices.

<uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

Setting android:required="false" means your app can run without the feature but will use it if available — you must then check at runtime with PackageManager.hasSystemFeature().

Permission does not imply feature requirement. Declaring CAMERA permission implicitly adds a camera feature requirement. If your app uses the camera as an optional feature, explicitly add <uses-feature android:name="android.hardware.camera" android:required="false" /> to prevent the Play Store from filtering out camera-less devices.

The Full Picture: Putting It Together

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.taskmanager"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.TaskManager" android:allowBackup="true" android:supportsRtl="true"> <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> <activity android:name=".TaskDetailActivity" android:exported="false" android:parentActivityName=".MainActivity" /> <service android:name=".SyncService" android:exported="false" /> </application> </manifest>
Keep the manifest lean. Every permission you request is visible to the user and subject to policy review by the Play Store. Only declare permissions you actually use. Unused permissions increase user distrust and can trigger Play Store rejections. Remove permissions when you refactor code that no longer needs them.

Summary

AndroidManifest.xml is the OS-level contract for your application. Declare every Activity, Service, BroadcastReceiver, and ContentProvider inside <application> — undeclared components simply do not exist to the system. List every permission your code calls on under <uses-permission>; dangerous permissions additionally need a runtime request in Java. Use <uses-feature> to control Play Store device filtering. With a well-formed manifest in place you are ready to wire up intents and start building multi-screen flows in the next lesson.