Skip to content

Repository files navigation

Tauri Plugin Camera

A Tauri v2 plugin that provides a unified JavaScript API for camera access across Android, iOS and desktop. It supports live preview, photo capture, video recording (with audio), camera controls (front/back, flash, zoom), saving to the photo gallery, and camera permission management.

Platform Supported
Android ✓
iOS ✓
macOS ✓ (via getUserMedia)
Windows ✓ (via getUserMedia)
Linux ✓ (via getUserMedia)

On desktop the camera is driven by the webview through navigator.mediaDevices.getUserMedia plus <video>/<canvas>. On mobile it uses a native preview (CameraX on Android, AVFoundation on iOS) for full control and quality.

Install

Add the Rust crate to src-tauri/Cargo.toml:

[dependencies]
tauri-plugin-camera-kessdev = "0.1.0"
# or from a git/path source:
# tauri-plugin-camera-kessdev = { path = "../tauri-plugin-camera" }

Add the JavaScript bindings:

npm add tauri-plugin-camera-kessdev
# pnpm add tauri-plugin-camera-kessdev
# yarn add tauri-plugin-camera-kessdev

Register

In src-tauri/src/lib.rs:

pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_camera_kessdev::init())
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Permissions

Capabilities (Tauri v2)

Add the default permission set to src-tauri/capabilities/default.json:

{
  "permissions": [
    "core:default",
    "camera:default"
  ]
}

To allow only specific commands, use the granular permissions instead of camera:default (e.g. camera:allow-capture, camera:allow-start-recording, camera:allow-check-permissions, …). The full list is generated under permissions/autogenerated/commands/ as allow-<command> / deny-<command>.

Android

The plugin's AndroidManifest.xml declares android.permission.CAMERA and android.permission.RECORD_AUDIO (for video audio). The Kotlin plugin registers them through the @TauriPlugin annotation, so checkPermissions / requestPermissions work out of the box. No further manifest edits are required.

iOS

Add the following usage descriptions to the app Info.plist (src-tauri/Info.plist):

<key>NSCameraUsageDescription</key>
<string>This app uses the camera to capture photos and videos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app uses the microphone to record audio in videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app saves captured photos to your photo library.</string>

NSMicrophoneUsageDescription is only required if you use video recording, NSPhotoLibraryAddUsageDescription only if you use saveToGallery.

Desktop

Desktop uses the browser's getUserMedia. The plugin installs a webview permission handler on Windows (WebView2 PermissionRequested) and Linux (webkitgtk permission-request) that allows camera and microphone, so startPreview() / requestPermissions() work without extra configuration. The webview asks the plugin, and the real gate is the operating system:

  • Windows: Settings → Privacy & security → Camera → turn on camera access and "Let desktop apps access your camera".
  • Linux: the desktop portal (e.g. xdg-desktop-portal) governs camera access.

On macOS, WKWebView additionally requires NSCameraUsageDescription and NSMicrophoneUsageDescription in the Info.plist (the same keys above).

Usage

import {
  startPreview,
  stopPreview,
  capture,
  startRecording,
  stopRecording,
  flipCamera,
  setFlash,
  setZoom,
  saveToGallery,
  checkPermissions,
  requestPermissions,
  getPreviewStream,
  convertFileSrc
} from 'tauri-plugin-camera-kessdev'

Preview

// windowed: true keeps the webview transparent so your UI renders over the camera.
await startPreview({ camera: 'back', windowed: true })

// Desktop: attach the stream to a <video> element.
const stream = await getPreviewStream()
if (stream) videoEl.srcObject = stream

await stopPreview()

Photo capture

const photo = await capture({ flash: 'auto' })
// photo: { path, width, height, orientation, format, thumbnail? } (mobile)
//        { dataUrl, width, height, orientation, format }       (desktop)

// Mobile: display the captured file.
imageEl.src = convertFileSrc(photo.path)

Video recording (with audio)

await startRecording()
// ... user records ...
const video = await stopRecording()
// video: { path, duration } (mobile) | { duration, blob, url } (desktop)

Camera controls

await flipCamera()
await setFlash('on') // 'on' | 'off' | 'auto'
await setZoom(2.0)

Gallery

await saveToGallery(photo.path) // mobile only

Permissions

const state = await checkPermissions()   // 'granted' | 'denied' | 'prompt'
await requestPermissions()

