# flutter-permission-handler: a federated plugin caught mid-migration

> Flutter's permission_handler is the plugin most Flutter projects meet early, and its repository sits in an interesting transitional state: the README describes Android and iOS as still living inside the app-facing package, while the tree already carries separate platform packages for Apple, Windows and the web.

**Baseflow/flutter-permission-handler** — Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.

- Repository: https://github.com/Baseflow/flutter-permission-handler
- Website: https://baseflow.com
- Stars: 2,175 · Forks: 977
- Language: Dart
- License: MIT
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/baseflow-flutter-permission-handler

## Two packages, and the one you actually depend on

The structure is the first thing to understand, because it determines which package appears in your pubspec and which one you read if you are extending it.

There are two, and they have different jobs. `permission_handler` is the app-facing package, the one an application depends on to use the plugin. `permission_handler_platform_interface` declares the interface that every platform package must implement in order to support the app-facing one.

That split is what the federated plugin architecture means in practice, and the README is explicit that it follows that architecture and defers the explanation to the Flutter documentation rather than restating it. For a consumer the consequence is simple: one dependency, one import, and the platform packages are pulled in because your target platforms need them. For someone implementing a new platform the consequence is a contract to satisfy, and the README sends you to that interface package's own README for the instructions rather than describing the interface here.

Both packages are published to pub.dev, which is where the documentation for each one lives and where the README's per-package links point. So the repository root is not the place to look up how to request a permission; it is a map of where to look.

One statement in the README is worth flagging as a statement about the future rather than the present. Additional platform support will be added in their own individual platform packages, the README says, and at the moment the Android and iOS platform implementations are also part of the app-facing package. That sentence is the specification for the layout the tree is heading towards, not a description of the current one.

## The tree has already moved past what the README describes

Compare the README's sentence above with the top-level directory list, because the difference is the most informative thing in this repository.

The tree contains `permission_handler/`, the app-facing package. It contains `permission_handler_platform_interface/`, the contract. And it contains four more directories: `permission_handler_android/`, `permission_handler_apple/`, `permission_handler_html/` and `permission_handler_windows/`.

So the migration the README describes as upcoming is at least partly done. Separate platform packages exist for three platforms plus Windows, and Android has a directory of its own in the tree while the README still lists Android as part of the app-facing package. Either the split for Android has landed in the tree and the README sentence has not caught up, or the directory holds something other than the full implementation. The tree does not say which, and that gap is the first thing to check before you reason about the package structure.

The naming is the other clue. The Apple package is called `permission_handler_apple` rather than `permission_handler_ios`, which is the shape the README's plan predicts: additional platforms grouped by vendor rather than by operating system, so that one package can serve the whole family rather than forcing a choice. Whether it currently serves macOS as well as iOS is not documented here, and given how the Android sentence reads, treat the naming as intent rather than as a fact about the shipped API.

There is also a package here the short project description does not mention. The description says cross-platform for iOS and Android, and the tree contains HTML and Windows packages, so the repository covers more than the description advertises.

## A whole document named after one Android failure state

There is a file at the repository root called `ANDROID_PERMANENTLY_DENIED_FIX_GUIDE.md`, and its presence is more informative than its contents would be.

Android's permission model has a third state beyond granted and denied, and it is the one that breaks onboarding flows. A user can deny a permission and be asked again, but a user can also deny it in a way that stops the app from asking again, and after that the only route to the permission is the system settings page. There is no API call that reverses it. So the problem is not technical, it is that the fix requires sending the user out of your app to a settings screen and asking them to come back, and the details of that journey differ by OS version and by how the permission was denied.

That is why this needs a document rather than a line in the API reference. If your app requests a permission on first launch, the user declines, and your flow has no branch for the permanently denied state, the permission is unobtainable for that user for ever unless you send them to settings. Designing for it from the start is cheap; discovering it from a support ticket is not.

What the guide actually recommends is not described here, and there is no reason to guess at it. What the filename establishes is that this is a known, documented, first-class problem for this plugin rather than something users work around.

The generalisation is worth carrying to every platform you support. A permission API that unifies request and check across platforms will unify the states too, and the states are where the platforms disagree. The existence of a guide for this one state suggests the others are handled somewhere in the package documentation.

## The web and the phone do not have the same permission model

The tree contains a package for HTML, and that is worth pausing on, because a browser permission model is not a translation of a mobile one.

On a phone, the app asks, the system decides, and the decision is durable: it persists, it can be changed in settings, and in Android's case it can be made permanent. On the web, permissions are granted per origin and per feature, are revocable from the browser's own settings interface, and are scoped to a browsing context rather than to an installed application. There is no notion of a permanently denied permission that the page can detect and act on, because the browser owns that decision entirely and the page never sees the settings screen.

Windows has a third model again, a capability system rather than a runtime prompt, which is why it earns its own package instead of being folded into the mobile implementation.

