aagya
0.1.1indexedSimplifies platform permission flows by exposing the real state machine, stateless-by-default with optional BYO storage, sealed permission model, crash-safe API, Compose-native controller and DI-agnostic integrations.
Simplifies platform permission flows by exposing the real state machine, stateless-by-default with optional BYO storage, sealed permission model, crash-safe API, Compose-native controller and DI-agnostic integrations.
आज्ञा, Sanskrit for permission, consent.
A small, opinionated Kotlin Multiplatform permission library for Android and iOS.
Built so you stop reimplementing the same shouldShowRequestPermissionRationale /
CLAuthorizationStatus dance in every app.
Permissions on Android and iOS are not the same shape:
Most libraries paper over this with the lowest common denominator (one ask, ever) and force you to pick a storage strategy. Aagya does neither.
It exposes the real state machine:
NotDetermined
becomes Granted (user allows)
becomes Denied(canAskAgain = true) (request again)
becomes Denied(canAskAgain = false) (open Settings)
…and lets you decide if you want to layer a stricter app policy on top (with your storage of choice).
// build.gradle.kts (KMP shared module)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("xyz.ksharma:aagya-data:0.3.0")
}
}
}
Upgrading from 0.2.0 or earlier? The group ID changed in 0.3.0, from
io.github.ksharma-xyztoxyz.ksharma, matching thexyz.ksharma.*package names the library has always shipped. Maven Central coordinates cannot be moved, so 0.2.0 and earlier remain under the old group. Change the group when you upgrade; artifact names and the API are unchanged.
@Composable
fun LocationButton() {
val controller = rememberPermissionController()
val scope = rememberCoroutineScope()
Button(onClick = {
scope.launch {
when (val result = controller.requestPermission(AppPermission.Location.Fine)) {
is PermissionResult.Granted -> startLocationFlow()
is PermissionResult.Denied -> if (!result.canAskAgain) controller.openAppSettings()
PermissionResult.Cancelled ->
}
}
}) {
Text()
}
}
That's it. No singletons, no Application subclass to extend, no storage to set up.
val controller = rememberPermissionController(
policy = PermissionPolicy(
maxRequestsAndroid = 1,
maxRequestsIos = 1,
store = rememberDataStorePermissionStore(),
),
)
See recipes for stricter policies, custom storage, and DI integration.
iosArm64, iosSimulatorArm64)JVM and JS targets may follow if there is real demand. Open an issue.
v0.1 shipped Location.Fine and Location.Coarse; v0.2 added Microphone.Default.
The sealed hierarchy already includes stubs for the rest so adding them is
non-breaking:
CameraNotificationsPhotos (read / read-write split for iOS 14+)Calendar, ContactsSee CONTRIBUTING.md. PRs welcome. Please open an issue before any non-trivial work so we can agree on the shape of the API.
Apache 2.0. Use it however you want.
Aagya is named for आज्ञा, the Sanskrit word for permission / command. The library gives you a clean way to ask the user for theirs.
shouldShowRequestPermissionRationale on Android and CLAuthorizationStatus on iOS as the source of truth. Zero storage required for the common case.:store-datastore (Android) and :store-userdefaults (iOS) adapters ship in the box.rememberPermissionController() for Compose users; plain interface for non-Compose KMP code.:di-koin module if you use Koin. Otherwise, build it yourself with rememberPermissionController().| Artifact | Purpose | Required? |
|---|
xyz.ksharma:aagya-state | Pure-Kotlin types: AppPermission, PermissionStatus, PermissionResult, PermissionPolicy. | yes |
xyz.ksharma:aagya-data | PermissionController interface and Android/iOS implementations. | yes |
xyz.ksharma:aagya-store-datastore | Android PermissionStore backed by Jetpack DataStore. | optional |
xyz.ksharma:aagya-store-userdefaults | iOS PermissionStore backed by NSUserDefaults. | optional |
xyz.ksharma:aagya-di-koin | Koin module factory if you use Koin. | optional |
Surfaced from shared tags and platforms — no rankings paid for.