SharedPreferencesGrantStore

A GrantStore that persists permission request history across process death.

On Android, the only OS signal that survives a restart is shouldShowRequestPermissionRationale() — and that signal is false for both a brand-new permission and one the user has permanently denied. To tell those two apart after the app's process has been killed, Grant needs to remember that it has asked for the permission at least once. InMemoryGrantStore keeps that flag in RAM, so it is lost on process death and the permanent-denial case is misreported as NOT_DETERMINED — the request then silently no-ops (Issue #55).

This store writes the "has been requested" flags to a private SharedPreferences file (grant_request_history) so they survive restart. Only the request-history flags are persisted; the per-session status cache stays in memory, because the OS remains the source of truth for the current status.

Restored data is discarded

History that arrives from another installation is worse than no history: Grant would believe it had already asked for permissions the OS considers untouched, and show a settings guide where it should show the system dialog.

Until 2.4.1 this was prevented with android:fullBackupContent / android:dataExtractionRules on the library manifest. That was removed: a library cannot set <application> attributes without colliding with apps that declare their own backup rules, and an app resolving that collision with tools:replace silently dropped the exclusion — so the protection was never dependable.

The store now defends itself, independently of any app's manifest. The history is stamped with the app's firstInstallTime, and is cleared whenever the stamp does not match the current installation, or is missing entirely (data written before this mechanism, which cannot be proven local). firstInstallTime is readable without any permission and is stable across app updateslastUpdateTime is the value that moves — so ordinary updates and process death keep their history, while a cloud-backup restore, device transfer, or reinstall starts clean.

This is the default store on Android (see GrantFactory.create and the Koin grantPlatformModule). Apps that prefer the in-memory behavior can pass InMemoryGrantStore explicitly.

Constructors

Link copied to clipboard
constructor(context: Context)

Functions

Link copied to clipboard
open override fun clear()

Clears all session-cached data.

open override fun clear(grant: AppGrant)

Clears session-cached data for a specific permission.

Link copied to clipboard
open override fun getStatus(grant: AppGrant): GrantStatus?

Retrieves the session-cached status for a permission.

Link copied to clipboard

Extension for getting the status of any GrantPermission.

Link copied to clipboard
open override fun isRawPermissionRequested(identifier: String): Boolean

Checks if a custom RawPermission has been requested.

Link copied to clipboard
open override fun isRequestedBefore(grant: AppGrant): Boolean

Checks if a permission has been requested during this app session or install.

Link copied to clipboard

Extension for checking if any GrantPermission has been requested before.

Link copied to clipboard
open override fun markRawPermissionRequested(identifier: String)

Marks a custom RawPermission as having been requested.

Link copied to clipboard
open override fun setRequested(grant: AppGrant)

Marks a permission as having been requested.

Link copied to clipboard

Extension for marking any GrantPermission as requested.

Link copied to clipboard
open override fun setStatus(grant: AppGrant, status: GrantStatus)

Caches the status for a permission in the current session.

Link copied to clipboard
fun warmUp()

Forces this store's disk read and PackageManager lookup to happen now, on the calling thread, so the first real read does not pay for them.