The AndroidManifest.xml is the passport of your Android app. It tells the system what your app is, what components it has, and most importantly, what it is allowed to do.
Declaring Permissions
Every permission your app needs must be declared in the manifest.
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application ... >
...
</application>
</manifest>Install-Time vs. Runtime Permissions
Normal Permissions (Install-Time)
These are granted automatically when the user installs the app because they are considered low-risk.
Examples:
- INTERNET
- ACCESS_NETWORK_STATE
- VIBRATE
Dangerous Permissions (Runtime)
Since Android 6.0 (Marshmallow), critical permissions must be requested while the app is running. Even if you declare them in the manifest, you cannot use them until the user taps "Allow" on the system dialog.
Examples:
- CAMERA
- READ_CONTACTS
- ACCESS_FINE_LOCATION
Requesting a Runtime Permission
The manifest entry only makes a dangerous permission requestable. To actually use it, check whether it is already granted, and if not, launch the system dialog. The modern approach uses the Activity Result API:
// Register the launcher (Activity or Fragment)
val requestCamera = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openCamera() else showRationaleAndFallback()
}
// Trigger it when the user taps the camera button
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
openCamera()
} else {
requestCamera.launch(Manifest.permission.CAMERA)
}If the permission is missing from the manifest, launch() returns an immediate denial and the dialog never appears — a common reason a request seems to be "ignored." Use shouldShowRequestPermissionRationale() to detect when the user has denied once but not permanently, and show an explanation before asking again.
The Permission Model Changes by Android Version
Behavior that is correct on one API level can silently break on another. The edge cases that trip up beta builds:
- Android 10 (API 29): Background location split out into
ACCESS_BACKGROUND_LOCATION. Foreground-only grants no longer cover background access. - Android 11 (API 30): Added one-time ("Only this time") grants and auto-reset of permissions for apps the user hasn't opened in a while. Do not assume a granted permission stays granted between sessions.
- Android 13 (API 33):
POST_NOTIFICATIONSbecame a runtime permission — apps that used to notify freely now need an explicit grant. Broad storage access was replaced by granularREAD_MEDIA_IMAGES,READ_MEDIA_VIDEO, andREAD_MEDIA_AUDIO. - Android 14 (API 34): Added the "Selected photos" partial media grant via
READ_MEDIA_VISUAL_USER_SELECTED, so a media permission may be granted only for specific files.
Always test the runtime flow on the actual API level your testers run, not just your emulator's default image. For getting fresh builds onto real devices quickly, see how to share Android APK files for testing.
Permissions Your Dependencies Add
The manifest you write is not the manifest that ships. During the build, Gradle's manifest merger pulls in <uses-permission> entries from every library and SDK you depend on. An analytics, ads, or crash-reporting SDK can quietly add ACCESS_COARSE_LOCATION, READ_PHONE_STATE, or AD_ID — permissions that surprise reviewers and users.
To strip an inherited permission you do not want, declare it with a removal marker:
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />Then verify the result against the compiled APK. The merged manifest is what Play Store reviewers, and privacy-conscious testers, actually see.
Best Practices
- Request Later: Don't ask for everything on startup. Wait until the user taps the camera button to ask for Camera permission.
- Explain Why: If a user denies a permission, show a UI explaining why the feature won't work without it.
- Handle Denial: Your app shouldn't crash if the user says "No". It should gracefully disable that specific feature.
- Declare the minimum: Every dangerous permission is a Play Console data-safety question you have to justify. Remove ones you no longer use.
- Audit the merged manifest: Check the permissions in the final build, not just your source, so an SDK-injected permission never ships by surprise.
Verify Permissions Before You Ship the Build
The fastest way to confirm what an APK really asks for is to read its compiled manifest directly. BetaDrop's free APK inspector extracts the package name, version, minimum SDK, and the full list of declared permissions from any .apk — no install required — so you catch an unexpected permission before your testers do. Once the build is clean, upload the APK to BetaDrop to get an instant over-the-air install link and QR code; testers install straight from their phone browser, with no Play Store review wait and no tester accounts to manage.
Frequently Asked Questions
What are dangerous permissions in Android?
Dangerous permissions cover data or actions that affect the user's privacy — contacts, camera, microphone, location, SMS, and body sensors. You declare them in the manifest with a uses-permission tag, but you must also request them at runtime, and the user can deny them or later revoke them in Settings.
What happens if I forget to declare a permission in the manifest?
The action fails at runtime. For most permissions the app throws a SecurityException and crashes; for a few the call silently returns empty or null data instead. Declaring the permission in AndroidManifest.xml is mandatory even for permissions you also request at runtime — without the manifest entry the runtime dialog never appears.
How do I request a runtime permission on Android?
Call ContextCompat.checkSelfPermission() to see if the permission is already granted. If it is not, launch the system dialog using the ActivityResultContracts.RequestPermission() contract (or requestPermissions() on older APIs) and handle the user's choice in the result callback. The permission must still be listed in the manifest or the dialog will not show.
What is the difference between normal and dangerous permissions?
Normal (install-time) permissions such as INTERNET or VIBRATE are granted automatically at install because they carry little privacy risk. Dangerous (runtime) permissions such as CAMERA or ACCESS_FINE_LOCATION are granted only when the user approves the runtime dialog, and they can be revoked at any time from system Settings.
Why is my location permission ignored even though I declared it?
Two common causes. On Android 6.0 and above you must request ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION at runtime, not just declare it in the manifest. And background access needs a separate ACCESS_BACKGROUND_LOCATION permission on Android 10 and above, which the user grants through a separate "Allow all the time" choice.
How can I check which permissions an APK actually requests?
Inspect the compiled build rather than trusting the source. BetaDrop's free APK inspector reads the manifest inside an .apk and lists every declared permission, so you can catch entries injected by an SDK or left over from testing before you ship.

