This guide explains how to build a Flutter plugin - prism_capture - that wraps the body-scan capture experience only of PrismSDK for both iOS and Android behind one unified Dart API. The plugin presents the full-screen capture UX, receives the output zip, and performs a direct PUT upload to an S3 presigned URL that your backend obtains from the Prism API. No Prism API credentials are needed on the device; all REST calls (user management, scan records, measurements, health reports) remain on the backend and are out of scope for this plugin.


Scope - What This Wraps / What It Doesn't

Wraps:

Does NOT wrap:


Unified Architecture

Dart Layer
  └── PrismCapture (lib/prism_capture.dart)
        ├── MethodChannel  "tech.prismlabs.prism_capture/methods"   ← commands
        └── EventChannel   "tech.prismlabs.prism_capture/events"    ← typed event stream
              ├── iOS: PrismCapturePlugin.swift
              │         FlutterPlugin + FlutterStreamHandler
              │         presents PrismSessionViewController via UIHostingController
              │         FileUploader (PrismLink) for background S3 PUT
              └── Android: PrismCapturePlugin.kt
                            FlutterPlugin + MethodCallHandler + StreamHandler + ActivityAware
                            launches PrismCaptureActivity (ComponentActivity + Compose)
                            PrismSessionView Composable wraps PrismSession controller
                            Ktor client for S3 PUT

The plugin uses the present native full-screen via method channel + stream events back model: startCaptureSession instructs the native side to present a new full-screen VC (iOS) or launch a new Activity (Android); the Future returned by startCaptureSession completes when the command is accepted, not when the UI finishes presenting. Events - status changes, archive delivery, upload progress - flow back through the EventChannel stream as typed maps. This gives the capture surface full access to camera hardware and native animations without embedding a PlatformView.

PlatformView alternative: If your app needs the capture surface inline (e.g., inside a tab layout), you can host it as a UiKitView (iOS) or AndroidView (Android) instead. That requires the native plugin class to register a FlutterPlatformViewFactory and is more complex to size and lifecycle-manage. The method-channel + full-screen model is strongly preferred for capture.


Plugin Contract

Methods

Dart Method What it does Platform notes
startCaptureSession({CaptureOptions? options}) Presents the full-screen capture flow. Returns Future<void> when the command is accepted (not when the UI finishes presenting). Both platforms
dismissCaptureSession() Programmatically dismisses the capture UI. Returns Future<void>. Both platforms
uploadCapture(String filePath, String presignedUrl) Uploads the zip at filePath via HTTP PUT to presignedUrl. Returns Future<void>. Both; see platform differences
setupUploader() Resumes interrupted background uploads from a previous app session. Returns Future<void>. iOS only. On Android this is a documented no-op.

Events