baaba_permission_handler 1.1.0 copy "baaba_permission_handler: ^1.1.0" to clipboard
baaba_permission_handler: ^1.1.0 copied to clipboard

Complete permission flow for Android and iOS: request, rationale, denied and permanently denied handling, Settings guidance dialogs. Fully customizable.

1.1.0 #

Fixed #

  • A prompt always finishes.
    • If the app tears down its navigator while a prompt is open (a logout that rebuilds MaterialApp, say), the prompt now counts as dismissed. Before, the request never completed, and every later request queued behind it hung too.
    • A snack-bar prompt no longer waits behind the app's own snack bar, which can stay up indefinitely. It becomes a dialog instead, and also while a screen reader is on.
    • The snack bar has a safety timeout as well.
  • A request started from an observer callback now queues. It used to slip past the queue as if the running flow had made it, so two Android requests could run at once.
  • iOS: refusing while-in-use location no longer blocks the "Always" upgrade for good. Once while-in-use is turned on in Settings, the upgrade prompt is shown.
  • iOS: switching Location Services back on from the service dialog now leads to the location prompt, when the permission had never been asked for.
  • A permanent denial counts for every capability that shares the native permission. After photos is refused on Android 12, a check(videos) (also storage there) reports permanentlyDenied, instead of a rationale followed by an instant refusal.
  • requestMany sends the user to Settings once. With retries used up, the denied dialog now covers the permanently denied permissions too, instead of a second Settings dialog and a second trip.
  • One misconfigured permission no longer fails its whole batch. iOS fails a request when one permission in it lacks its usage description. The other permissions are now asked on their own.
  • Per-call options.texts wins over textsBuilder, as documented, and merges into the app's texts field by field instead of replacing them.
  • Button labels have their placeholders filled, in the dialogs and in PermissionGate.
  • PermissionGate runs one flow for a double tap, not two back to back.
  • Theme values that were ignored now apply. The Cupertino dialog takes theme.barrierColor and start-aligns its steps. The snack bar takes backgroundColor, padding and accentColor, and its button now follows textDirection like its text.
  • clearHistory waits for history writes still in flight, so a write can no longer land after the clear.
  • iOS: locationAlways after location now shows the "Allow Always" prompt. Once while-in-use is granted, iOS reports background location as permanently denied even though it was never asked for. The flow took that at face value and sent the user to Settings without ever showing the upgrade prompt. It now asks once, and treats it as permanently denied only after a refusal.
  • iOS: Location Services switched off is reported as serviceDisabled. iOS reports location as denied while Location Services are off globally. The flow showed "permanently denied" and pointed the user at the app's permission instead of the service.
  • A snack bar no longer holds up the flow. In current Flutter, a snack bar with an action stays on screen until the user acts on it, so PermissionDialogTheme.snackBarDuration was ignored and every later request queued behind it. It now times out and counts as dismissed. A snack bar is also no longer shown when there is no Scaffold to show it in, since in release builds it would never appear and the request would never finish; a dialog is used instead.
  • A context with no Navigator above it no longer blocks the request. Passing, for example, the context of the widget that builds MaterialApp used to fail silently: the rationale counted as "Not now", and the permission was never requested. The flow now falls back to the app's root navigator.
  • A dialog that throws is no longer counted as "Not now". If the presentation throws (a broken presenter or dialogBuilder, say), the error goes to PermissionObserver.onError and the flow carries on as if no UI was available. A rationale proceeds to the system prompt, and a follow-up dialog is skipped without setting declinedByUser.
  • Notifications below Android 13. There is no runtime permission there, and the status only mirrors the app's notification switch. When notifications are off, notification is now reported as permanentlyDenied and goes straight to the Settings dialog. Previously the flow offered an "Allow" retry that could never show a prompt, and debug builds blamed a missing manifest entry.
  • Background permissions are requested on their own on Android. Android 11+ ignores a background-location request bundled with other permissions. requestMany([AppPermission.locationAlways, AppPermission.sensorsAlways]) now makes a separate call for each background permission.
  • recheckAfterSettings: false now also applies to the service-disabled dialog. That step used to re-check straight away, before the user could change anything.
  • openSettingsAndRecheck results are published. They now reach the results stream and PermissionObserver.onResult, so PermissionGate and watch() update too.
  • openSettingsAndRecheck always waits for the return from Settings. With recheckAfterSettings: false it used to re-check at once and report the state from before. Its results now carry initialState, so changed tells whether the user changed anything.
  • PermissionGate with a mix of restricted and denied permissions now requests the denied ones. It used to offer only "Open Settings".
  • BaabaPermissions.init called a second time now closes the replaced instance's results stream. A PermissionGate without its own handler moves over to the new instance, instead of listening to the old one.
  • PermissionGate keeps its own request's details. Its request was followed by a redundant re-check, so onChanged fired twice and the final results lost requested, declinedByUser and openedSettings. A result from a request made elsewhere is now applied directly too, without a re-check.
  • PermissionGate ignores app resumes during its own request or Settings trip. The system prompt pauses and resumes the app, and the re-check that triggered could briefly replace the request's result.
  • PermissionGate re-checks when its handler changes.
  • watch() no longer emits a stale state when a check is overtaken by a newer result while it runs.
  • Bottom sheets open on the root navigator, like the dialogs, even when the context passed is inside a nested navigator.
  • History writes are serialized. A flow now settles several permissions in parallel, and a PermissionStore that rewrites one shared record could have lost updates.
  • PermissionGate's fallback uses the gate's options. Per-call texts, theme and textDirection now apply to the built-in PermissionRequiredView, not only to the dialogs.
  • Closing a prompt never closes another route. If the app pushed a route on top of an open dialog or sheet, answering the prompt now removes the prompt's own route instead of popping the route on top.

