### Complete Info.plist Example for iOS
Source: https://github.com/brewkits/grant/blob/main/docs/platform-specific/ios/info-plist.md
This example shows a complete Info.plist file with descriptions for camera, microphone, photo library, location, contacts, Bluetooth, and motion usage.
```xml
CFBundleDisplayName
My Awesome App
NSCameraUsageDescription
Camera is needed to scan QR codes for secure login
NSMicrophoneUsageDescription
Microphone is needed to record audio for video messages
NSPhotoLibraryUsageDescription
Photo library access lets you select images for your profile
NSLocationWhenInUseUsageDescription
Location is needed to show nearby restaurants and stores
NSContactsUsageDescription
Access to contacts helps you find and invite friends
NSBluetoothAlwaysUsageDescription
Bluetooth is used to connect to your fitness tracker
NSMotionUsageDescription
Motion data is used to track your steps and activity level
```
--------------------------------
### Build and Install Android Demo App
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
Use this command to build and install the Android demo application onto a connected device or emulator.
```bash
./gradlew :demo:installDebug
```
--------------------------------
### Actionable Settings Guide for Camera
Source: https://github.com/brewkits/grant/blob/main/docs/BEST_PRACTICES.md
Illustrates an actionable, step-by-step settings message for enabling camera permission, guiding the user through the process.
```kotlin
settingsMessage = "Camera access was denied. To enable:\n\n1. Tap 'Open Settings' below
2. Enable Camera permission
3. Return to app and try again"
```
--------------------------------
### Install and Run Android Demo via Gradle
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
Use these Gradle commands to install the Android demo application and launch it. This is the primary method for running the demo on Android using the command line.
```bash
# Option 1: Gradle
./gradlew :demo:installDebug
adb shell am start -n dev.brewkits.grant.demo/.MainActivity
```
--------------------------------
### Install Grant Core on Android
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START.md
Installs the Grant Core demo app on a connected Android device or emulator. Follow the on-screen prompts to test camera grant functionality.
```bash
# Install on device/emulator
./gradlew :demo:installDebug
# Test camera grant:
# 1. Tap "Request Camera"
# 2. Allow grant
# 3. Should show "Granted"
```
--------------------------------
### Test Case 1: First Request (Fresh Install)
Source: https://github.com/brewkits/grant/blob/main/docs/FIX_DEAD_CLICK_ANDROID.md
Verifies the expected behavior for the initial permission request on a fresh app install, including the system dialog and subsequent rationale dialog.
```text
1. Install app
2. Click "Request Camera"
3. EXPECTED: System dialog appears
4. Deny
5. EXPECTED: No dialog (isFirstRequest=true)
6. Click again
7. EXPECTED: Rationale dialog appears ✅
```
--------------------------------
### Grant Handler ViewModel Setup
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/ARCHITECTURE.md
Example of setting up a GrantHandler in a ViewModel. This requires the permission manager, the specific app grant, and the viewModelScope.
```kotlin
// ViewModel (3 lines!)
val cameraGrant = GrantHandler(manager, AppGrant.CAMERA, viewModelScope)
```
--------------------------------
### Platform-Specific Settings Guide
Source: https://github.com/brewkits/grant/blob/main/docs/BEST_PRACTICES.md
Shows how to provide platform-specific instructions for enabling permissions in the device settings.
```kotlin
settingsMessage = when (platform) {
Platform.ANDROID -> "Enable in Settings > Apps > ${appName} > Permissions > Camera"
Platform.IOS -> "Enable in Settings > ${appName} > Camera"
}
```
--------------------------------
### Launch Android Demo App
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
Use this command to launch the installed Android demo application via ADB.
```bash
adb shell am start -n dev.brewkits.grant.demo/.MainActivity
```
--------------------------------
### List Available Simulators
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START_iOS.md
Use this command to list all available simulators on your system. You can install more simulators via Xcode settings.
```bash
# List available simulators
xcrun simctl list devices
# Install more simulators via Xcode:
# Xcode > Settings > Platforms
```
--------------------------------
### All Permission Types Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Test file covering all permission types.
```kotlin
package dev.brewkits.grant
import kotlin.test.Test
class AllPermissionTypesTest {
@Test
fun testAllPermissionTypes() {
// Add assertions for all 14 permission types
}
}
```
--------------------------------
### Setup Grant Koin Modules
Source: https://github.com/brewkits/grant/blob/main/docs/DEPENDENCY_MANAGEMENT.md
Configure Koin to include Grant's DI modules. This should be done during your Koin setup.
```kotlin
startKoin {
modules(
grantModule, // Common Grant DI
grantPlatformModule // Platform-specific (Android/iOS)
)
}
```
--------------------------------
### iOS Basic Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
This is a basic test file for iOS, part of the completed iOS test infrastructure.
```kotlin
package dev.brewkits.grant
import kotlin.test.Test
import kotlin.test.assertTrue
class IosBasicTest {
@Test
fun testExample() {
assertTrue(true, "iOS basic test should pass")
}
}
```
--------------------------------
### Initializing modules on iOS
Source: https://github.com/brewkits/grant/blob/main/docs/ios/APPLE_FRAMEWORK_LINKING_ISSUE.md
Shows how to initialize the Grant permission modules once at application start on iOS. Call `initialize()` for each module that has been added as a dependency.
```kotlin
// iosMain — call once, e.g. in ApplicationDelegate
GrantContacts.initialize()
GrantCalendar.initialize()
GrantMotion.initialize()
```
--------------------------------
### Example Info.plist Permission Descriptions
Source: https://github.com/brewkits/grant/blob/main/docs/ios/INFO_PLIST_LOCALIZATION.md
Shows how permission descriptions are defined within the Info.plist file using XML keys and string values.
```xml
NSCameraUsageDescription
Camera is used to scan QR codes
NSLocationWhenInUseUsageDescription
Location is used to show nearby stores
```
--------------------------------
### iOS Bluetooth Manager Delegate Example
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
An example of a custom delegate for handling iOS CoreBluetooth state changes and asynchronous grant requests.
```kotlin
class BluetoothManagerDelegate {
// Handles CoreBluetooth state changes
// Async grant requests
}
```
--------------------------------
### Good Info.plist Descriptions
Source: https://github.com/brewkits/grant/blob/main/docs/platform-specific/ios/info-plist.md
Examples of specific and user-friendly usage descriptions for Info.plist keys, recommended for clarity and user trust.
```xml
NSCameraUsageDescription
Camera is needed to scan QR codes
NSMicrophoneUsageDescription
Microphone is needed to record voice messages
```
--------------------------------
### Install Xcode Command Line Tools
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START_iOS.md
Run this command in the terminal to install the Xcode Command Line Tools if you encounter 'xcodebuild: command not found' errors.
```bash
xcode-select --install
```
--------------------------------
### Consumer build.gradle.kts example
Source: https://github.com/brewkits/grant/blob/main/docs/ios/APPLE_FRAMEWORK_LINKING_ISSUE.md
Illustrates how a consumer's `build.gradle.kts` file can manage dependencies to avoid unnecessary framework inclusion. Shows that `grant-contacts.klib` is not downloaded or compiled when not explicitly added.
```kotlin
Consumer build.gradle.kts:
implementation("dev.brewkits:grant-core:2.1.0")
// grant-contacts NOT added
▼ Dependency resolution
grant-core.klib downloaded ✅
grant-contacts.klib NOT downloaded — never compiled
▼ K/N ObjC interop
ContactsPermissionHandler.kt NEVER processed
"Contacts" framework string NEVER emitted into metadata
▼ Apple static analyzer
No "Contacts" metadata found
NSContactsUsageDescription NOT required ✅
```
--------------------------------
### Dependency Injection with Koin and Manual Setup
Source: https://github.com/brewkits/grant/blob/main/grant-core/README.md
Shows how to integrate GrantManager with dependency injection frameworks like Koin or through manual class construction. Requires context for Koin.
```kotlin
// Koin
val grantModule = module {
single { GrantFactory.create(androidContext()) }
}
// Manual
class MyRepository(private val grantManager: GrantManager) {
suspend fun requestCamera() = grantManager.request(AppGrant.CAMERA)
}
```
--------------------------------
### Optimize Activity Launch Time (Kotlin)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/TRANSPARENT_ACTIVITY_GUIDE.md
Implement minimal overhead in `onCreate` by avoiding layout inflation and view setup. Directly proceed to the grant request to improve launch speed.
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// No layout inflation
// No view setup
// Direct to grant request
requestGrants()
}
```
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.transparent) // ❌ Don't do this!
setupViews() // ❌ Don't do this!
requestGrants()
}
```
--------------------------------
### Performance Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Performance test file for measuring request latency and memory efficiency.
```kotlin
package dev.brewkits.grant.performance
import kotlin.test.Test
class PerformanceTest {
@Test
fun testRequestLatencyAndMemory() {
// Add assertions for performance tests
}
}
```
--------------------------------
### Abstraction with GrantManager (Good)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/ARCHITECTURE.md
This example demonstrates abstracting platform dependencies by depending on a `GrantManager` interface, improving testability and platform independence.
```kotlin
// ✅ GOOD: Depend on abstraction
class CameraViewModel(
private val grantManager: GrantManager // Platform-agnostic!
) {
suspend fun requestCamera() {
val status = grantManager.checkStatus(AppGrant.CAMERA)
when (status) {
GrantStatus.GRANTED -> openCamera()
// ...
}
}
}
```
--------------------------------
### Android Koin Setup
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/GRANTS.md
Integrate Grant's Koin modules into your Android application's onCreate method. Ensure the DemoApplication class extends Application and calls startKoin with the appropriate modules.
```kotlin
package dev.brewkits.grant.demo
import android.app.Application
import dev.brewkits.grant.di.grantModule
import dev.brewkits.grant.di.grantPlatformModule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
class DemoApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@DemoApplication)
modules(
grantModule,
grantPlatformModule
)
}
}
}
```
```xml
```
--------------------------------
### Setup iOS Simulator Run Configuration (External Tool)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START_iOS.md
Configure Android Studio to run an iOS simulator using an external tool. This method allows for more granular control over the execution.
```bash
/bin/bash
```
```bash
$ProjectFileDir$/setup-ios-app.sh
```
--------------------------------
### Simplified ViewModel with GrantHandler (Good)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/ARCHITECTURE.md
This example demonstrates using the `GrantHandler` composition pattern to significantly reduce boilerplate code in a ViewModel for handling permission requests.
```kotlin
// ✅ GOOD: 3 lines!
class CameraViewModel(manager: GrantManager) : ViewModel() {
val cameraGrant = GrantHandler(
manager,
AppGrant.CAMERA,
viewModelScope
)
fun onCaptureClick() {
cameraGrant.request { openCamera() }
}
}
```
--------------------------------
### Gradle Installation (Kotlin DSL)
Source: https://github.com/brewkits/grant/blob/main/grant-core/README.md
Add the Grant Core dependency to your project using Gradle with Kotlin DSL. Ensure mavenCentral() is configured in your repositories.
```kotlin
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
// shared/build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("dev.brewkits.grant:grant-core:1.0.2")
}
}
}
```
--------------------------------
### Setup ViewModel with GrantHandler
Source: https://github.com/brewkits/grant/blob/main/grant-compose/README.md
Set up your ViewModel by initializing a GrantHandler for the desired permission. This handler manages the permission request lifecycle and state. The request block runs only when the permission is granted.
```kotlin
import dev.brewkits.grant.*
class CameraViewModel(grantManager: GrantManager) : ViewModel() {
val cameraGrant = GrantHandler(
grantManager = grantManager,
grant = AppGrant.CAMERA,
scope = viewModelScope
)
fun onTakePhotoClick() {
cameraGrant.request {
// This runs ONLY when permission is granted
openCamera()
}
}
}
```
--------------------------------
### Setup iOS Simulator Run Configuration (Shell Script)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START_iOS.md
Configure Android Studio to run an iOS simulator using a shell script. This script automates the build and launch process.
```bash
cd "$PROJECT_DIR" && ./setup-ios-app.sh
```
--------------------------------
### Create Service Manager
Source: https://github.com/brewkits/grant/blob/main/docs/getting-started/installation.md
Instantiate a service manager to check hardware states like GPS or Bluetooth. This example requires a `Context` on Android.
```kotlin
val serviceManager = ServiceFactory.createServiceManager(context)
```
--------------------------------
### Check Specific UI States
Source: https://github.com/brewkits/grant/blob/main/grant-compose/README.md
Check specific states within the collected UI state object to conditionally display UI elements or perform actions. For example, check if a rationale should be shown or if a settings guide is needed.
```kotlin
if (state.showRationale) { /* ... */ }
if (state.showSettingsGuide) { /* ... */ }
```
--------------------------------
### Error Handling Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Example test file for error handling scenarios.
```kotlin
package dev.brewkits.grant
import kotlin.test.Test
class ErrorHandlingTest {
@Test
fun testErrorPaths() {
// Add assertions for error handling paths
}
}
```
--------------------------------
### Compose Multiplatform Manual Instance Creation
Source: https://github.com/brewkits/grant/blob/main/docs/DEPENDENCY_MANAGEMENT.md
Create GrantManager and GrantHandler instances within a Compose Multiplatform Composable. This example shows how to manage the lifecycle of these instances using `remember`.
```kotlin
@Composable
fun App() {
// Create once and remember
val grantManager = remember {
GrantFactory.create(
context = LocalContext.current // Android
// or null for iOS
)
}
val handler = remember {
GrantHandler(
grantManager = grantManager,
grant = AppGrant.CAMERA,
scope = rememberCoroutineScope()
)
}
// Use handler
}
```
--------------------------------
### Build iOS Framework for Demo
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
Build the iOS framework for the demo application using Gradle. This command is necessary before opening the project in Xcode.
```bash
# Build framework
./gradlew :demo:linkDebugFrameworkIosSimulatorArm64
# Open Xcode
open demo/iosApp/iosApp.xcodeproj
# Build & Run on simulator
```
--------------------------------
### iOS Location Manager Delegate Example
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_SETUP.md
An example of a custom delegate for handling iOS CoreLocation callbacks. It converts native asynchronous callbacks into Kotlin coroutines and ensures main thread safety.
```kotlin
// Custom delegates for complex grants
class LocationManagerDelegate {
// Handles CoreLocation async callbacks
// Converts to Kotlin coroutines
// Main thread safety
}
```
--------------------------------
### Provide User Guidance for Service Issues
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/SERVICES.md
When a service is not ready, inform the user clearly and provide an actionable prompt to resolve the issue, such as opening service settings.
```kotlin
when (checker.checkLocationReady()) {
is LocationReadyStatus.ServiceDisabled -> {
showDialog(
title = "GPS is Off",
message = "Please turn on GPS to use location features",
action = "Enable GPS"
) {
serviceManager.openServiceSettings(ServiceType.LOCATION_GPS)
}
}
// ...
}
```
--------------------------------
### Validate Persistent Grant Store on App Start
Source: https://github.com/brewkits/grant/blob/main/docs/architecture/grant-store.md
If using a persistent grant store, implement validation logic to detect and correct potential desynchronization between the cached state and the actual grant status when the app starts.
```kotlin
class ValidatedGrantStore(private val delegate: GrantStore) : GrantStore by delegate {
suspend fun validateOnStart(grantManager: GrantManager) {
AppGrant.entries.forEach { grant ->
val cached = getStatus(grant)
val actual = grantManager.checkStatus(grant)
if (cached != actual) {
// Desync detected! Update cache
setStatus(grant, actual)
}
}
}
}
```
--------------------------------
### Start Location Tracking with Service and Permission Checks
Source: https://github.com/brewkits/grant/blob/main/docs/getting-started/quick-start.md
This function checks if location services are enabled and if the necessary location permission is granted before starting location tracking. It handles opening settings if services or permissions are denied.
```kotlin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun startLocationTracking(): Boolean {
val serviceManager = ServiceFactory.create(context)
// Step 1: Check service
if (!serviceManager.isLocationEnabled()) {
withContext(Dispatchers.Main) {
showDialog("Please enable GPS in Settings")
}
serviceManager.openLocationSettings()
return false
}
// Step 2: Check permission
val status = grantManager.request(AppGrant.LOCATION)
if (status != GrantStatus.GRANTED) {
withContext(Dispatchers.Main) {
if (status == GrantStatus.DENIED_ALWAYS) {
showDialog("Location permission denied. Please enable in Settings")
grantManager.openSettings()
} else {
showDialog("Location permission is required")
}
}
return false
}
// All good!
return true
}
```
--------------------------------
### Build and Run Demo App
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START.md
Build all modules and run the Android demo application. For iOS, open the Xcode project.
```bash
# Build everything
./gradlew clean build
# Run Android demo
./gradlew :demo:installDebug
# Run iOS demo (requires Xcode)
open demo/iosApp/iosApp.xcodeproj
```
--------------------------------
### Expected SharedPreferences Content
Source: https://github.com/brewkits/grant/blob/main/docs/FIX_DEAD_CLICK_ANDROID.md
Example of the XML content expected in SharedPreferences after a permission has been requested.
```xml
```
--------------------------------
### Bad Info.plist Descriptions
Source: https://github.com/brewkits/grant/blob/main/docs/platform-specific/ios/info-plist.md
Examples of generic and unhelpful usage descriptions for Info.plist keys, which are not recommended.
```xml
NSCameraUsageDescription
This app needs access to function
NSMicrophoneUsageDescription
This app needs access to function
```
--------------------------------
### Setup Media Picker Screen with Fallback
Source: https://github.com/brewkits/grant/blob/main/docs/recipes/photo-picker-fallback.md
Sets up the Photo Picker launcher and a function to either launch the picker on Android 13+ or fall back to requesting gallery permissions for older versions. Requires `GrantHandler` for the fallback.
```kotlin
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import dev.brewkits.grant.GrantHandler
@Composable
fun MediaPickerScreen(galleryGrantHandler: GrantHandler) {
// 1. Setup the Photo Picker launcher
val photoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia()
) { uri ->
if (uri != null) {
// User selected an image
processImage(uri)
}
}
// 2. Function to launch the picker or fallback to permissions
fun pickImage() {
if (ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable()) {
// Android 13+ (or backported via Google Play Services)
// No permissions needed!
photoPickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
} else {
// Fallback for older Android versions
galleryGrantHandler.requestSuspend(
rationaleMessage = "We need gallery access to let you pick a photo."
) { status ->
if (status == GrantStatus.GRANTED) {
// Launch traditional ACTION_GET_CONTENT or custom gallery UI
launchLegacyImagePicker()
}
}
}
}
// ... UI ...
}
```
--------------------------------
### Regression Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Regression test file created to prevent previously fixed bugs from reappearing.
```kotlin
package dev.brewkits.grant.regression
import kotlin.test.Test
class RegressionTest {
@Test
fun testBugPrevention() {
// Add assertions for regression tests
}
}
```
--------------------------------
### Boot Simulator and Open App Manually
Source: https://github.com/brewkits/grant/blob/main/docs/ios/QUICK_START_IOS_ANDROID_STUDIO.md
If the app doesn't launch, use these bash commands to manually boot a specific simulator and open the Simulator application.
```bash
xcrun simctl boot "iPhone 16"
open -a Simulator
```
--------------------------------
### Group Handler Stress Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Stress test file for the GroupHandler, simulating high-volume operations.
```kotlin
package dev.brewkits.grant.performance
import kotlin.test.Test
class GroupHandlerStressTest {
@Test
fun testHighVolumeOperations() {
// Add assertions for stress tests
}
}
```
--------------------------------
### Grant Group Handler Integration Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Integration test for the GrantGroupHandler, focusing on multi-permission flows.
```kotlin
package dev.brewkits.grant.integration
import kotlin.test.Test
class GrantGroupHandlerIntegrationTest {
@Test
fun testMultiPermissionFlows() {
// Add assertions for GrantGroupHandler integration tests
}
}
```
--------------------------------
### Grant Handler Integration Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Integration test for the GrantHandler, covering complete user flows.
```kotlin
package dev.brewkits.grant.integration
import kotlin.test.Test
class GrantHandlerIntegrationTest {
@Test
fun testCompleteUserFlows() {
// Add assertions for GrantHandler integration tests
}
}
```
--------------------------------
### Inject GrantAndServiceChecker with Koin
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/SERVICES.md
Example of injecting the GrantAndServiceChecker into a ViewModel using Koin's automatic dependency injection.
```kotlin
class MyViewModel(
private val checker: GrantAndServiceChecker // Auto-injected
) : ViewModel()
```
--------------------------------
### Open Demo App on Android
Source: https://github.com/brewkits/grant/blob/main/docs/demo/DEMO_GUIDE.md
Use this ADB command to open the Grant Demo app's main activity on an Android device.
```bash
adb shell am start -n dev.brewkits.grant.demo/dev.brewkits.grant.demo.MainActivity
```
--------------------------------
### Saved State Delegate Integration Test Example
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Integration test for SavedStateDelegate, validating process death recovery.
```kotlin
package dev.brewkits.grant.integration
import kotlin.test.Test
class SavedStateDelegateIntegrationTest {
@Test
fun testProcessDeathRecovery() {
// Add assertions for SavedStateDelegate integration tests
}
}
```
--------------------------------
### Available iOS App Configurations
Source: https://github.com/brewkits/grant/blob/main/docs/ios/QUICK_START_IOS_ANDROID_STUDIO.md
View the different configurations available for running the iOS app, including specific simulators and building the framework.
```text
📱 iosApp → iPhone 16 (default)
📱 iosApp (iPhone 16 Pro) → iPhone 16 Pro
📱 iosApp (iPad Pro) → iPad Pro 11-inch
🔧 Build iOS Framework Only → Build framework only
```
--------------------------------
### Boot an iOS Simulator
Source: https://github.com/brewkits/grant/blob/main/docs/ios/IOS_SETUP_ANDROID_STUDIO.md
Boots a specific iOS simulator before it can be used. Replace 'iPhone 16' with the desired simulator name.
```bash
xcrun simctl boot "iPhone 16"
```
--------------------------------
### Grant Manager Integration
Source: https://github.com/brewkits/grant/blob/main/demo/README.md
Initialize the GrantManager and GrantDemoViewModel in your Android application's setup, typically in the MainActivity or AppModule.
```kotlin
// In your app setup (MainActivity or AppModule)
val grantManager = get()
val viewModel = GrantDemoViewModel(
grantManager = grantManager,
scope = viewModelScope // or rememberCoroutineScope()
)
// In your Compose UI
GrantDemoScreen(viewModel = viewModel)
```
--------------------------------
### List Available iOS Simulators
Source: https://github.com/brewkits/grant/blob/main/docs/ios/IOS_SETUP_ANDROID_STUDIO.md
Executes a helper script to display a list of available iOS simulators on the system.
```bash
./list-ios-simulators.sh
```
--------------------------------
### Documentation as Tests with Annotations
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Shows how tests can serve as living documentation. Use descriptive test names to clarify behavior.
```kotlin
// Tests serve as documentation
@Test
fun `CAMERA permission should be requestable`()
@Test
fun `request with DENIED status should allow retry`()
```
--------------------------------
### GrantSettingsDialog
Source: https://github.com/brewkits/grant/blob/main/grant-compose/README.md
A composable dialog shown when a permission is permanently denied, guiding the user to open the app's settings.
```APIDOC
## GrantSettingsDialog
### Description
Shows settings guide when permission is permanently denied.
### Parameters
- **message** (String) - Required - The message to display to the user, instructing them to enable the permission in settings.
- **title** (String) - Optional - Default: "Permission Denied" - The title of the dialog.
- **confirmText** (String) - Optional - Default: "Open Settings" - The text for the confirmation button, typically to open settings.
- **dismissText** (String) - Optional - Default: "Cancel" - The text for the dismiss button.
- **onConfirm** (() -> Unit) - Required - Callback function when the user confirms, usually to open settings.
- **onDismiss** (() -> Unit) - Required - Callback function when the user dismisses the dialog.
### Usage
```kotlin
GrantSettingsDialog(
message = "Please enable camera access in Settings",
onConfirm = { handler.onSettingsConfirmed() },
onDismiss = { handler.onDismiss() }
)
```
```
--------------------------------
### Initialize Koin with Grant Modules (Kotlin)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/GRANTS.md
Properly initialize Koin with the necessary grant modules. Incorrect Koin initialization can lead to issues with grant requests.
```kotlin
// DemoApplication.kt
startKoin {
androidContext(this@DemoApplication)
modules(grantModule, grantPlatformModule)
}
```
--------------------------------
### Comprehensive State Transition Testing
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING_IMPROVEMENTS_SUMMARY.md
Illustrates testing all possible state transitions for permissions. Ensure all state changes are validated.
```kotlin
// Test all state transitions
NOT_DETERMINED → GRANTED
NOT_DETERMINED → DENIED
DENIED → GRANTED (after Settings)
DENIED → DENIED_ALWAYS
```
--------------------------------
### Run iOS Simulator Tests
Source: https://github.com/brewkits/grant/blob/main/docs/TESTING.md
Execute only the iOS Simulator tests for a specific module. This requires macOS and Xcode to be installed.
```bash
# iOS Simulator tests only (requires macOS + Xcode)
./gradlew :grant-core:iosSimulatorArm64Test
```
--------------------------------
### Migrate from Koin to Manual Dependency Creation
Source: https://github.com/brewkits/grant/blob/main/docs/DEPENDENCY_MANAGEMENT.md
Shows how to refactor ViewModel to use manual dependency injection instead of Koin's `inject()`.
```kotlin
class MyViewModel : ViewModel() {
private val grantManager: GrantManager by inject()
}
```
```kotlin
class MyViewModel(
private val grantManager: GrantManager
) : ViewModel()
// In your composition root
val grantManager = GrantFactory.create(context)
val viewModel = MyViewModel(grantManager)
```
--------------------------------
### Testing ViewModel with Grant Core
Source: https://github.com/brewkits/grant/blob/main/grant-core/README.md
Example of testing a ViewModel that uses Grant Core's fake manager to simulate permission states.
```kotlin
class MyViewModelTest {
@Test
fun `test camera permission flow`() = runTest {
val fakeManager = FakeGrantManager()
fakeManager.setStatus(AppGrant.CAMERA, GrantStatus.GRANTED)
val viewModel = MyViewModel(fakeManager)
viewModel.requestCamera()
assertTrue(viewModel.cameraOpened)
}
}
```
--------------------------------
### After: Simplified Camera Permission Handling with grant-compose
Source: https://github.com/brewkits/grant/blob/main/docs/grant-compose/COMPOSE_SUPPORT_RELEASE_NOTES.md
This snippet demonstrates the significantly reduced code needed to handle camera permissions using the grant-compose library's GrantDialog.
```kotlin
import dev.brewkits.grant.compose.GrantDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun CameraScreen(viewModel: CameraViewModel) {
// ✅ ONE LINE - handles everything
GrantDialog(handler = viewModel.cameraGrant)
// Your UI
Button(onClick = { viewModel.onCaptureClick() }) {
Text("Take Photo")
}
}
```
--------------------------------
### Build Framework for iOS Simulator
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/QUICK_START_iOS.md
Execute this Gradle command to build the framework for the iOS simulator, which is necessary if you encounter 'Framework not found' errors.
```bash
./gradlew :demo:linkDebugFrameworkIosSimulatorArm64
```
--------------------------------
### Summary of Build Pipeline Layers and Analysis
Source: https://github.com/brewkits/grant/blob/main/docs/ios/APPLE_FRAMEWORK_LINKING_ISSUE.md
Illustrates the flow from Kotlin/Native imports through various build stages to the final App Store analysis, highlighting where the static analyzer identifies framework references.
```text
import platform.CoreMotion.*
│
▼ K/N ObjC interop (COMPILE TIME)
.klib metadata: "CoreMotion" ◄── Apple static analyzer reads HERE
│
▼ K/N DCE (BUILD TIME)
Strips Kotlin class bodies — cannot retract metadata already emitted
│
▼ Linker (-weak_framework)
Changes LC_LOAD_DYLIB → LC_LOAD_WEAK_DYLIB — analyzer unaffected
│
▼ Apple static analyzer (UPLOAD TIME)
Finds "CoreMotion" in metadata → requires NSMotionUsageDescription
│
▼ Runtime
hasInfoPlistKey guard — prevents crash, too late for App Store
```
--------------------------------
### GrantSettingsDialog Component
Source: https://github.com/brewkits/grant/blob/main/grant-compose/README.md
GrantSettingsDialog is shown when a permission is permanently denied, guiding the user to enable it in settings. It requires a message and callbacks for confirmation and dismissal.
```kotlin
fun GrantSettingsDialog(
message: String,
title: String = "Permission Denied",
confirmText: String = "Open Settings",
dismissText: String = "Cancel",
onConfirm: () -> Unit,
onDismiss: () -> Unit
)
```
```kotlin
GrantSettingsDialog(
message = "Please enable camera access in Settings",
onConfirm = { handler.onSettingsConfirmed() },
onDismiss = { handler.onDismiss() }
)
```
--------------------------------
### English Localized InfoPlist.strings
Source: https://github.com/brewkits/grant/blob/main/docs/ios/INFO_PLIST_LOCALIZATION.md
This file provides English descriptions for various permission keys used in the Info.plist.
```strings
"NSCameraUsageDescription" = "Camera is used to scan QR codes for quick login and product identification";
/* Location Permissions */
"NSLocationWhenInUseUsageDescription" = "Location is used to show nearby stores and calculate delivery distance";
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Background location is used to track delivery routes even when the app is closed. This helps provide accurate delivery ETAs.";
/* Photo Library */
"NSPhotoLibraryUsageDescription" = "Photo library access is used to upload profile pictures and share product images";
/* Microphone */
"NSMicrophoneUsageDescription" = "Microphone is used to record voice messages and audio notes";
/* Contacts */
"NSContactsUsageDescription" = "Contacts access is used to help you find and invite friends to the app";
/* Bluetooth */
"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to connect to fitness trackers and smart devices";
/* Motion & Fitness */
"NSMotionUsageDescription" = "Motion data is used for step counting, activity tracking, and fitness goals";
```
--------------------------------
### Initialize ServiceFactory on Android
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/SERVICES.md
Required for Android. Initialize ServiceFactory with the application context in your Application class's onCreate method before starting Koin.
```kotlin
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// REQUIRED: Initialize ServiceFactory with context
ServiceFactory.init(this)
// Start Koin
startKoin {
modules(
grantModule, // Includes ServiceManager
grantPlatformModule
)
}
}
}
```
--------------------------------
### Grant Compose Permission Handling
Source: https://github.com/brewkits/grant/blob/main/grant-compose/README.md
Demonstrates the simplified approach to permission handling using Grant Compose with a single line of code.
```kotlin
import androidx.compose.runtime.*
// ✅ GRANT COMPOSE: One line, handles everything
@Composable
fun CameraScreen(viewModel: CameraViewModel) {
GrantDialog(handler = viewModel.cameraGrant) // That's it!
Button(onClick = { viewModel.onTakePhotoClick() }) {
Text("Take Photo")
}
}
```
--------------------------------
### Conventional Commit Example
Source: https://github.com/brewkits/grant/blob/main/CONTRIBUTING.md
Commit changes following the Conventional Commits specification. Use prefixes like 'feat:', 'fix:', 'docs:' to categorize your commits.
```bash
git commit -m "feat: Add your feature description"
```
--------------------------------
### Create Grant Manager with Custom Storage
Source: https://github.com/brewkits/grant/blob/main/grant-core/README.md
Demonstrates creating a GrantManager instance with default in-memory storage and how to provide a custom GrantStore implementation for advanced persistence needs.
```kotlin
// Default (recommended): In-memory storage
val grantManager = GrantFactory.create(context)
// Custom: Implement your own GrantStore
class MyCustomStore : GrantStore { /* ... */ }
val grantManager = GrantFactory.create(context, MyCustomStore())
```
--------------------------------
### Test Case 3: After Settings Enable
Source: https://github.com/brewkits/grant/blob/main/docs/FIX_DEAD_CLICK_ANDROID.md
Tests the scenario where the user enables the permission through system settings and then returns to the app.
```text
1. Continue from Test Case 2
2. Go to Settings → Enable Camera
3. Return to app
4. Click "Request Camera"
5. EXPECTED: Granted immediately, callback runs ✅
```
--------------------------------
### Bloated ViewModel with Boilerplate (Bad)
Source: https://github.com/brewkits/grant/blob/main/docs/grant-core/ARCHITECTURE.md
This example illustrates a ViewModel with extensive boilerplate code for handling permission requests, including state management for rationale and settings.
```kotlin
// ❌ BAD: 40+ lines of boilerplate per grant
class CameraViewModel(private val manager: GrantManager) : ViewModel() {
private val _showRationale = MutableStateFlow(false)
val showRationale = _showRationale.asStateFlow()
private val _showSettings = MutableStateFlow(false)
val showSettings = _showSettings.asStateFlow()
private val _isRequesting = MutableStateFlow(false)
val isRequesting = _isRequesting.asStateFlow()
fun onCaptureClick() {
viewModelScope.launch {
_isRequesting.value = true
when (manager.checkStatus(AppGrant.CAMERA)) {
GrantStatus.GRANTED -> openCamera()
GrantStatus.NOT_DETERMINED -> requestGrant()
GrantStatus.DENIED -> _showRationale.value = true
GrantStatus.DENIED_ALWAYS -> _showSettings.value = true
}
_isRequesting.value = false
}
}
fun onRationaleConfirmed() {
viewModelScope.launch {
_showRationale.value = false
_isRequesting.value = true
val result = manager.request(AppGrant.CAMERA)
if (result == GrantStatus.GRANTED) {
openCamera()
} else if (result == GrantStatus.DENIED_ALWAYS) {
_showSettings.value = true
}
_isRequesting.value = false
}
}
fun onSettingsConfirmed() {
_showSettings.value = false
manager.openSettings()
}
fun onDismiss() {
_showRationale.value = false
_showSettings.value = false
}
// ... 40+ lines total
}
```
--------------------------------
### Documenting Manual Creation
Source: https://github.com/brewkits/grant/blob/main/docs/DEPENDENCY_MANAGEMENT.md
Document your choice to use manual creation for the Grant library in your project's code. This clarifies the dependency management strategy.
```kotlin
// Manual creation approach
// We don't use Koin to avoid version conflicts
private val grantManager = GrantFactory.create(context)
```