Documentation

$appContext

The Android Context, available anywhere — including the places LocalContext.current cannot reach.

The problem it solves

Half of the Android API wants a Context. In Compose you get one from LocalContext.current, but that only works inside a composable — so the moment state logic moves into a store or a ViewModel, the usual answer is to thread a Context through every call, or to keep a static one and hope nothing leaks.

$appContext resolves in all of them:

$onMount {
  Session.load($appContext)
}

It is backed by a generated WhitehallApp : Application registered in the manifest, so it is alive for as long as the process is and cannot outlive anything.

It is the application context

This matters more than it sounds. An application context has no window, which rules out two things:

  • Starting an activity needs a flag. Without a task to launch into, Android requires FLAG_ACTIVITY_NEW_TASK.
  • UI-scoped things will not work. Dialogs and anything else that needs to attach to a window need an activity context, not this one.
fun openBrowser(url: String) {
  val tab = CustomTabsIntent.Builder().build()
  tab.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)   // required
  tab.launchUrl($appContext, Uri.parse(url))
}
Asking for a runtime permission needs an activity, so it is not something $appContext can do. That is what $permission is for — it finds the activity itself.

What it is good for

UseExample
Storage paths$appContext.filesDir, cacheDir
Preferences and databasesgetSharedPreferences, Room builders
Resources$appContext.resources, assets
System servicesgetSystemService(…)
Launching into a new taskCustom tabs, share sheets, external intents

In a store

Stores are where context-hungry code usually ends up, and they are exactly where LocalContext is unavailable:

@store object Session {
  var token: String? = null

  fun restore() {
    token = $appContext
      .getSharedPreferences("session", Context.MODE_PRIVATE)
      .getString("token", null)
  }
}

See Also