PlatformGrantDelegate

Platform-specific delegate for grant operations.

Permission Types:

  • AppGrant: Built-in permissions (CAMERA, LOCATION, etc.)

  • RawPermission: Custom platform-specific permissions

Implementations:

  • Android (androidMain): Uses ActivityCompat, ContextCompat, Activity Result API

  • iOS (iosMain): Uses AVFoundation, CoreLocation, CoreBluetooth, EventKit, etc.

iOS Platform Grant Delegate — Production-ready implementation.

Dispatches permission operations to dedicated PermissionHandler instances, each of which owns exactly the native framework imports it needs. This ensures that unused permission frameworks are not statically linked into the app binary, preventing Apple App Store rejections caused by undeclared usage description keys.

See docs/ios/APPLE_FRAMEWORK_LINKING_ISSUE.md for the full architectural rationale.

Supported permissions (17 total):

  • Camera / Microphone — AVFoundation

  • Gallery / Storage — Photos

  • Location (WhenInUse / Always) — CoreLocation

  • Notification — UserNotifications

  • Contacts — Contacts

  • Calendar — EventKit

  • Motion — CoreMotion

  • Bluetooth — CoreBluetooth (via BluetoothManagerDelegate)

  • Schedule Exact Alarm — GRANTED unless the app declares NSAlarmKitUsageDescription; see ExactAlarmHandler for why AlarmKit (iOS 26+) cannot be answered from here

Thread Safety:

  • mutexMap is protected by mapsMutex

  • statusCacheMap uses per-entry locking via mapsMutex

  • All synchronous iOS framework calls dispatch to the main thread via runOnMain

  • Notification status is checked via its own async path to avoid nested dispatch

JVM desktop delegate — deliberately minimal. grant-core has no macOS/Windows framework dependency and never will; every GrantPermission resolves through DesktopPermissionHandlerRegistry, and a lookup miss reports GrantStatus.DENIED_ALWAYS with a logged reason rather than a fabricated GrantStatus.GRANTED. The grant-desktop module (opt-in) is what actually populates the registry with a real macOS TCC bridge — see DesktopPermissionHandlerRegistry's KDoc and ROADMAP.md v2.6.0.

store is unused here for the same reason it's unused on iOS/web: the OS's own privacy database is the durable "have we asked before" record.

Browser Platform Grant Delegate — shared by the js and wasmJs targets via webMain.

Backed by the real browser consent APIs — getUserMedia, Notification.requestPermission, Geolocation.getCurrentPosition — never a stub. store is unused: the browser itself is the durable "have we asked before" record (a denied getUserMedia call stays denied across page loads without any help from Grant), so there is nothing for a local store to add here.

Only four AppGrant values have a real browser equivalent: AppGrant.CAMERA, AppGrant.MICROPHONE, AppGrant.LOCATION, AppGrant.NOTIFICATION. Every other value — gallery, contacts, calendar, bluetooth, motion, and the rest — has no standard Web Platform API to back it. Those resolve to GrantStatus.DENIED_ALWAYS with a logged reason, matching the existing convention (hasInfoPlistKey on iOS) of failing safe and loud rather than fabricating a status the platform cannot actually provide. RawPermission follows the same rule: there is no generic "request an arbitrary permission" primitive in a browser.

Constructors

Link copied to clipboard
constructor(context: Context, store: GrantStore)
constructor(store: <Error class: unknown class>)
constructor(store: GrantStore)
constructor(store: GrantStore)

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
actual suspend fun checkStatus(grant: GrantPermission): GrantStatus
expect suspend fun checkStatus(grant: GrantPermission): GrantStatus
actual suspend fun checkStatus(grant: <Error class: unknown class>): <Error class: unknown class>
actual suspend fun checkStatus(grant: GrantPermission): GrantStatus
actual suspend fun checkStatus(grant: GrantPermission): GrantStatus
Link copied to clipboard
actual fun openSettings()
expect fun openSettings()
actual fun openSettings()

Opens the app's settings page in iOS Settings. Logs a warning if the Settings URL cannot be resolved (e.g., App Extensions, App Clips).

actual fun openSettings()

Opens System Settings' Privacy & Security pane. Unlike the browser target, macOS does have a real, documented URL scheme for this (x-apple.systempreferences:com.apple.preference.security) — but only grant-desktop can invoke it (it needs NSWorkspace, an AppKit/macOS-only API grant-core's jvmMain does not and should not depend on, since this module also has to compile on any JVM, not just macOS). Delegates to DesktopPermissionHandlerRegistry.settingsOpener when one is registered; logs instead of silently doing nothing when none is.

actual fun openSettings()

No standard way for a web page to open the browser's own site-permission settings — unlike a native OS Settings app, there is no cross-browser URL or API for this. Logs instead of silently doing nothing, so an integrator sees why nothing happened rather than filing a "openSettings() is broken on web" bug.

Link copied to clipboard
actual suspend fun request(grant: GrantPermission): GrantStatus
actual suspend fun request(grants: List<GrantPermission>): Map<GrantPermission, GrantStatus>
expect suspend fun request(grant: GrantPermission): GrantStatus
expect suspend fun request(grants: List<GrantPermission>): Map<GrantPermission, GrantStatus>
actual suspend fun request(grant: <Error class: unknown class>): <Error class: unknown class>
actual suspend fun request(grants: List<<Error class: unknown class>>): Map<<Error class: unknown class>, <Error class: unknown class>>
actual suspend fun request(grant: GrantPermission): GrantStatus
actual suspend fun request(grants: List<GrantPermission>): Map<GrantPermission, GrantStatus>
actual suspend fun request(grant: GrantPermission): GrantStatus
actual suspend fun request(grants: List<GrantPermission>): Map<GrantPermission, GrantStatus>
Link copied to clipboard
actual fun setLauncher(launcher: GrantLauncher)
expect fun setLauncher(launcher: GrantLauncher)
actual fun setLauncher(launcher: <Error class: unknown class>)
actual fun setLauncher(launcher: GrantLauncher)
actual fun setLauncher(launcher: GrantLauncher)