Declare only the required capability
For a feature that directly uses the camera, declare android.permission.CAMERA in the manifest. A feature that delegates capture to another application may have a different access model; first choose the API that minimizes your own permission needs.
The official runtime-permission guide recommends requesting access in context rather than presenting a bundle of unrelated requests on launch.
Register the result handler before the action
This Kotlin fragment belongs in an AndroidX activity or fragment. The helper methods represent your application's UI and feature code:
private val cameraRequest = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openCameraFeature()
else showCameraUnavailableMessage()
}
private fun onScanRequested() {
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED) {
openCameraFeature()
} else {
cameraRequest.launch(Manifest.permission.CAMERA)
}
}
For a fragment, use the appropriate context and lifecycle setup. Required imports and the camera implementation are intentionally not hidden inside this small example.
Add a rationale without coercion
Use shouldShowRequestPermissionRationale where appropriate to explain why the feature needs access. Do not treat its false result as a universal “permanently denied” flag: it can also be false before the first request and in other states.
Let the user continue with unrelated features. Repeatedly reopening the dialog or blocking the entire app after a declined optional permission undermines the choice.
Handle changed access
Recheck permission when the protected operation starts. A grant can be revoked in settings or expire under platform behavior. Catch and handle the operation's failure appropriately rather than relying on a preference such as cameraPermissionWasGranted=true.
Test the full state table
Test first request, grant, denial, repeated denial, settings grant, settings revocation and app recreation. Check behavior on the oldest supported Android version and a current target/version combination.
APKLint can inspect the declaration and flag suspicious patterns. It cannot click the system dialog or prove that the feature degrades gracefully after denial; those are device or emulator tests.
Keep the request and the user's original action connected
In the scanner example above, tapping Scan creates an intention to start the camera. If the system dialog appears, the eventual result belongs to that action. Register the launcher through the supported activity or fragment lifecycle and ensure a recreated screen can interpret the result. Do not register a new launcher inside every button click or retain a destroyed view in its callback.
The runtime-permission guide documents the request and rationale flow. The fragment is deliberately incomplete application code: the scanner implementation, error UI and imports must match the real project. A granted permission enables an attempted camera operation; it does not guarantee that hardware is available or that opening it will succeed.
Exercise a request across screen changes
Start with no grant, tap Scan and deny the request. Confirm that the message explains the unavailable scanner while manual entry remains usable if the product offers it. Request again through an explicit user action and verify the rationale behavior appropriate to the current platform state. Avoid interpreting a false rationale result as a universal permanent-denial signal.
Next, grant access, leave the screen and revoke access in settings. Return without reinstalling the app and tap Scan again. This exposes implementations that cache the first grant in preferences instead of checking at the operation boundary. Also recreate the screen while a request is pending and check that one result leads to at most one scanner start.
Handle camera-open failure separately from permission refusal so the user is not asked to grant access that already exists. Close or release the camera through its supported lifecycle when scanning ends, and avoid leaving a success indicator after initialization failed. Keep the test record organized by actual state transitions and device API level. Manifest validation confirms the declaration; only the device workflow can establish that request results, recreation, denial and revocation lead to the intended behavior.
Sources and further reading
Reference review: 29 September 2026. Examples illustrate the workflow; check your installed versions, release artifact and account-specific Console requirements before applying them. This guide is not a claim that APKLint executed your project or verified your private account.


