-
Notifications
You must be signed in to change notification settings - Fork 2
share README
Cross-platform native share sheet for Kotlin Multiplatform — one API, every target.
cmp-share exposes a single suspending Share object that invokes the native share sheet
on Android/iOS/macOS, falls back to navigator.share on JS/wasmJs, and provides a JVM
best-effort implementation (opens system file manager / mailto). Share text, URLs, images,
arbitrary files, or a mixed multi-payload — all through one unified API.
Experimental API: annotated with
@ExperimentalShareApi. Opt in with@OptIn(ExperimentalShareApi::class)or the compiler flag below.
| Platform | Real impl | onUnsupported |
Notes |
|---|---|---|---|
| Android | ✅ | — | ACTION_SEND / ACTION_SEND_MULTIPLE via Chooser |
| iOS | ✅ | — | UIActivityViewController |
| macOS | ✅ | — | NSSharingServicePicker |
| JVM | ✅ best-effort | — | Desktop.open() / mailto for URLs; file-manager for files |
| JS | ✅ | — |
navigator.share() (HTTPS + user gesture required) |
| wasmJs | ✅ | — |
navigator.share() (same constraints as JS) |
| tvOS | ⚠ UnsupportedPlatform | ✅ | tvOS lacks UIActivityViewController; K/N bindings also omit UIPasteboard (v3.3.0 limitation) |
| watchOS | ⚠ UnsupportedPlatform | ✅ | No share-sheet surface; handoff-to-iPhone via WCSession is v0.3 candidate |
| Linux | ✅ URL/file via xdg-open | ✅ | Requires xdg-utils. Text/image/multi onUnsupported |
| mingw | ✅ URL/file via cmd /c start
|
✅ | Default Windows handler resolution. Text/image/multi onUnsupported |
| wasmWasi | ⛔ out-of-scope | — | No DOM, no clipboard, no UI gesture surface — server-side WASM only |
v0.2 update (v3.3.0): tier-3 targets are no longer hard-excluded. Linux + mingw ship real URL-share implementations; tvOS/watchOS ship documented
UnsupportedPlatformfallbacks (the sameonUnsupported { }hook callers already use on JS/wasmJs is honored).wasmWasistays out-of-scope — the constraint is genuine, not effort-based.
@OptIn(ExperimentalShareApi::class)
suspend fun onShareClicked() {
val result = Share.text("Check out KMP Toolkit!")
when (result) {
is ShareResult.Completed -> println("Shared successfully")
is ShareResult.Cancelled -> println("User cancelled")
is ShareResult.Failed -> println("Error: ${result.cause}")
}
}@ExperimentalShareApi
expect object Share {
suspend fun share(
payload: SharePayload,
options: ShareOptions = ShareOptions()
): ShareResult
}suspend fun Share.text(content: String, options: ShareOptions = ShareOptions()): ShareResult
suspend fun Share.url(href: String, options: ShareOptions = ShareOptions()): ShareResult
suspend fun Share.image(
bytes: ByteArray,
mimeType: String,
filename: String? = null,
options: ShareOptions = ShareOptions()
): ShareResult
suspend fun Share.file(
bytes: ByteArray,
mimeType: String,
filename: String,
options: ShareOptions = ShareOptions()
): ShareResult
suspend fun Share.multi(
payloads: List<SharePayload>,
options: ShareOptions = ShareOptions()
): ShareResultsealed class SharePayload {
data class Text(val content: String) : SharePayload()
data class Url(val href: String) : SharePayload()
data class Image(val bytes: ByteArray, val mimeType: String, val filename: String?) : SharePayload()
data class File(val bytes: ByteArray, val mimeType: String, val filename: String) : SharePayload()
data class Multi(val payloads: List<SharePayload>) : SharePayload()
}data class ShareOptions(
val chooserTitle: String? = null, // Android only — Chooser dialog title
val excludedActivities: List<String> = emptyList(), // Android only — package names to exclude
val presentingController: Any? = null // iOS/macOS — UIViewController / NSViewController
)sealed class ShareResult {
object Completed : ShareResult()
object Cancelled : ShareResult()
data class Failed(val cause: ShareError) : ShareResult()
}sealed class ShareError {
object UnsupportedPlatform : ShareError()
object NoHandler : ShareError()
object UserGestureMissing : ShareError() // JS/wasmJs only
data class Unknown(val message: String) : ShareError()
}-
JS / wasmJs:
navigator.share()requires HTTPS and a user gesture — call from a click handler, not a coroutine launched inLaunchedEffectwithout user interaction. - JVM: best-effort — opens the default handler registered by the OS; file-type support depends on installed applications.
-
Multi-payload on iOS: wraps items in a single
UIActivityViewControlleractivity items array.
- SETUP.md — Integration steps
-
CLAUDE_AI_SETUP.md — AI-assisted setup with
/sync-share
** Partials**
App Intents
Bubble
Clipboard
Cookbook
- Clipboard Copy Text
- Clipboard Read Text
- Consumer Anon Key Setup
- Crashlytics Attribution Per Library
- Ifonline Block
- Index
- Index
- Index
- Index
- Open Url Compose
- Pick And Share Image
- React To Offline
- Register Firebase Hooks
- Share Pdf Android
- Share Text
- Wifi Vs Cellular
Firebase Analytics
In App Update
Intent Launcher
Inter App Comms
Modules
- Cmp App Intents
- Cmp App Intents Compose
- Cmp Bubble
- Cmp Clipboard
- Cmp Deep Link
- Cmp Firebase Analytics
- Cmp In App Update
- Cmp Intent Launcher
- Cmp Intent Launcher Compose
- Cmp Library
- Cmp Network Monitor
- Cmp Network Monitor Compose
- Cmp Observe
- Cmp Observe Koin
- Cmp Open Url
- Cmp Pdf Generator
- Cmp Product Tickets
- Cmp Remote Config
- Cmp Share
- Cmp Share Compose
- Cmp Toast
Network Monitor
Open Url
Pdf Generator
Remote Config
Share
Toast
User Tickets
General