### Handling Permission Exceptions Source: https://context7.com/icerockdev/moko-permissions/llms.txt Implement try-catch blocks to handle `DeniedException`, `DeniedAlwaysException`, and `RequestCanceledException` when requesting permissions with `controller.providePermission()`. `DeniedAlwaysException` requires guiding the user to settings. ```kotlin import dev.icerock.moko.permissions.DeniedAlwaysException import dev.icerock.moko.permissions.DeniedException import dev.icerock.moko.permissions.RequestCanceledException suspend fun requestWithFullHandling( controller: PermissionsController, permission: Permission, showRationale: () -> Unit, showSettingsPrompt: (Permission) -> Unit ) { try { controller.providePermission(permission) println("Success: ${permission::class.simpleName} granted") } catch (e: DeniedAlwaysException) { // e.permission holds the denied Permission instance showSettingsPrompt(e.permission) // Guide user to Settings } catch (e: DeniedException) { // e is also the base type — DeniedAlwaysException is a subtype showRationale() // Explain why the permission is needed, allow retry } catch (e: RequestCanceledException) { // Android only: the system dialog was dismissed (e.g., back button) println("Request cancelled for ${e.permission}") } } ``` -------------------------------- ### iOS PermissionsController Setup Source: https://context7.com/icerockdev/moko-permissions/llms.txt On iOS, no binding is required. Instantiate `PermissionsController` directly and pass it to your shared code. Ensure all required permission keys are added to your Info.plist. ```swift // Swift (iOS AppDelegate or SwiftUI View) import MultiPlatformLibrary // your shared KMP module let permissionsController = PermissionsController() let viewModel = MediaViewModel(permissionsController: permissionsController) ``` ```xml NSCameraUsageDescription We need camera access to take photos. NSLocationWhenInUseUsageDescription We need location to show nearby items. NSMicrophoneUsageDescription We need microphone access for audio recording. NSPhotoLibraryUsageDescription We need gallery access to pick photos. NSBluetoothAlwaysUsageDescription We need Bluetooth to connect to devices. NSContactsUsageDescription We need contacts access to find your friends. NSMotionUsageDescription We need motion data for fitness tracking. ``` -------------------------------- ### Compose Multiplatform Permission Request Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md Example of requesting a permission (REMOTE_NOTIFICATION) in a Compose Multiplatform UI using `rememberPermissionsControllerFactory`. ```kotlin @Composable fun Sample() { val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory() val controller: PermissionsController = remember(factory) { factory.createPermissionsController() } val coroutineScope: CoroutineScope = rememberCoroutineScope() Button( onClick = { coroutineScope.launch { controller.providePermission(Permission.REMOTE_NOTIFICATION) } } ) { Text(text = "give permissions") } } ``` -------------------------------- ### Inspect Detailed Permission State Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use `getPermissionState` to get a detailed enum of the permission status. This is helpful for rendering UI elements conditionally without triggering a permission request. ```kotlin import dev.icerock.moko.permissions.PermissionState import dev.icerock.moko.permissions.location.BACKGROUND_LOCATION import dev.icerock.moko.permissions.location.LOCATION // Common code suspend fun describeLocationState(controller: PermissionsController) { when (controller.getPermissionState(Permission.LOCATION)) { PermissionState.NotDetermined -> println("Never asked — safe to request") PermissionState.NotGranted -> println("Not granted (Android: could be denied or not asked)") PermissionState.Granted -> println("Granted — feature available") PermissionState.Denied -> println("Denied (Android) — show rationale before retry") PermissionState.DeniedAlways -> println("Permanently denied — direct to Settings") } // Background location needs foreground first val bgState = controller.getPermissionState(Permission.BACKGROUND_LOCATION) if (bgState != PermissionState.Granted) { println("Background location not available: $bgState") } } ``` -------------------------------- ### openAppSettings() Source: https://context7.com/icerockdev/moko-permissions/llms.txt Opens the application's system settings page, allowing the user to manually change permissions, especially useful after a permission has been permanently denied. ```APIDOC ## `openAppSettings()` — Navigate to System Settings ### Description Opens the app's system settings page so the user can manually change a permanently denied permission. Call this after catching `DeniedAlwaysException`. ### Method `openAppSettings` ### Endpoint N/A (This is a function call, not an HTTP endpoint) ### Usage Call this function when a user has permanently denied a permission and needs to be directed to the system settings to enable it. ``` -------------------------------- ### Open App Settings for Denied Permissions Source: https://context7.com/icerockdev/moko-permissions/llms.txt Call `openAppSettings()` to direct the user to the system settings for your app. This is typically used after catching a `DeniedAlwaysException` to allow manual permission changes. ```kotlin // Common code suspend fun handleDeniedAlways(controller: PermissionsController, permission: Permission) { try { controller.providePermission(permission) } catch (e: DeniedAlwaysException) { // Show a dialog to the user explaining why, then: controller.openAppSettings() // On Android: opens Settings > Apps > YourApp > Permissions // On iOS: opens Settings > YourApp } } ``` -------------------------------- ### Initializing ViewModel with Permissions Controller (iOS) Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md On iOS, initialize your ViewModel by passing the platform-specific permissions controller directly. ```swift // Just pass the platform implementation of the permission controller to a common code. let viewModel = ViewModel(permissionsController: PermissionsController()) ``` -------------------------------- ### Listing All Available Permissions Source: https://context7.com/icerockdev/moko-permissions/llms.txt Access all available permissions via `Permission.Companion` extension properties. Each permission requires its specific module to be included in Gradle dependencies. ```kotlin // Bluetooth (permissions-bluetooth) Permission.BLUETOOTH_LE // Bluetooth Low Energy Permission.BLUETOOTH_SCAN // Scan for BLE devices (Android 12+) Permission.BLUETOOTH_CONNECT // Connect to BLE devices (Android 12+) Permission.BLUETOOTH_ADVERTISE // Advertise via BLE (Android 12+) // Camera (permissions-camera) Permission.CAMERA // Contacts (permissions-contacts) Permission.CONTACTS // Read + write contacts Permission.READ_CONTACTS // Read-only contacts // Gallery (permissions-gallery) Permission.GALLERY // Location (permissions-location) Permission.LOCATION // Fine (GPS) location Permission.COARSE_LOCATION // Network-based location Permission.BACKGROUND_LOCATION // Background location (Android 10+) // Microphone (permissions-microphone) Permission.RECORD_AUDIO // Motion (permissions-motion) Permission.MOTION // Activity recognition / CoreMotion // Notifications (permissions-notifications) Permission.REMOTE_NOTIFICATION // Push notifications // Storage (permissions-storage) Permission.STORAGE // Read external storage Permission.WRITE_STORAGE // Write external storage ``` -------------------------------- ### Create Permission Controller Mock Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use `createPermissionControllerMock` from the `permissions-test` module to mock permission behavior for unit tests. Configure pre-granted and allowed permissions to simulate different scenarios without needing a device or emulator. ```kotlin import dev.icerock.moko.permissions.DeniedException import dev.icerock.moko.permissions.PermissionState import dev.icerock.moko.permissions.camera.CAMERA import dev.icerock.moko.permissions.gallery.GALLERY import dev.icerock.moko.permissions.test.createPermissionControllerMock import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertFailsWith import kotlin.test.assertTrue class MediaViewModelTest { @Test fun `camera request succeeds when allowed`() = runTest { val mock = createPermissionControllerMock( allow = setOf(Permission.CAMERA), // these will be granted when requested granted = setOf(Permission.GALLERY) // pre-granted without asking ) // Already granted — no dialog shown assertTrue(mock.isPermissionGranted(Permission.GALLERY)) // Requesting allowed permission succeeds silently mock.providePermission(Permission.CAMERA) assertTrue(mock.isPermissionGranted(Permission.CAMERA)) // State reflects the grant val state = mock.getPermissionState(Permission.CAMERA) assertTrue(state == PermissionState.Granted) } @Test fun `camera request throws DeniedException when not in allow set`() = runTest { val mock = createPermissionControllerMock( allow = emptySet() // nothing allowed ) assertFailsWith { mock.providePermission(Permission.CAMERA) } } } ``` -------------------------------- ### Request Camera Permission with Error Handling Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use PermissionsController to request camera permission. Handle exceptions for permanent denial (open settings), temporary denial (show rationale), and request cancellation. ```kotlin // --- Common code (shared module) --- import dev.icerock.moko.permissions.DeniedAlwaysException import dev.icerock.moko.permissions.DeniedException import dev.icerock.moko.permissions.Permission import dev.icerock.moko.permissions.PermissionsController import dev.icerock.moko.permissions.RequestCanceledException import dev.icerock.moko.permissions.camera.CAMERA import dev.icerock.moko.permissions.location.LOCATION import dev.icerock.moko.permissions.microphone.RECORD_AUDIO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class MediaViewModel( val permissionsController: PermissionsController, private val scope: CoroutineScope ) { fun requestCamera() { scope.launch { try { permissionsController.providePermission(Permission.CAMERA) // Camera access granted — proceed with feature openCamera() } catch (e: DeniedAlwaysException) { // User permanently denied; prompt to open Settings permissionsController.openAppSettings() } catch (e: DeniedException) { // User denied this time; can ask again later showRationale() } catch (e: RequestCanceledException) { // Android-only: dialog was dismissed without a choice } } } fun requestLocation() { scope.launch { val granted = permissionsController.isPermissionGranted(Permission.LOCATION) if (!granted) { permissionsController.providePermission(Permission.LOCATION) } } } } ``` -------------------------------- ### Importing Permission Modules Source: https://context7.com/icerockdev/moko-permissions/llms.txt Import the relevant sub-modules for each permission type you intend to use. Ensure the corresponding Gradle dependency is included. ```kotlin import dev.icerock.moko.permissions.Permission // Import the relevant sub-modules: import dev.icerock.moko.permissions.bluetooth.* import dev.icerock.moko.permissions.camera.* import dev.icerock.moko.permissions.contacts.* import dev.icerock.moko.permissions.gallery.* import dev.icerock.moko.permissions.location.* import dev.icerock.moko.permissions.microphone.* import dev.icerock.moko.permissions.motion.* import dev.icerock.moko.permissions.notifications.* import dev.icerock.moko.permissions.storage.* ``` -------------------------------- ### Add Moko Permissions Dependencies to Gradle Source: https://context7.com/icerockdev/moko-permissions/llms.txt Include the core API and any desired permission-specific modules in your shared module's build.gradle.kts file. Also add the Compose Multiplatform integration and test utilities if needed. ```kotlin // build.gradle.kts (shared module) dependencies { // Core API (required) commonMainApi("dev.icerock.moko:permissions:0.20.1") // Optional permission modules — include only what your app needs commonMainImplementation("dev.icerock.moko:permissions-bluetooth:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-camera:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-contacts:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-gallery:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-location:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-microphone:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-motion:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-notifications:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-storage:0.20.1") // Compose Multiplatform integration commonMainApi("dev.icerock.moko:permissions-compose:0.20.1") // Test utilities commonTestImplementation("dev.icerock.moko:permissions-test:0.20.1") } ``` -------------------------------- ### Add moko-permissions to root build.gradle Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md Configure the mavenCentral() repository in your root build.gradle file to download moko-permissions artifacts. ```groovy allprojects { repositories { mavenCentral() } } ``` -------------------------------- ### providePermission(permission) Source: https://context7.com/icerockdev/moko-permissions/llms.txt Suspends until the user grants or denies the permission. If already granted, returns immediately. Throws `DeniedException`, `DeniedAlwaysException`, or `RequestCanceledException` on failure. ```APIDOC ## providePermission(permission) — Request a Permission Suspends until the user grants or denies the permission. If already granted, returns immediately. Throws `DeniedException`, `DeniedAlwaysException`, or `RequestCanceledException` on failure. ```kotlin // Common code suspend fun ensureMicrophoneAccess(controller: PermissionsController) { try { controller.providePermission(Permission.RECORD_AUDIO) println("Microphone granted — start recording") } catch (e: DeniedAlwaysException) { println("Microphone permanently denied: ${e.permission}") controller.openAppSettings() } catch (e: DeniedException) { println("Microphone denied: ${e.permission} — show explanation") } } ``` ``` -------------------------------- ### Add moko-permissions dependencies to project build.gradle Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md Include the moko-permissions library and its specific permission modules in your project's build.gradle file. The compose module provides extensions for Jetpack Compose. ```groovy dependencies { commonMainApi("dev.icerock.moko:permissions:0.20.1") // specific permissions support commonMainImplementation("dev.icerock.moko:permissions-bluetooth:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-camera:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-contacts:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-gallery:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-location:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-microphone:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-motion:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-notifications:0.20.1") commonMainImplementation("dev.icerock.moko:permissions-storage:0.20.1") // compose multiplatform commonMainApi("dev.icerock.moko:permissions-compose:0.20.1") // permissions api + compose extensions commonTestImplementation("dev.icerock.moko:permissions-test:0.20.1") } ``` -------------------------------- ### Binding Permissions Controller to Lifecycle (Compose) Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md For Compose applications, bind the permissions controller to the `LocalLifecycleOwner`'s lifecycle using `BindEffect`. ```kotlin @Composable fun TestScreen() { val viewModel = getViewModel { // Pass the platform implementation of the permission controller to a common code. ViewModel(PermissionsController()) } // Binds the permissions controller to the LocalLifecycleOwner lifecycle. BindEffect(viewModel.permissionsController) } ``` -------------------------------- ### Requesting Permissions in ViewModel (Common Kotlin) Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md Use this common code within your ViewModel to request permissions. It handles success and various denial scenarios. ```kotlin class ViewModel(val permissionsController: PermissionsController): ViewModel() { fun onPhotoPressed() { viewModelScope.launch { try { permissionsController.providePermission(Permission.GALLERY) // Permission has been granted successfully. } catch(deniedAlways: DeniedAlwaysException) { // Permission is always denied. } catch(denied: DeniedException) { // Permission was denied. } } } } ``` -------------------------------- ### Ensure Microphone Access with Moko Permissions Source: https://context7.com/icerockdev/moko-permissions/llms.txt This function checks if microphone access is granted and requests it if not. It handles permanent denial by opening app settings and temporary denial by showing an explanation. ```kotlin // Common code suspend fun ensureMicrophoneAccess(controller: PermissionsController) { try { controller.providePermission(Permission.RECORD_AUDIO) println("Microphone granted — start recording") } catch (e: DeniedAlwaysException) { println("Microphone permanently denied: ${e.permission}") controller.openAppSettings() } catch (e: DeniedException) { println("Microphone denied: ${e.permission} — show explanation") } } ``` -------------------------------- ### PermissionsController Interface Source: https://context7.com/icerockdev/moko-permissions/llms.txt The central interface for all permission operations, implemented natively per platform and consumed from common Kotlin code. ```APIDOC ## PermissionsController Interface The central interface for all permission operations. Implemented natively per platform; consumed from common Kotlin code. On Android an instance must be bound to a `ComponentActivity`; on iOS no binding is needed. ```kotlin // --- Common code (shared module) --- import dev.icerock.moko.permissions.DeniedAlwaysException import dev.icerock.moko.permissions.DeniedException import dev.icerock.moko.permissions.Permission import dev.icerock.moko.permissions.PermissionsController import dev.icerock.moko.permissions.RequestCanceledException import dev.icerock.moko.permissions.camera.CAMERA import dev.icerock.moko.permissions.location.LOCATION import dev.icerock.moko.permissions.microphone.RECORD_AUDIO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class MediaViewModel( val permissionsController: PermissionsController, private val scope: CoroutineScope ) { fun requestCamera() { scope.launch { try { permissionsController.providePermission(Permission.CAMERA) // Camera access granted — proceed with feature openCamera() } catch (e: DeniedAlwaysException) { // User permanently denied; prompt to open Settings permissionsController.openAppSettings() } catch (e: DeniedException) { // User denied this time; can ask again later showRationale() } catch (e: RequestCanceledException) { // Android-only: dialog was dismissed without a choice } } } fun requestLocation() { scope.launch { val granted = permissionsController.isPermissionGranted(Permission.LOCATION) if (!granted) { permissionsController.providePermission(Permission.LOCATION) } } } } ``` ``` -------------------------------- ### Binding Permissions Controller to Activity (Android) Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md In Android, bind the permissions controller to the activity's lifecycle within `onCreate` for proper management. ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val viewModel = getViewModel { // Pass the platform implementation of the permission controller to a common code. ViewModel(PermissionsController()) } // Binds the permissions controller to the activity lifecycle. viewModel.permissionsController.bind(activity) } ``` -------------------------------- ### Compose Multiplatform with Moko MVVM Source: https://github.com/icerockdev/moko-permissions/blob/master/README.md Integrates Moko Permissions with Moko MVVM, ensuring correct configuration change handling on Android and binding the controller to the ViewModel. ```kotlin @Composable fun Sample() { val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory() val viewModel: PermissionsViewModel = getViewModel( key = "permissions-screen", factory = viewModelFactory { PermissionsViewModel(factory.createPermissionsController()) } ) BindEffect(viewModel.permissionsController) Button(onClick = viewModel::onButtonClick) { Text(text = "give permissions") } } class PermissionsViewModel( val permissionsController: PermissionsController ) : ViewModel() { fun onButtonClick() { viewModelScope.launch { permissionsController.providePermission(Permission.REMOTE_NOTIFICATION) } } } ``` -------------------------------- ### Create PermissionsController with rememberPermissionsControllerFactory Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use `rememberPermissionsControllerFactory` to create a `PermissionsController` within a Composable. This is recommended when the controller should survive configuration changes and is owned by a ViewModel. ```kotlin import dev.icerock.moko.permissions.PermissionsController import dev.icerock.moko.permissions.compose.BindEffect import dev.icerock.moko.permissions.compose.PermissionsControllerFactory import dev.icerock.moko.permissions.compose.rememberPermissionsControllerFactory import dev.icerock.moko.permissions.gallery.GALLERY // Shared Composable (works on Android + iOS) @Composable fun GalleryScreen() { val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory() val controller: PermissionsController = remember(factory) { factory.createPermissionsController() } val scope = rememberCoroutineScope() BindEffect(controller) // Binds lifecycle on Android; no-op on iOS Button(onClick = { scope.launch { try { controller.providePermission(Permission.GALLERY) openPhotoPicker() } catch (e: DeniedAlwaysException) { controller.openAppSettings() } catch (e: DeniedException) { // Retry later } } }) { Text("Pick Photo") } } // With moko-mvvm (survives Android config changes): @Composable fun GalleryScreenWithViewModel() { val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory() val viewModel: GalleryViewModel = getViewModel( key = "gallery-screen", factory = viewModelFactory { GalleryViewModel(factory.createPermissionsController()) } ) BindEffect(viewModel.permissionsController) Button(onClick = viewModel::onPickPhoto) { Text("Pick Photo") } } ``` -------------------------------- ### getPermissionState(permission) Source: https://context7.com/icerockdev/moko-permissions/llms.txt Retrieves the detailed current state of a permission. This is useful for conditional UI rendering without triggering a permission request. ```APIDOC ## `getPermissionState(permission)` — Inspect Detailed Permission State ### Description Returns a `PermissionState` enum value describing the current state in detail. Useful for conditional UI rendering without triggering a request. ### Method `getPermissionState` ### Parameters #### Path Parameters - **permission** (Permission) - Required - The permission to inspect. ### Response #### Success Response (PermissionState) - **PermissionState.NotDetermined**: The permission has never been asked for. - **PermissionState.NotGranted**: The permission is not granted (on Android, this could be denied or not asked). - **PermissionState.Granted**: The permission is granted, and the feature is available. - **PermissionState.Denied**: The permission has been denied (on Android, a rationale might be shown before retrying). - **PermissionState.DeniedAlways**: The permission has been permanently denied, and the user should be directed to Settings. ``` -------------------------------- ### bind(activity) Source: https://context7.com/icerockdev/moko-permissions/llms.txt Binds the PermissionsController to a ComponentActivity on Android. This is essential for registering the ActivityResultLauncher and ensuring proper lifecycle cleanup for permission requests. ```APIDOC ## Android — `bind(activity)` — Lifecycle Binding ### Description On Android, `PermissionsController` must be bound to a `ComponentActivity` before any permission can be requested. This registers the `ActivityResultLauncher` and attaches lifecycle cleanup. ### Method `bind` ### Parameters #### Path Parameters - **activity** (ComponentActivity) - Required - The activity to bind the controller to. ``` -------------------------------- ### Compose Lifecycle Binding Source: https://context7.com/icerockdev/moko-permissions/llms.txt In Jetpack Compose, use the `BindEffect(permissionsController)` composable. It automatically handles binding the controller to the `LocalLifecycleOwner` and re-binds on recomposition, simplifying lifecycle management. ```kotlin import dev.icerock.moko.permissions.PermissionsController import dev.icerock.moko.permissions.compose.BindEffect import dev.icerock.moko.permissions.notifications.REMOTE_NOTIFICATION @Composable fun NotificationsScreen(viewModel: NotificationsViewModel) { // Automatically binds on Android; no-op on iOS BindEffect(viewModel.permissionsController) val scope = rememberCoroutineScope() Button(onClick = { scope.launch { try { viewModel.permissionsController.providePermission(Permission.REMOTE_NOTIFICATION) } catch (e: DeniedAlwaysException) { viewModel.permissionsController.openAppSettings() } } }) { Text("Enable Notifications") } } ``` -------------------------------- ### Evaluating Permission State Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use `PermissionState` enum with `controller.getPermissionState()` to determine the current status of a permission. This is useful for conditionally updating the UI. ```kotlin import dev.icerock.moko.permissions.PermissionState // Evaluate permission state for conditional UI suspend fun updatePermissionUI( controller: PermissionsController, permission: Permission ): String = when (controller.getPermissionState(permission)) { PermissionState.NotDetermined -> "Not yet requested" // Both platforms PermissionState.NotGranted -> "Not granted" // Android-only PermissionState.Granted -> "Granted" // Both platforms PermissionState.Denied -> "Denied (retry ok)" // Android-only PermissionState.DeniedAlways -> "Permanently denied" // Android (all), iOS (push only) } ``` -------------------------------- ### Android Lifecycle Binding Source: https://context7.com/icerockdev/moko-permissions/llms.txt On Android, `PermissionsController` must be bound to a `ComponentActivity` using `bind(activity)`. This is essential for registering `ActivityResultLauncher` and ensuring proper lifecycle cleanup. ```kotlin // Android Activity import dev.icerock.moko.permissions.PermissionsController class MainActivity : AppCompatActivity() { private lateinit var viewModel: MyViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val controller = PermissionsController(applicationContext = applicationContext) viewModel = ViewModelProvider(this)[MyViewModel::class.java].also { vm -> vm.permissionsController = controller } // Must bind before any permission request fires controller.bind(this) } } ``` -------------------------------- ### BindEffect(permissionsController) Source: https://context7.com/icerockdev/moko-permissions/llms.txt A Composable function that automatically binds the PermissionsController to the current LifecycleOwner within a Compose UI. It handles binding on Android and is a no-op on iOS, simplifying lifecycle management in Compose applications. ```APIDOC ## Compose — `BindEffect(permissionsController)` — Compose Lifecycle Binding ### Description In a Composable, use `BindEffect` instead of manually calling `bind()`. It automatically binds the controller to the current `LocalLifecycleOwner` and re-binds on recomposition. ### Method `BindEffect` ### Parameters #### Path Parameters - **permissionsController** (PermissionsController) - Required - The controller to bind to the Compose lifecycle. ``` -------------------------------- ### Check if Permission is Granted Source: https://context7.com/icerockdev/moko-permissions/llms.txt Use `isPermissionGranted` to check the status without requesting. It returns true if granted, false otherwise. Useful for conditional logic before performing actions. ```kotlin suspend fun checkBeforeUpload(controller: PermissionsController) { val hasStorage = controller.isPermissionGranted(Permission.STORAGE) val hasCamera = controller.isPermissionGranted(Permission.CAMERA) when { hasStorage && hasCamera -> startUpload() !hasCamera -> println("Camera permission missing") !hasStorage -> println("Storage permission missing") } } ``` -------------------------------- ### isPermissionGranted(permission) Source: https://context7.com/icerockdev/moko-permissions/llms.txt Checks if a specific permission is currently granted without prompting the user. Returns true if granted, false otherwise. ```APIDOC ## `isPermissionGranted(permission)` — Check Permission Without Requesting ### Description Returns `true` if the permission is currently granted, `false` otherwise. Does not show any system dialog. ### Method `isPermissionGranted` ### Parameters #### Path Parameters - **permission** (Permission) - Required - The permission to check. ### Response #### Success Response (Boolean) - **true**: The permission is granted. - **false**: The permission is not granted. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.