Image return pattern

  • Mobile writes the capture to a temporary file in native code and returns its path. Use convertFileSrc(path) to display it, read it with the fs plugin, or upload it with fetch/the http plugin.
  • Desktop returns a base64 data URL and a Blob (no native file system write).

This keeps large image payloads out of the JSON IPC bridge (mobile) while staying idiomatic on the web (desktop).

Testing

The plugin ships unit tests for every layer. They are pure logic tests — no camera hardware, emulator or device is required.

Layer Test file Command Run from Requires
Rust src/models.rs (inline tests) cargo test plugin root Rust + Cargo
JS guest-js/index.test.ts npm test plugin root Node.js 18+ + npm
Android android/src/test/java/CameraPluginTest.kt gradle test android/ (or generated app) JDK 17+, Android SDK, Gradle
iOS ios/Tests/PluginTests/PluginTests.swift swift test ios/ macOS + Xcode

Prerequisites

Rust

  • Rust (stable toolchain).
  • Optional — to verify the crate compiles for mobile:
    rustup target add aarch64-linux-android

JavaScript

  • Node.js 18+ and npm (or pnpm/yarn).

Android (Kotlin)

  • JDK 17 or newer.
  • Android SDK with platforms/android-36 and build-tools.
  • Gradle (or the generated project's wrapper).

iOS (Swift)

  • macOS with Xcode. iOS tests cannot run on Linux or Windows.

Rust

cd tauri-plugin-camera
cargo test

Covers model (de)serialization and the error types. To also verify the crate compiles against the Android target:

cargo check --target aarch64-linux-android

JavaScript

cd tauri-plugin-camera
npm install
npm test

npm test runs Vitest; the tests cover the API signatures and the mobile/desktop dispatch. To validate types and generate the bindings:

npm run build

Android (Kotlin)

The JUnit tests cover flash-mode mapping, zoom clamping and camera direction.

Running them requires the full Tauri Android pipeline. The plugin's android/ module is a Gradle library built as part of the generated app project, and the Gradle config (tauri.settings.gradle) is only generated during a Tauri Android build — not by tauri android init (that only lays down the base project). The sequence is:

cd tauri-plugin-camera/examples/tauri-app
npm install
npm run tauri android init
npm run tauri android build     # generates tauri.settings.gradle and compiles
cd src-tauri/gen/android
./gradlew test

Requires JDK 17+, Android SDK + NDK, and platforms/android-36 — or set compileSdk = 35 in android/build.gradle.kts if your SDK only goes up to 35. tauri android build builds a release APK (needs a signing key); tauri android dev builds a debug APK but requires a connected device/emulator. Either one generates tauri.settings.gradle, after which ./gradlew test works.

iOS (Swift)

The XCTest tests cover decoding of the command options. Testing requires full Xcode — Command Line Tools is not enough, because the plugin imports UIKit, AVFoundation and Photos, which need the iOS SDK and the Simulator.

The plugin is iOS-only, so it cannot be built with swift test (that targets macOS, where UIKit is unavailable, and the Tauri package referenced by ios/Package.swift is only created by the Tauri iOS setup). Validate the Swift code by building the iOS app:

cd tauri-plugin-camera/examples/tauri-app
npm install
npm run tauri ios init
npm run tauri ios build       # compiles the Swift plugin for iOS

To run the XCTest suite itself, use xcodebuild test against an iOS Simulator destination from the generated Xcode project (src-tauri/gen/apple).

Full API

Function Mobile Desktop
startPreview(options?) ✓ native preview ✓ getUserMedia
stopPreview() ✓ ✓
capture(options?) ✓ ImageCapture / AVCapturePhotoOutput ✓ canvas
flipCamera() ✓ ✗ (throws)
setFlash(mode) ✓ ✗ (throws)
setZoom(factor) ✓ ✗ (throws)
startRecording() ✓ VideoCapture / AVCaptureMovieFileOutput ✓ MediaRecorder
stopRecording() ✓ ✓
saveToGallery(path) ✓ ✗ (throws)
checkPermissions() ✓ ✓
requestPermissions() ✓ ✓
openAppSettings() ✓ ✗ (throws)
getPreviewStream() null MediaStream

About

Camera plugin for Tauri v2: capture photos, record video, and control the camera on mobile and desktop.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages