{"id":24443587,"url":"https://github.com/kdroidfilter/platform-tools","last_synced_at":"2025-04-12T21:27:33.163Z","repository":{"id":271452077,"uuid":"913485299","full_name":"kdroidFilter/Platform-Tools","owner":"kdroidFilter","description":"PlatformTools is a Kotlin Multiplatform library designed to provide platform-specific utilities and tools for managing operating systems, cache directories, and application versioning seamlessly across various platforms.","archived":false,"fork":false,"pushed_at":"2025-03-17T17:25:20.000Z","size":378,"stargazers_count":68,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T15:42:53.811Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://kdroidfilter.github.io/Platform-Tools/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kdroidFilter.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-07T19:20:57.000Z","updated_at":"2025-03-24T13:21:45.000Z","dependencies_parsed_at":"2025-01-07T21:22:02.570Z","dependency_job_id":"955ac403-f549-409d-be2d-b2a5d71efe51","html_url":"https://github.com/kdroidFilter/Platform-Tools","commit_stats":null,"previous_names":["kdroidfilter/platform-tools"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdroidFilter%2FPlatform-Tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdroidFilter%2FPlatform-Tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdroidFilter%2FPlatform-Tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdroidFilter%2FPlatform-Tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kdroidFilter","download_url":"https://codeload.github.com/kdroidFilter/Platform-Tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248633666,"owners_count":21136899,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-20T22:16:46.873Z","updated_at":"2025-04-12T21:27:33.154Z","avatar_url":"https://github.com/kdroidFilter.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PlatformTools\n\n**PlatformTools** is a Kotlin Multiplatform library designed to provide platform-specific utilities and tools for managing operating systems, application installation, and release fetching seamlessly across various platforms. The library is modular and divided into three main components: core, appmanager, and releasefetcher.\n\n---\n\n## 🌐 Core Module\n\nThe **Core** module of the KMP Platform Tools library provides utilities for detecting the underlying operating system and platform, enabling platform-specific logic in Kotlin Multiplatform (KMP) projects. Below, we will detail the functionality and demonstrate usage of the provided features.\n\n### ⚙️ Function: `getOperatingSystem`\n\nThe `getOperatingSystem` function determines the operating system on which the application is currently running. This function is expected to be implemented for each target platform in a Kotlin Multiplatform project.\n\n#### ℹ️ Note\n\nWhile this functionality may appear to contradict the principles of Kotlin Multiplatform by focusing on operating systems rather than platforms, it is important to note that `getOperatingSystem` returns the operating system itself and not the platform. For example, on JVM, JavaScript, or WASM targets, this function will return the operating system being used (e.g., `WINDOWS`, `MACOS`, `LINUX`) rather than distinguishing between different platforms or runtime environments.\n\n```kotlin\nfun getOperatingSystem(): OperatingSystem\n```\n\n### ⚙️ Function: `getPlatform`\n\nThe `getPlatform` function determines the specific platform or runtime environment on which the application is running. This is useful for small adjustments in shared code that depend on the platform.\n\n```kotlin\nfun getPlatform(): Platform\n```\n\n### 🔧 Example Usage\n\nHere is an example of how to use `getOperatingSystem` and `getPlatform` with separate `when` blocks for each:\n\n```kotlin\nwhen (val os = getOperatingSystem()) {\n    OperatingSystem.WINDOWS -\u003e println(\"Logic for Windows OS\")\n    OperatingSystem.MACOS -\u003e println(\"Logic for macOS\")\n    OperatingSystem.LINUX -\u003e println(\"Logic for Linux OS\")\n    OperatingSystem.ANDROID -\u003e println(\"Logic for Android OS\")\n    OperatingSystem.IOS -\u003e println(\"Logic for iOS OS\")\n    OperatingSystem.UNKNOWN -\u003e println(\"Logic for unknown OS\")\n}\n\nwhen (val platform = getPlatform()) {\n    Platform.ANDROID -\u003e println(\"Logic for Android platform\")\n    Platform.JVM -\u003e println(\"Logic for JVM platform\")\n    Platform.IOS_NATIVE -\u003e println(\"Logic for iOS Native platform\")\n    Platform.JS -\u003e println(\"Logic for JavaScript platform\")\n    Platform.WASM_JS -\u003e println(\"Logic for WebAssembly JS platform\")\n    Platform.LINUX_NATIVE -\u003e println(\"Logic for Linux Native platform\")\n    Platform.MAC_OS_NATIVE -\u003e println(\"Logic for macOS Native platform\")\n    Platform.WINDOWS_NATIVE -\u003e println(\"Logic for Windows Native platform\")\n}\n```\n\n### 🛠️ Android and JVM Only functions\n\n#### `getCacheDir`\n\n```kotlin\nval cacheDir: File = getCacheDir()\n```\n\n#### `getAppVersion`\n\n```kotlin\nval version = getAppVersion()\nprintln(\"App version: $version\")\n```\n\n### 🛠️ Android only functions\n\n#### `getAppVersion(packageName: String)`\n\nUnder Android, it's possible to take a package name as a parameter to get the version of another application.\n\n```kotlin\nval version = getAppVersion(\"com.sample.anotherApp\")\nprintln(\"App version: $version\")\n```\n\n---\n\nThis library is available on Maven Central. To include this library in your project, add the following dependency to your `build.gradle.kts`:\n\n```kotlin\nimplementation(\"io.github.kdroidfilter:platformtools.core:0.2.7\")\n```\n\n## 🌙 Dark Mode Detection Module\n\nThe **Dark Mode Detection** module of PlatformTools enhances theme management by introducing a reactive function, `isSystemInDarkMode`, that accurately detects system-wide dark mode settings across all supported platforms.\n\n### ⚙️ Function: `isSystemInDarkMode`\n\nThe `isSystemInDarkMode` function determines whether the system is currently in dark mode. Unlike `isSystemInDarkTheme`, which is not reactive on desktop platforms, `isSystemInDarkMode` provides real-time updates when the system's theme changes.\n\n#### 🔍 How It Works\n\n- On **desktop platforms (Windows, macOS, Linux)**, `isSystemInDarkMode` utilizes [JNA (Java Native Access)](https://github.com/java-native-access/jna) to detect and react to dark mode changes dynamically.\n- On **other platforms (Android, iOS, JVM, JavaScript, WebAssembly)**, `isSystemInDarkMode` falls back to `isSystemInDarkTheme`, ensuring compatibility across all targets.\n- This makes `isSystemInDarkMode` a **fully cross-platform and reactive solution** for detecting dark mode preferences in a Kotlin Multiplatform project.\n\n```kotlin\nfun isSystemInDarkMode(): Boolean\n```\n\n### 🔧 Example Usage\n\nHere is an example of using `isSystemInDarkMode` in a Jetpack Compose-based UI:\n\n```kotlin\nMaterialTheme(\n    colorScheme = if (isSystemInDarkMode()) darkColorScheme() else lightColorScheme()\n) {\n    // Your UI content\n}\n```\n\nThis allows automatic adaptation of the UI theme based on the system’s dark mode setting, ensuring a seamless user experience.\n\n### 🔗 Comparison with `isSystemInDarkTheme`\n\n| Function | Reactive | Desktop Support | Other Platforms |\n|----------|----------|----------------|----------------|\n| `isSystemInDarkTheme` | ❌ No | ❌ Not reactive | ✅ Yes |\n| `isSystemInDarkMode` | ✅ Yes | ✅ Fully supported (via JNA) | ✅ Yes (fallback to `isSystemInDarkTheme`) |\n\n---\n\n## 🎨 Adaptive Title Bar Support\n\nOn **Windows and macOS**, the application title bar does not automatically update based on dark mode settings. PlatformTools provides solutions for ensuring adaptive title bars.\n\n### 🖥️ Windows Support\n\nFor Windows, use the following function to enable an adaptive title bar:\n\n```kotlin\nfun Window.setWindowsAdaptiveTitleBar(dark: Boolean = isSystemInDarkMode())\n```\n\nExample usage in a Jetpack Compose for Desktop application:\n\n```kotlin\nWindow(\n    title = \"sample\",\n    state = rememberWindowState(width = 800.dp, height = 600.dp),\n    onCloseRequest = ::exitApplication,\n) {\n    window.minimumSize = Dimension(350, 600)\n    window.setWindowsAdaptiveTitleBar()\n    App()\n}\n```\n\n### 🍏 macOS Support\n\nOn macOS, enabling an adaptive title bar requires adding the following configuration in the `gradle.build.kts` file:\n\n```kotlin\ncompose.desktop {\n    application {\n        mainClass = \"MainKt\"\n        nativeDistributions {\n            macOS {\n                jvmArgs(\n                    \"-Dapple.awt.application.appearance=system\"\n                )\n            }\n        }\n    }\n}\n```\n\n### 🐧 Linux Support\n\nOn Linux, the title bar updates correctly with system-wide dark mode settings, so no additional configuration is required.\n\n---\n\n## 📦 Installation\n\nThis library is available on Maven Central. To include this module in your project, add the following dependency to your `build.gradle.kts`:\n\n```kotlin\nimplementation(\"io.github.kdroidfilter:platformtools.darkmodedetector:0.2.7\")\n```\n\n---\n\nWith `isSystemInDarkMode`, your Kotlin Multiplatform projects can now dynamically react to dark mode changes on all supported platforms. 🚀\n\n\n## 🔧 AppManager Module (Jvm \u0026 Android only)\n\nThe **AppManager** module of the KMP Platform Tools library provides utilities to manage application-level information and configurations across multiple platforms. Below, we will detail the functionality and demonstrate usage of the provided features.\n\n### 🔮 Overview\n\nThis module is designed to simplify retrieving and managing app-related metadata, such as package information and other common requirements. It supports platform-specific implementations while offering a unified API for shared code.\n\n### 💡 Interface: `AppInstaller`\n\nThe `AppInstaller` interface provides platform-specific functionality for managing application installation and uninstallation. For each platform, the required file format is as follows:\n\n- **Android**: APK file\n- **Windows**: MSI file\n- **Linux**: DEB file\n- **Mac**: PKG file\n#### Key Functions\n\n##### ⬇️ `installApp`\n\nInstalls an application from the specified file. This function requires appropriate permissions, such as the ability to install apps from unknown sources.\n\n```kotlin\nsuspend fun installApp(appFile: File, onResult: (success: Boolean, message: String?) -\u003e Unit)\n```\n\n**Parameters:**\n\n- `appFile`: The file to be installed (e.g., APK, MSI, PKG, or DEB).\n- `onResult`: A callback with the installation result. Provides:\n    - `success`: Indicates whether the installation succeeded.\n    - `message`: An optional message with additional context (e.g., error details).\n\n##### ⬆️ `uninstallApp`\n\nUninstalls an application using the provided package name or removes the current application. Currently, uninstallation functionality is only supported on Android.\n\n```kotlin\nsuspend fun uninstallApp(packageName: String, onResult: (success: Boolean, message: String?) -\u003e Unit)\n```\n\n```kotlin\nsuspend fun uninstallApp(onResult: (success: Boolean, message: String?) -\u003e Unit)\n```\n\n**Parameters:**\n\n- `packageName` (optional): The package name of the app to uninstall.\n- `onResult`: A callback with the uninstallation result. Provides:\n    - `success`: Indicates whether the uninstallation succeeded.\n    - `message`: An optional message with additional context.\n\n### 🎫 Factory Function: `getAppInstaller`\n\nRetrieves the platform-specific implementation of the `AppInstaller` interface.\n\n```kotlin\nfun getAppInstaller(): AppInstaller\n```\n\n**Example Usage:**\n\n```kotlin\nsuspend fun performAppInstallation(appFile: File) {\n    val appInstaller = getAppInstaller()\n    appInstaller.installApp(appFile) { success, message -\u003e\n        if (success) {\n            println(\"App installed successfully.\")\n        } else {\n            println(\"Failed to install app: $message\")\n        }\n    }\n}\n\nsuspend fun performAppUninstallation(packageName: String) {\n    val appInstaller = getAppInstaller()\n    appInstaller.uninstallApp(packageName) { success, message -\u003e\n        if (success) {\n            println(\"App uninstalled successfully.\")\n        } else {\n            println(\"Failed to uninstall app: $message\")\n        }\n    }\n}\n```\n\n---\n\n### 🔧 Windows-Specific Configuration\n\nThe `AppManager` module provides additional configuration options for managing Windows application installations:\n\n#### 🔒 Configuring Administrator Privileges\n\nYou can configure whether the application installation requires administrator privileges by modifying the `requireAdmin` property:\n\n```kotlin\nWindowsInstallerConfig.requireAdmin = false // Default is true\n```\n\n#### 🌐 Enabling Per-User Installation for Silent Updates\n\nFor enabling silent updates on Windows, it is recommended to configure `perUserInstall` as `true` in your build settings. Below is an example configuration for a Compose Desktop application:\n\n```kotlin\ncompose.desktop {\n  application {\n    mainClass = \"com.kdroid.sample.MainKt\"\n    nativeDistributions {\n      targetFormats(TargetFormat.Msi, TargetFormat.Deb, TargetFormat.Pkg)\n      windows {\n        perUserInstall = true\n      }\n    }\n  }\n}\n```\n\n---\n\n### 🎮 Android-Specific Function: `installAppSilently`\n\nThe `AppManager` module provides an additional function for Android devices running in Device Owner mode:\n\n#### 🔄 `installAppSilently`\n\nSilently installs an application from the specified file without requiring user interaction. This is particularly useful for enterprise environments or Device Owner mode.\n\n```kotlin\nsuspend fun installAppSilently(\n    appFile: File,\n    onResult: (success: Boolean, message: String?) -\u003e Unit\n)\n```\n\n## 📃 Additional Functions (Jvm \u0026 Android)\n\nThe `AppManager` module also provides the following utility functions for JVM and Android platforms:\n\n### 🔁 `restartApplication`\n\nRestarts the current application.\n\n```kotlin\nfun restartApplication()\n```\n\n### 🔄 `hasAppVersionChanged`\n\nChecks if the application version has changed since the last time it was opened. This is useful for detecting updates and performing related actions.\n\n```kotlin\nfun hasAppVersionChanged(): Boolean\n```\n\n### 🏠 `isFirstInstallation`\n\nChecks if it is the first installation of the app. This function can be used to perform setup actions or show onboarding screens.\n\n```kotlin\nfun isFirstInstallation(): Boolean\n```\n\n**Example Usage:**\n\n```kotlin\n  if (hasAppVersionChanged()) {\n      println(\"The application has been updated.\")\n      // Perform actions required after an update\n  } else {\n      println(\"No updates detected.\")\n  }\n\n  if (isFirstInstallation()) {\n    println(\"This is the first installation of the app.\")\n  // Perform any necessary setup actions here\n  } else {\n    println(\"The app has been installed before.\")\n  }\n```\n\nThis library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts` :\n\n```kotlin\nimplementation(\"io.github.kdroidfilter:platformtools.appmanager:0.2.7\")\n```\n\n---\n\n## 📥 Release Fetcher\n\n### 🔧 Overview\n\nThis module simplifies application downloads for the target platform and streamlines new release management.\n\n### 📦 `Downloader` Class\n\nThe `Downloader` class is a core component of the **Release Fetcher** module, designed to download application files from a given URL while tracking the download progress.\n\n### Main Functionality\n- **File Downloading:**\n    - The primary method, `downloadApp`, accepts a URL and downloads the associated file.\n    - It provides real-time updates on the download progress through a callback `onProgress`, reporting a percentage (from 0.0 to 100.0) and the local file when available.\n    - In case of an error, the progress percentage is set to `-1.0`.\n\n### 🔧 Technical Highlights\n- **Error Handling:** Comprehensive handling of network or file errors with detailed error logging.\n- **Optimized Downloading:** Uses a configurable buffer for efficient file writing.\n- **Coroutine Compatibility:** The method is `suspend`, making it ideal for use with Kotlin Coroutines.\n\n---\n\n### 🔧 Usage Example\n\nHere is how you can use the `Downloader` class:\n\n```kotlin\nfun main() = runBlocking {\n    val downloader = Downloader()\n    val url = \"https://example.com/app-release.apk\"\n\n    val success = downloader.downloadApp(url) { progress, file -\u003e\n        when {\n            progress == -1.0 -\u003e println(\"Error during download.\")\n            progress == 100.0 -\u003e println(\"Download complete: ${file?.absolutePath}\")\n            else -\u003e println(\"Progress: ${\"%.2f\".format(progress)}%\")\n        }\n    }\n\n    if (success) {\n        println(\"Download succeeded!\")\n    } else {\n        println(\"Download failed.\")\n    }\n}\n```\n\n### ⚖️ Configuration\n\nThe `ReleaseFetcherConfig` object allows modification of configuration settings for the downloader:\n\n- **Default Configuration:**\n    - `downloaderBufferSize`: `2 * 1024 * 1024` (2 MB)\n    - `clientTimeOut`: `HttpTimeoutConfig.INFINITE_TIMEOUT_MS`\n\n- **Example:** Modifying the default configuration:\n\n```kotlin\nReleaseFetcherConfig.downloaderBufferSize = 4 * 1024 * 1024 // Set buffer size to 4 MB\nReleaseFetcherConfig.clientTimeOut = 60_000 // Set client timeout to 60 seconds\n```\n\n### 🔧 `GitHubReleaseFetcher` Class\n\nThe `GitHubReleaseFetcher` class is a key utility in the **Release Fetcher** module that interacts with the GitHub API to fetch release information, check for updates, and retrieve platform-specific download links.\n\n### 🔧 Main Functionality\n\n- **Fetch Latest Release:**\n    - The `getLatestRelease` method uses the GitHub API to fetch the latest release for a given repository.\n    - Handles HTTP responses and parses the response body into a `Release` object.\n\n- **Check for Updates:**\n    - The `checkForUpdate` method compares the latest release version with the current application version.\n    - The comparison is made using the release name (`tag_name`) of the latest GitHub release and the application's version.\n    - If a newer version is available, it triggers a callback with the new version and changelog.\n\n- **Platform-Specific Download Links:**\n    - The `getDownloadLinkForPlatform` method provides the appropriate download link based on the current operating system.\n    - Supports Android (`.apk`), Windows (`.msi`), Linux (`.deb`), and macOS (`.dmg`).\n\n### 🔧 Important Note\n\n- The GitHub repository must contain at least one release.\n- The release name (`tag_name`) in the repository is critical as it is compared to the application's current version.\n- Ensure the GitHub repository is configured correctly to include meaningful release names and assets.\n\n---\n\n### 🔧 Usage Example\n\nHere is how you can use the `GitHubReleaseFetcher` class:\n\n```kotlin\nfun main() = runBlocking {\n    val fetcher = GitHubReleaseFetcher(owner = \"ownerName\", repo = \"repoName\")\n\n    // Fetch the latest release\n    val latestRelease = fetcher.getLatestRelease()\n    if (latestRelease != null) {\n        println(\"Latest version: ${latestRelease.tag_name}\")\n        println(\"Changelog: ${latestRelease.body}\")\n\n        // Get platform-specific download link\n        val downloadLink = fetcher.getDownloadLinkForPlatform(latestRelease)\n        if (downloadLink != null) {\n            println(\"Download here: $downloadLink\")\n        } else {\n            println(\"No suitable download link for the current platform.\")\n        }\n    } else {\n        println(\"Failed to fetch the latest release.\")\n    }\n\n    // Check for updates\n    fetcher.checkForUpdate { latestVersion, changelog -\u003e\n        println(\"Update available: $latestVersion\")\n        println(\"Changelog: $changelog\")\n    }\n}\n```\n\nThis library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts`:\n\n```kotlin\nimplementation(\"io.github.kdroidfilter:platformtools.releasefetcher:0.2.7\")\n```\n\n---\n\n## ⚖️ Permission Handler Module (Android Only)\n\nThe **Permission Handler** module provides a simple way to check and request permissions on Android. It simplifies the process, requiring only that you declare the necessary permissions in the Android manifest file.\n\n### 🔧 Main Features\n\n- **Permission Checking:**\n    - Functions like `hasInstallPermission()` allow you to verify if a specific permission is granted.\n\n- **Permission Requesting:**\n    - Functions like `requestInstallPermission(onGranted, onDenied)` allow you to request permissions, with callbacks for granted or denied states.\n\n- **Manifest Requirements:**\n    - Each function's documentation specifies the permissions required in the manifest file.\n\n### 🔧 Available Permissions and Functions\n\n1. **Install Permission:**\n- **Check:** `hasInstallPermission()`\n- **Request:** `requestInstallPermission(onGranted, onDenied)`\n- **Manifest Permission:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" /\u003e\n  ```\n\n2. **Notification Permission:**\n- **Check:** `hasNotificationPermission()`\n- **Request:** `requestNotificationPermission(onGranted, onDenied)`\n- **Manifest Permission:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" /\u003e\n  ```\n\n3. **Location Permissions:**\n- **Check:** `hasLocationPermission()`\n- **Request:** `requestLocationPermission(onGranted, onDenied)`\n- **Manifest Permissions:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" /\u003e\n  ```\n\n4. **Background Location Permission:**\n- **Check:** `hasBackgroundLocationPermission()`\n- **Request:** `requestBackgroundLocationPermission(onGranted, onDenied)` (requires location permissions to be granted first)\n- **Manifest Permission:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" /\u003e\n  ```\n\n5. **Bluetooth Permissions:**\n- **Check:** `hasBluetoothPermission()`\n- **Request:** `requestBluetoothPermission(onGranted, onDenied)`\n- **Manifest Permissions:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.BLUETOOTH\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\" android:required=\"false\" /\u003e\n  ```\n\n6. **Camera Permission:**\n- **Check:** `hasCameraPermission()`\n- **Request:** `requestCameraPermission(onGranted, onDenied)`\n- **Manifest Requirements:**\n  ```xml\n  \u003cuses-feature android:name=\"android.hardware.camera\" android:required=\"false\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.CAMERA\" /\u003e\n  ```\n\n7. **Audio Recording Permission:**\n- **Check:** `hasRecordAudioPermission()`\n- **Request:** `requestRecordAudioPermission(onGranted, onDenied)`\n- **Manifest Permission:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.RECORD_AUDIO\" /\u003e\n  ```\n\n8. **Overlay Permission:**\n- **Check:** `hasOverlayPermission()`\n- **Request:** `requestOverlayPermission(onGranted, onDenied)`\n- **Manifest Permission:**\n  ```xml\n  \u003cuses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" /\u003e\n  ```\n\n9. **Contacts Permissions:**\n- **Read Contacts:**\n    - **Check:** `hasReadContactsPermission()`\n    - **Request:** `requestReadContactsPermission(onGranted, onDenied)`\n    - **Manifest Permission:**\n      ```xml\n      \u003cuses-permission android:name=\"android.permission.READ_CONTACTS\" /\u003e\n      ```\n- **Write Contacts:**\n    - **Check:** `hasWriteContactsPermission()`\n    - **Request:** `requestWriteContactsPermission(onGranted, onDenied)`\n    - **Manifest Permission:**\n      ```xml\n      \u003cuses-permission android:name=\"android.permission.WRITE_CONTACTS\" /\u003e\n      ```\n\n10. **Read External Storage Permission (Android 13 and Above):**\n- **Check:** `hasReadExternalStoragePermission(mediaTypes: Set\u003cMediaType\u003e = emptySet())`\n- **Request:** `requestReadExternalStoragePermission(mediaTypes: Set\u003cMediaType\u003e = emptySet(), onGranted, onDenied)`\n- **MediaType Enum:**\n  ```kotlin\n  enum class MediaType {\n      IMAGES,\n      VIDEO,\n      AUDIO\n  }\n  ```\n- **Manifest Permission:**\n  ```xml\n  \u003c!-- Example permissions depending on media types --\u003e\n  \u003cuses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.READ_MEDIA_VIDEO\" /\u003e\n  \u003cuses-permission android:name=\"android.permission.READ_MEDIA_AUDIO\" /\u003e\n  ```\n\n### 🔧 Usage Example\n\nHere is how to use the module for requesting and handling permissions:\n\n```kotlin\nfun checkAndRequestInstallPermission() {\n    if (hasInstallPermission()) {\n        println(\"Install permission already granted.\")\n    } else {\n        requestInstallPermission(\n            onGranted = {\n                println(\"Install permission granted.\")\n            },\n            onDenied = {\n                println(\"Install permission denied.\")\n            }\n        )\n    }\n}\n\n```\n\n### 🔹 Special Notes for External Storage Permissions\n\n- **Requests read external storage permission for the application.**\n- **Behavior Based on Android Version:**\n    - For Android versions below 13, it requests `READ_EXTERNAL_STORAGE`.\n      ```xml\n      \u003cuses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" /\u003e\n      ```\n    - For Android 13 and above, it requests specific media permissions based on the provided media types.\n      ```xml\n      \u003cuses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\" /\u003e\n      \u003cuses-permission android:name=\"android.permission.READ_MEDIA_VIDEO\" /\u003e\n      \u003cuses-permission android:name=\"android.permission.READ_MEDIA_AUDIO\" /\u003e\n      ```\n\n### 🔧 Usage Example\n\nHere is how you can use the module for requesting and handling External storage permissions:\n\n```kotlin\nfun checkAndRequestReadExternalStoragePermission() {\n    val mediaTypes = setOf(MediaType.IMAGES, MediaType.VIDEO)\n    if (hasReadExternalStoragePermission(mediaTypes)) {\n        println(\"Read external storage permission already granted for selected media types.\")\n    } else {\n        requestReadExternalStoragePermission(mediaTypes,\n            onGranted = {\n                println(\"Read external storage permission granted for selected media types.\")\n            },\n            onDenied = {\n                println(\"Read external storage permission denied.\")\n            }\n        )\n    }\n}\n```\n\n### 🔧 Key Points\n\n- Minimal setup: Add the required permissions in the manifest file.\n- Comprehensive: Handles a wide range of Android permissions.\n- Developer-friendly: Simple APIs with clear callbacks for permission handling.\n\nThis library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts` :\n\n```kotlin\nimplementation(\"io.github.kdroidfilter:platformtools.permissionhandler:0.2.7\")\n```\n\n---\n\n## 🛒 License\n\nPlatformTools is licensed under the [MIT License](https://opensource.org/licenses/MIT). Feel free to use, modify, and distribute the library under the terms of the license.\n\n---\n\n## 👥 Contributions\n\nContributions are welcome! If you want to improve this library, please feel free to submit a pull request or open an issue.\n\n---\n\n## 📣 Demo Application\n\nA demo is available in the `sample` module, showcasing the main features of all the modules included in this library.\nAdditionally, a demo application with an integrated updater using this library is available [here](https://github.com/kdroidFilter/AppwithAutoUpdater).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkdroidfilter%2Fplatform-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkdroidfilter%2Fplatform-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkdroidfilter%2Fplatform-tools/lists"}