This guide explains how to build a React Native native module - PrismCapture - that wraps the body-scan capture experience only of PrismSDK for both iOS and Android behind one unified JS/TS API. The module 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 module.


Scope - What This Wraps / What It Doesn't

Wraps:

Does NOT wrap:


Unified Architecture

JS Layer
  └── NativeModules.PrismCapture   ← one JS surface
        ├── iOS: PrismCapture.swift / PrismCapture.m  (RCTEventEmitter)
        │         presents PrismSessionViewController (UIKit) or UIHostingController<PrismSessionView>
        │         FileUploader (PrismLink) for background S3 PUT
        └── Android: PrismCaptureModule.kt  (ReactContextBaseJavaModule)
                      launches PrismCaptureActivity (ComponentActivity + Compose)
                      PrismSessionView Composable wraps PrismSession controller
                      Ktor client for S3 PUT

New Architecture note: On RN New Architecture (Fabric / JSI), this module becomes a TurboModule. The JS surface - method names, event names, payload shapes - is identical. The bridge registration code (.m file on iOS, Package on Android) is the only mechanical change; swap RCT_EXTERN_MODULE for the codegen spec and register via ReactPackageTurboModuleManagerDelegate on iOS, and implement the generated NativePrismCaptureTurboModule spec on Android.


Module Contract

Methods

RN Method What it does Platform notes
startCaptureSession(options?) Presents the full-screen capture flow. Both platforms
dismissCaptureSession() Programmatically dismisses the capture UI. Both platforms
uploadCapture(filePath, presignedUrl) Uploads the zip at filePath via HTTP PUT to presignedUrl. Both; see platform differences
setupUploader() Resumes interrupted background uploads from a previous app session. iOS only. On Android this is a documented no-op.

Events

RN Event When it fires Payload
onCaptureComplete Zip is ready on disk. { archivePath: string }
onStatusChange Capture state machine transitions. { status: string, error?: string }
onDismiss Capture UI is dismissed (user or programmatic). {}
onUploadProgress Upload bytes transferred. { progress: number } (0.0–1.0)
onUploadComplete Upload finished (success or failure). { success: boolean }