Changed #

  • The snack bar's button is now part of its content, not a SnackBarAction, so it can follow textDirection. It looks much the same.

  • Internal restructuring, with no API change: the flow's per-call state, dialog plumbing, dialog data, wording resolution and diagnostics moved out of baaba_permissions.dart into their own files. The dialogs and PermissionRequiredView now resolve wording through the same code. Independent platform calls within a flow (rationale checks, re-checks after Settings, service checks) now run in parallel.

  • Example app: the branded dialogBuilder now works in every presentation, and an on-device integration test (example/integration_test/, driven over adb by example/tool/device_driver.py) runs the flow against a real Android phone.

Added #

  • PermissionDialogData.presentation: the presentation a prompt actually gets, so a dialogBuilder can return a whole Dialog for dialogs and just the content for sheets and snack bars.
  • PermissionHistory.permanentlyDeniedPermissions: the native permissions a request reported permanently denied. Histories stored by 1.0.0 still load.
  • FakePermissionPlatform.requestErrors: make only the requests that include a given permission throw.
  • FakePermissionPlatform models two more iOS behaviors: location reports permanentlyDenied while Location Services are off, and locationAlways reports permanentlyDenied once while-in-use is granted, though a request still shows the upgrade prompt. Tests that script iOS location may see different results.
  • PermissionPlan.settingsOnly, for a permission that only Settings can grant. A custom resolver can set it too.

1.0.0 #

First release.

  • Zero setup: dialogs find the app's root navigator automatically, so init(), navigatorKey and context are all optional.

  • Short syntax: AppPermission.camera.request(), .check(), .isAllowed, and for several at once [AppPermission.camera, AppPermission.microphone].request() / .areAllowed.

  • BaabaPermissions: check, checkMany, request, requestMany, isAllowed, openAppSettings, openSettingsAndRecheck, watch, results, planFor, clearHistory.

  • One request covers the whole flow: rationale → system prompt (stage by stage) → denied dialog with retry → permanently-denied dialog with numbered Settings steps → wait for the return from Settings and re-check → service-disabled dialog for location services and Bluetooth. Restricted permissions get an explanation.

  • AppPermission: 35 capabilities, each resolved to the right native permission for the OS and Android SDK level. For example, photos maps to READ_MEDIA_IMAGES on 13+ and to storage below, Bluetooth maps to scan + connect on 12+, and locationAlways requests while-in-use first. A capability that doesn't exist on the platform is notApplicable and counts as allowed.

  • PermissionState extends permission_handler's status with serviceDisabled, notApplicable and error. isAllowed is the one getter that is correct for every state.

  • Remembers Android's permanent denial, which the OS never reports to a status check, in a pluggable PermissionStore.

  • Customization: RationaleMode, DialogPolicy, maxRetries, PermissionStrings (with {app}/{permission}/{service}/{settings} placeholders, plus stringsBuilder for i18n), per-permission PermissionTexts, PermissionDialogTheme, dialog / bottom sheet / snack bar presentation per dialog kind, dialogBuilder, presenter, a resolver override, and per-call PermissionRequestOptions.

  • Text direction: PermissionConfig.textDirection and per-call PermissionRequestOptions.textDirection set RTL/LTR for every dialog, sheet, snack bar and gate, custom dialogBuilder widgets included. It defaults to the app's direction. Also PermissionDialogTheme.textAlign, and PermissionDialogData.textDirection/isRtl for custom layouts.

  • PermissionGate / PermissionGate.many widget with a built-in PermissionRequiredView fallback.

  • PermissionObserver for analytics and error reporting.

  • No exceptions cross the API. Requests are serialized, since Android rejects overlapping ones. Dialogs fall back safely when ScaffoldMessenger or Material localizations are missing.

  • package:baaba_permission_handler/testing.dart: FakePermissionPlatform.

0
likes
160
points
422
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Complete permission flow for Android and iOS: request, rationale, denied and permanently denied handling, Settings guidance dialogs. Fully customizable.

Repository (GitHub)
View/report issues

Topics

#permissions #permission-handler #android #ios #dialog

License

MIT (license)

Dependencies

app_settings, device_info_plus, flutter, permission_handler

More

Packages that depend on baaba_permission_handler