Production-ready, type-safe permission handling for Kotlin Multiplatform — handling the complex edge cases of Android and iOS flows.
Grant is not just another permission library. It is a production-hardened engine designed to handle complex edge cases that lead to crashes and hangs in other solutions. Built for professionals who demand absolute reliability.
- 🎯 Pure Logic-First API — Works anywhere: ViewModels, Repositories, or Composables. No Activity or Fragment references required.
- 🍎 iOS Framework Isolation — Each permission type is isolated to its own handler, preventing unused Apple frameworks (Location, Bluetooth, Motion, etc.) from being linked into your binary. No more phantom
NSUsageDescriptionrequirements. - 🛡️ iOS Crash-Guard — Automatically validates
Info.plistkeys before requesting, preventing the dreadedSIGABRTproduction crashes. - 🔄 Android Process-Death Resilience — The only library that handles system-initiated process death gracefully with zero timeouts.
- ⚡ iOS Deadlock Fix — Built-in protection against the infamous Camera/Microphone first-request deadlock.
- 📦 17 Native Permissions — Deep, native integration for Camera, Gallery (Partial access!), Location, Bluetooth, Motion, Health, and more.
- 🛠️ Service Intelligence — Don't just check permissions; check if services (GPS, Bluetooth, Health) are actually enabled.
- 🧩 Custom Extensibility — Use
RawPermissionto support new OS permissions (Android 15+, iOS 18+) instantly without library updates. - 🧪 Ultra-Robust Testing — 782 automated tests (423 Android + 359 iOS Simulator) covering every platform edge case, state invariant, and UI interaction. 100% pass rate.
class CameraViewModel(private val grantManager: GrantManager) : ViewModel() {
val cameraGrant = GrantHandler(
grantManager = grantManager,
grant = AppGrant.CAMERA,
scope = viewModelScope
)
fun capturePhoto() {
cameraGrant.request {
// Only runs when permission is FULLY granted
cameraEngine.startCapture()
}
}
}@Composable
fun CameraScreen(viewModel: CameraViewModel) {
// Handles Rationale, Denied, and Settings dialogs automatically
GrantDialog(handler = viewModel.cameraGrant)
IconButton(onClick = { viewModel.capturePhoto() }) {
Icon(Icons.Default.Camera, contentDescription = "Capture")
}
}Permission is only half the battle. In production, you also need to check if the hardware service (GPS, Bluetooth) is actually enabled.
// Use GrantAndServiceChecker to combine both worlds
class LocationViewModel(
private val checker: GrantAndServiceChecker,
private val grantManager: GrantManager
) : ViewModel() {
fun startTracking() {
viewModelScope.launch {
when (val status = checker.checkLocationReady()) {
LocationReadyStatus.Ready -> sensor.start()
LocationReadyStatus.ServiceDisabled -> _uiState.showEnableGPS()
LocationReadyStatus.GrantDenied -> requestPermission()
LocationReadyStatus.BothRequired -> _uiState.showTotalFailure()
}
}
}
}Most KMP permission libraries are simple wrappers around native APIs. Grant is an Architectural Solution.
| Feature | Grant | moko-permissions | accompanist-permissions |
|---|---|---|---|
| No Lifecycle Binding | ✅ | ❌ (needs BindEffect) | ❌ (needs Activity) |
| ViewModel Support | Full | Partial | ❌ |
| iOS Crash Prevention | ✅ | ❌ | ❌ |
| iOS Framework Isolation | ✅ | ❌ | N/A |
| Android Deadlock Fix | ✅ | ❌ | ❌ |
| Process Death Recovery | Native | ❌ | Manual |
| Service Checks (GPS/BT/Health) | ✅ | ❌ | ❌ |
| Android 14 Partial Access | ✅ | Partial | ✅ |
| Custom Permissions | ✅ | Limited | Limited |
| Permission | Android | iOS | Notes |
|---|---|---|---|
| Camera | ✅ | ✅ | iOS main-thread safe + deadlock fix |
| Microphone | ✅ | ✅ | Shares AVFoundation handler with Camera |
| Gallery (full) | ✅ | ✅ | Android 14+ partial access (PARTIAL_GRANTED) |
| Gallery (images only) | ✅ | ✅ | AppGrant.GALLERY_IMAGES_ONLY |
| Gallery (video only) | ✅ | ✅ | AppGrant.GALLERY_VIDEO_ONLY |
| Storage (legacy) | ✅ | ✅ | Pre-API 33 fallback |
| Location (when in use) | ✅ | ✅ | Intelligent GPS service check included |
| Location (always) | ✅ | ✅ | Android 2-step background flow handled |
| Notifications | ✅ | ✅ | Android 13+ and legacy flows |
| Bluetooth | ✅ | ✅ | Service status check + Scan/Connect |
| Bluetooth Advertise | ✅ | ✅ | AppGrant.BLUETOOTH_ADVERTISE |
| Contacts (full) | ✅ | ✅ | Read + Write access |
| Contacts (read-only) | ✅ | ✅ | AppGrant.READ_CONTACTS |
| Calendar (full) | ✅ | ✅ | iOS 17+ FullAccess / WriteOnly mapped correctly |
| Calendar (read-only) | ✅ | ✅ | AppGrant.READ_CALENDAR |
| Motion / Activity | ✅ | ✅ | Simulator-aware (safe mock on Simulator) |
| Schedule Exact Alarm | ✅ | ✅ | Android 12+ SCHEDULE_EXACT_ALARM |
| Service | Android | iOS |
|---|---|---|
| GPS / Location | ✅ | ✅ |
| Bluetooth | ✅ | ✅ |
| Wi-Fi | ✅ | ✅ |
| NFC | ✅ | — |
| Camera hardware | ✅ | ✅ |
| Health Connect / HealthKit | ✅ | ✅ |
// shared/build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("dev.brewkits:grant-core:1.3.1")
implementation("dev.brewkits:grant-compose:1.3.1") // Optional: Compose dialogs
implementation("dev.brewkits:grant-core-koin:1.3.1") // Optional: Koin DI support
}
}
}Important
For projects targeting Web (JS) or Desktop (JVM), use an intermediate mobileMain source set to avoid linking iOS/Android dependencies on unsupported platforms. Read the Guide.
Note
Koin users: The Koin integration was moved to grant-core-koin in v1.3.1. Add the new artifact alongside grant-core and replace GrantPlatformModule imports. See the Migration Guide.
| Guide | Description |
|---|---|
| Architecture | How concurrency, state machines, and the mutex flow work |
| iOS Setup | Critical Info.plist configuration — read before shipping |
| Migration Guide | Upgrading from v1.2.x to v1.3.1 |
| Service Checking | Combining permission + hardware service checks |
| Manual Injection | Using Grant without any DI framework |
| Android Reliability | How we fix "Dead Clicks" on Android |
| Best Practices | Patterns for production apps |
We are on a mission to make permissions a "solved problem" for KMP. Join us!
- Check out CONTRIBUTING.md.
- Run
./gradlew :grant-core:allTeststo ensure stability. - Submit your PR.
Grant is licensed under the Apache License 2.0. See LICENSE for details.