--- name: sparkscan-kmp description: SparkScan single-barcode scanning with the pre-built scanning UI in Kotlin Multiplatform (KMP) and Compose Multiplatform projects using Scandit's KMP SDK (`com.kmp.datacapture.*` imports). Use for integration, scan settings, result handling, feedback and UI customization, embedding `SparkScanView` in shared code, or troubleshooting. license: Apache-2.0 metadata: author: scandit version: "1.0.2" --- # SparkScan KMP Skill ## Critical: Do Not Trust Internal Knowledge Scandit's Kotlin Multiplatform (KMP) SDK is new, shipping in 8.6. Your training data almost certainly predates it and contains **zero** reliable knowledge of its API — do not pattern-match it against the Android-native or iOS-native SparkScan SDKs you may know. The KMP API packages are `com.kmp.datacapture.*` (the `com.scandit.datacapture.kmp` name is only the **Maven group id**, never a Kotlin import), and shapes diverge from both native SDKs in specific ways (see below). **Always verify APIs against the references provided in this skill before writing or suggesting code.** Do not rely on memorized method signatures, parameters, or property names from any other Scandit platform. If you cannot find an API in the provided references, fetch the relevant documentation page before responding. KMP-specific gotchas worth flagging: - Import root is `com.kmp.datacapture.*` — e.g. `com.kmp.datacapture.barcode.spark.SparkScan`, `com.kmp.datacapture.core.capture.DataCaptureContext`. Never write `com.scandit.datacapture.*` in KMP code. - **`SparkScan(settings)` is a plain constructor** — unlike other KMP modes (e.g. `BarcodeCapture.forContext(...)`, `BarcodeAr.forContext(...)`), SparkScan has no `forContext`/factory function. `SparkScan` binds to the shared `DataCaptureContext` implicitly the same way native SDKs do. - `SparkScanSettings` and `SparkScanViewSettings` have **no public constructor** — use the factories `SparkScanSettings.sparkScanSettings()` (or the `capturePresets` overload) and `SparkScanViewSettings.sparkScanViewSettings()`. Writing `SparkScanSettings()` is a compile error. - `SparkScanView` is **platform-divergent by construction signature**: Android's constructor is `SparkScanView(context: android.content.Context, dataCaptureContext: DataCaptureContext, sparkScan: SparkScan, settings: SparkScanViewSettings)`; iOS's is `SparkScanView(dataCaptureContext: DataCaptureContext, sparkScan: SparkScan, settings: SparkScanViewSettings)` — **no `Context` parameter on iOS**. Shared `commonMain` code cannot construct a `SparkScanView` directly; each platform host constructs it and hands it to shared code (e.g. the screen model) to wire the feedback delegate and lifecycle. - To embed the native view: Android uses `view.toAndroidView(): View` (import `com.kmp.datacapture.barcode.ui.toAndroidView`) inside a Compose `AndroidView` factory or a plain `ViewGroup`; iOS uses `view.toUIView(): UIView` inside a `UIViewRepresentable`. These are the *only* supported bridges — never call `toNative()` from application code (it's public only because Kotlin's `internal` cannot span the multi-module KMP SDK). - `SparkScanListener` has exactly two methods to implement: `onBarcodeScanned(sparkScan, session, frameData)` and `onSessionUpdated(sparkScan, session, frameData)` — both required (no default bodies), and `frameData: FrameData` is **non-null** on KMP (Android-native's `data: FrameData?` is nullable). Read the scanned barcode from `session.newlyRecognizedBarcode`. - `SparkScanFeedbackDelegate.getFeedbackForBarcode(barcode)` returns `SparkScanBarcodeFeedback?`. Build success/error feedback with `SparkScanBarcodeSuccessFeedback(...)` / `SparkScanBarcodeErrorFeedback(errorMessage, resumeCapturingDelay, ...)` — the error constructor's message parameter is named **`errorMessage`** (not `message`), and `resumeCapturingDelay` is a plain **`Long` in milliseconds** (not `TimeInterval` like Android-native, not a `.NET TimeSpan`). `feedbackDelegate` is a property on the platform `SparkScanView` instance, not on `SparkScanSettings`. - **There is no `SparkScanScanningMode.Target` on KMP.** Native Android's combined "Target scanning mode" class is not bound. Instead, `SparkScanViewSettings` exposes two independent properties: `scanningBehavior: SparkScanScanningBehavior` (`SINGLE` / `CONTINUOUS`) and `previewBehavior: SparkScanPreviewBehavior` (`DEFAULT` / `PERSISTENT`). Correspondingly, `SparkScanViewUiListener` has no `onScanningModeChange` callback — don't invent one. - UI-chrome toggles (`triggerButtonVisible`, `torchControlVisible`, `toolbarBackgroundColor`, `triggerButtonCollapsedColor`, etc.) are `var` properties on the constructed **`SparkScanView` instance itself**, not on `SparkScanViewSettings` — `SparkScanViewSettings` only configures construction-time behavior (zoom, timeouts, sound/haptic, hardware trigger, toast, mini-preview size, camera position, periscope mode, scanning/preview behavior). The Compose Multiplatform `SparkScanView` composable exposes the view-level toggles directly as parameters since it owns view construction. - Reactive alternative to implementing `SparkScanListener`: `sparkScan.recognizedBarcodes: Flow` and `sparkScan.sessionUpdates: Flow` (from the same `com.kmp.datacapture.barcode.spark` package). Collecting either Flow registers a listener; cancelling the collection removes it. Each collector gets an independent listener — share a single upstream listener with `.shareIn(scope, SharingStarted.WhileSubscribed())` if multiple coroutines need the same stream. - Compose Multiplatform: `@Composable fun SparkScanView(...)` (from the `barcode-compose` module) starts scanning as the final step on entering composition and stops it on dispose — **do not add manual `onResume()`/`onPause()`/`startScanning()`/`stopScanning()` calls** when using this composable; it manages the whole lifecycle. Use `rememberSparkScan(context, settings)` to build the mode (defaults `context` to `DataCaptureContext.sharedInstance`). - Teardown when NOT using the Compose composable (i.e. the manual `SparkScanView` pattern): `sparkScan.removeListener(this)` then `dataCaptureContext.removeMode(sparkScan)` — in that order, on screen/model disposal. This matches the canonical sample's `dispose()` exactly; there is no separate `onDestroy()`. - The license key placeholder is exactly `-- ENTER YOUR SCANDIT LICENSE KEY HERE --` (matches the canonical sample). Use this exact string, not a different placeholder. - On iOS, distribution is via Swift Package Manager (`Scandit/datacapture-kmp-spm`, an umbrella XCFramework) — an app links exactly **one** Kotlin framework product from that package; pick the variant that bundles the barcode module (needed for SparkScan). The native Scandit XCFrameworks (core, barcode) resolve transitively — do not add them as separate SPM dependencies. - Request the `CAMERA` permission at runtime on Android before starting scanning (the manifest declaration alone is not sufficient). On iOS, `NSCameraUsageDescription` in `Info.plist` triggers the OS permission prompt automatically on first camera use. ## Intent Routing Based on the user's request, load the appropriate reference file before responding: - **Integrating SparkScan from scratch, configuring symbologies, customizing feedback, handling scan results, wiring the Compose Multiplatform view, customizing the SparkScan UI, or tearing down the integration** (e.g. "add SparkScan to my KMP app", "set up barcode scanning in my shared module", "how do I use SparkScan with Compose Multiplatform", "reject a barcode and show an error", "enable continuous scanning", "hide the trigger button") → read [`references/integration.md`](references/integration.md) and follow the instructions there. ## API Usage Policy Only use APIs that are explicitly documented in the Scandit references below. Do not invent or guess method signatures, parameters, or property names — and never carry over a signature from the Android-native or iOS-native SDKs without verifying it also holds for KMP. If unsure whether an API exists or how it is called — or if a compile error occurs — fetch the relevant reference page before responding. Do not tell the user to check the docs themselves. After answering, always include the relevant link so the user can explore further. **Never construct or guess documentation URLs.** When you need a specific class or property's API page: 1. First check whether the page you already fetched (e.g. the Advanced Configurations page) contains a direct hyperlink to it — topic pages link directly to relevant API symbols. Always request links alongside content in your fetch prompt. 2. If no direct link was found, fetch the API index (see **Full API reference** in the table below), extract the actual link from it, and follow that. URL structures can vary (e.g. `api/ui/` subdirectory) and guessing will lead to 404s. ## Licence key Scanning needs a Scandit licence key. For this skill the licence product is `native` and the licence platforms are `ios` and `android`. Work through these in order — never block the user on MCP: 1. **The Scandit MCP server is connected** — call `ensure_scanner_setup` with product `native` and platforms `ios` and `android`, then run the command `get_license_env_command` returns, which writes the key into the project's `.env`. Show at most a masked preview in chat; never print a full key. 2. **It is not connected** — ask the user once to connect the Scandit server in the plugin's Edit dialog, Connections tab, then continue from step 1. Authentication is browser-based, so it is **not supported headless or in CI**. The server provisions **trial** keys only; it never creates, revokes, or modifies production licences. 3. **The user declines** — they generate a key themselves at (no account yet: ) and paste it in. **Then put the key into the code** in place of the placeholder; a key in `.env` does not reach the app by itself. Kotlin Multiplatform does not load `.env` by itself, so use the simplest route below. The simplest route on any platform: read `.env` and put the key into the licence-key call directly, still showing only a masked preview in chat. ## References Direct users to the right resource based on their question: | Topic | Resource | |---|---| | Get Started | [Intro](https://docs.scandit.com/sdks/kmp/sparkscan/intro/) · [Get Started](https://docs.scandit.com/sdks/kmp/sparkscan/get-started/) | | Advanced topics (custom feedback, scanning behavior, UI customization) | [`references/integration.md`](references/integration.md) | | Compose Multiplatform | [Core Concepts](https://docs.scandit.com/sdks/kmp/core-concepts/) | | Core concepts (context, camera, views) | [Core Concepts](https://docs.scandit.com/sdks/kmp/core-concepts/) |