The point for a user of this plugin is that the cross-platform surface is where these models have been reconciled, and the README at the root does not describe how. It points at the per-package READMEs, which is where the answer is. If your product depends on a permission being in one specific state on every platform, for example because your analytics assume a camera prompt will be shown once, that assumption needs checking against each platform's documentation rather than against the unified API.

The unified surface is still the right shape. A permission that has to be spelled four different ways in Dart is a permission most projects will get wrong on at least one platform.

## An index README, and pub.dev as the release channel

This README is nine lines of substance and it is not trying to be more.

It states what the plugin is for, names the federated architecture, links the Flutter documentation for that concept, and then does the useful thing: it links two package READMEs, one for usage and one for implementing a platform package. There is no installation snippet, no API listing, no version matrix and no changelog pointer in the root document, because all of that belongs with the packages rather than with the repository.

That is a defensible editorial choice and it is also what a repository looks like mid-migration. A monorepo whose packages are published separately has to keep several READMEs consistent, and the root one ends up as a table of contents while each package carries its own detail. The cost is that a reader arriving from a search result finds less than they expected.

The distribution detail follows from the same arrangement. There are no GitHub releases in this repository, which is unremarkable for a Dart project: packages are versioned and published through pub.dev, and the two pub.dev links in the README are the canonical locations for both the app-facing package and the platform interface. The root `pubspec.yaml` and the `.metadata` file are the Flutter plugin markers, and `analysis_options.yaml` is the Dart analyzer configuration for the workspace.

The rest of the top-level files are ordinary and worth noting only as evidence of the scale: an editor configuration, a code of conduct, a contribution guide, the licence, and a directory of GitHub metadata for the release and CI configuration.

## Recent activity, a company behind it, and what to check first

Maintenance looks active. The last push was on 2026-09-26 and the repository is not archived, and the licence is MIT. The homepage is a company domain rather than a project page, so this is maintained by a company that sells Flutter development time rather than by an individual, which is a reasonable thing to know about the sustainability of a dependency.

Given the transitional state described above, here is what to verify before you depend on it.

First, find out which platforms have their own package and which are still bundled, by reading the package READMEs on pub.dev rather than the repository root. The tree and the root README disagree, and that disagreement is the kind of thing that becomes your problem the day you add a Windows or web build.

Second, read the permanently denied guide before you write the flow that asks for a permission. If your onboarding has no branch for the state where the user will never be asked again, that is a defect in your app that this plugin documents and does not fix.

Third, if you intend to add a platform the plugin does not cover, start with the platform interface package rather than with the app-facing one, because the interface is the contract and the app-facing package is one implementation of it.

None of that is a warning about the plugin. It is a warning about the fact that a federated plugin is several packages moving at once, and the root README is the least current document in the repository.

## Conclusion

Adopt permission_handler if you need one permissions API across Android, iOS and the web, and read permission_handler/README.md on pub.dev rather than this repository's README, because the root README is an index that points at the package documentation. Read ANDROID_PERMANENTLY_DENIED_FIX_GUIDE.md before you design an onboarding flow that asks twice for the same permission, because a permanently denied permission cannot be requested again from inside the app. If you need a platform this plugin does not implement, read permission_handler_platform_interface/README.md first, since that package declares the interface every platform package must satisfy.

## FAQ

### What is the Flutter permission_handler plugin for?

It provides a cross-platform API in Dart for requesting and checking permissions, so an application asks for camera, microphone or location the same way regardless of the operating system underneath. The plugin is built following the federated plugin architecture rather than as a single package with platform code inside it.

### What is the difference between permission_handler and permission_handler_platform_interface?

permission_handler is the app-facing package that your project depends on. permission_handler_platform_interface declares the interface that every platform package must implement in order to support the app-facing package, and its own README carries the instructions for implementing one.

### Which platforms does the Flutter permission_handler plugin support?

The project description names iOS and Android, but the repository also contains permission_handler_android, permission_handler_apple, permission_handler_html and permission_handler_windows directories, so the tree covers more than the description advertises. The root README notes that additional platform support will be added in its own packages and that Android and iOS implementations are still part of the app-facing package.

### What is the permanently denied problem in the Flutter permission_handler plugin?

On Android a user can deny a permission in a way that stops the app asking again, and the only route to it afterwards is the system settings screen, so the fix is a user journey rather than an API call. The repository ships a document at its root called ANDROID_PERMANENTLY_DENIED_FIX_GUIDE.md for this case.

### Where should I find the usage documentation for the Flutter permission_handler plugin?

In the permission_handler package's own README, which is linked from the repository root and published on pub.dev. The root README is an index: it explains the federated structure, links the Flutter documentation for that concept, and points at the per-package READMEs rather than documenting the API itself.

## Sources

- [Baseflow/flutter-permission-handler on GitHub](https://github.com/Baseflow/flutter-permission-handler)
- [Issues](https://github.com/Baseflow/flutter-permission-handler/issues)
- [License: MIT](https://github.com/Baseflow/flutter-permission-handler/blob/main/LICENSE)
- [Project website](https://baseflow.com)
- [README](https://github.com/Baseflow/flutter-permission-handler/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/baseflow-flutter-permission-handler
