DEV Community

Cover image for Grant: The “No-Nonsense” Permission Manager for Kotlin Multiplatform
Viet, Nguyen Tuan
Viet, Nguyen Tuan

Posted on

Grant: The “No-Nonsense” Permission Manager for Kotlin Multiplatform

Stop Fighting with Android Manifests and Info.plist. Request permissions in shared code like a boss.

After solving the UI Command problem, I ran into the next biggest wall in Kotlin Multiplatform (KMP) development: Runtime Permissions.

The Current Chaos

Android: You need ActivityResultLauncher, ContextCompat.checkSelfPermission, manifest entries, and complex logic for shouldShowRequestPermissionRationale.

iOS: You need AVCaptureDevice.requestAccess, PHPhotoLibrary, delegates, and async completion blocks.

The Shared Problem: How do you unite these two chaotic worlds into a clean, linear flow in your ViewModel?

Enter Grant.


🎯 What is Grant?

Grant is a permission manager built specifically for Kotlin Multiplatform, designed with a "Headless & Coroutines-First" philosophy.

  • ❌ It is NOT a UI library (it won't force ugly popups on you)
  • ✅ It is a System Engine that abstracts the operating system, giving you full control over the UI/UX while it handles the dirty work

🏆 Why Grant is the "De-Facto Standard" for 2026

1️⃣ Unified API (One Enum to Rule Them All)

Forget about checking Android SDK versions or iOS authorization statuses manually. Grant abstracts everything into a simple, type-safe Enum.

You don't need to know the difference between Android API 33 and iOS 16 under the hood. Grant handles it.

2️⃣ Linear Logic (Suspend Functions)

Permissions are inherently transactional: Ask → Wait → Result.

Instead of callbacks (which lead to "Callback Hell") or complex Delegates, Grant uses suspend functions natively. Your logic runs top-to-bottom, making it incredibly readable and maintainable.

3️⃣ Smart Status Handling

The hardest part of permissions isn't asking; it's handling when the user says "No, and don't ask again."

  • Android: The system dialog stops appearing
  • iOS: The status becomes .denied

Grant detects this state automatically across platforms, allowing you to guide the user to System Settings instantly.


🛠️ The "Clean" Architecture Way

Let's look at the difference between the traditional way and the Grant way.

❌ The Old Way (The Pain)

You have to inject an Activity into your ViewModel (causing leaks), or create complex interfaces in commonMain and implement them separately for each platform. Your code becomes fragmented and hard to test.

✅ The Grant Way (The Solution)

You handle permissions directly in your Shared Code (ViewModel/UseCase), with zero Android Context or iOS Delegates required.

class CameraViewModel : ViewModel() {
    fun onCaptureClicked() {
        viewModelScope.launch {
            // 1. Check current status
            val status = Grant.check(Permission.CAMERA)
            when (status) {
                PermissionStatus.GRANTED -> openCamera()

                PermissionStatus.DENIED -> {
                    // 2. Request (Suspends until user decides)
                    val result = Grant.request(Permission.CAMERA)
                    if (result.isGranted) {
                        openCamera()
                    } else {
                        showErrorUI("We need camera access to take photos.")
                    }
                }

                PermissionStatus.PERMANENTLY_DENIED -> {
                    // 3. Handle "Don't ask again" scenario
                    showSettingsDialog()
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

🚀 The Killer Feature: Handling "Permanently Denied"

A major UX pain point occurs when a user accidentally clicks "Don't ask again" (Android) or denies permission (iOS). Subsequent requests fail silently, making your app look broken.

Grant solves this with a single line of code:

if (Grant.status(Permission.CAMERA) == PermissionStatus.PERMANENTLY_DENIED) {
    // Opens the specific System Settings page for your app
    Grant.openSettings()
}
Enter fullscreen mode Exit fullscreen mode

This is the polish of a library built by product veterans: It solves the UX problem, not just the technical one.


📊 Technical Face-Off: Grant vs. The World

Let's break down exactly why Grant outperforms traditional methods (like Moko-Permissions or Accompanist):

1. Configuration & Setup

Approach Experience
Traditional ❌ High friction. Often requires binding to an Activity or wrapping your Compose UI in a special Provider.
Grant Zero-Config. Just add the dependency. It automatically hooks into the lifecycle context-aware components.

2. Control Flow

Approach Experience
Traditional ❌ Relies on Callbacks or reactive Streams/Flows, which can complicate simple transactional logic.
Grant ✅ Uses Suspend Functions. This keeps your business logic linear and easy to reason about.

3. Architecture Compatibility

Approach Experience
Traditional ❌ Tightly coupled to the UI Layer. Hard to use inside a ViewModel or Domain UseCase.
Grant Headless. It works perfectly inside ViewModels, keeping your UI code dumb and your logic code smart.

4. Boilerplate

Approach Experience
Traditional ❌ Requires passing Context or Activity references manually.
Grant Context-Aware. It handles the platform context injection under the hood, keeping your shared code pure.

👨‍💻 Final Verdict

In modern software architecture, specifically KMP, we strive for "Platform Transparency." Your business logic shouldn't care if it's running on an iPhone 15 or a Pixel 9.

Grant is the perfect abstraction layer to achieve this transparency for permissions. It hides the ugly, fragmented platform APIs and gives you a clean, powerful, and safe toolset.

If you are looking for a "Complete & Elite" permission solution for your next KMP project, Grant is the way to go.


🔗 Links

👉 GitHub Repo: https://www.github.com/brewkits/Grant


Tags: #KotlinMultiplatform #KMP #AndroidDev #iOSDev #Permissions #CleanArchitecture

Top comments (0)