insta-360-expo-module
v0.1.2
Published
Expo plugin used for insta 360 android and ios sdk
Maintainers
Readme
Insta360 Expo Module
A comprehensive Expo module that provides React Native bindings for the Insta360 Camera SDK, enabling seamless integration of Insta360 camera functionality into your Expo/React Native applications.
📋 Table of Contents
- Features
- Installation
- Platform Setup
- Quick Start
- API Reference
- Event Listeners
- Usage Examples
- Troubleshooting
- License
✨ Features
This module provides full access to Insta360 camera capabilities:
🔌 Connection Management
- Bluetooth Low Energy (BLE) - Wireless connection with automatic device scanning
- WiFi Connection - Direct WiFi connectivity
- USB Connection - Wired connection support
📷 Camera Operations
- Photo Capture - Standard photo capture with various modes
- Video Recording - High-quality video recording
- HDR Capture - High Dynamic Range photography
- Timelapse - Time-lapse video recording
- Interval Shooting - Automatic interval-based photo capture
- Bullet Time - 360° bullet time effect
ℹ️ Camera Information
- Real-time battery level monitoring
- Storage state and SD card status
- Camera serial number and type
- Supported capture modes
- Connection status
🎥 Preview & Live Streaming
- Real-time camera preview streaming
- Preview status monitoring
📁 File Management
- List files on camera
- Delete files from camera
- File metadata (size, duration, resolution)
🔔 Real-time Events
- Connection state changes
- Battery level updates
- Capture progress
- Preview status
- Storage changes
- BLE device discovery
📦 Installation
npm install insta-360-expo-moduleor
yarn add insta-360-expo-module🛠 Platform Setup
Android
1. Add Insta360 SDK to your project
Add the Insta360 SDK repository to your android/build.gradle:
allprojects {
repositories {
// ... other repositories
maven {
url 'https://github.com/Insta360Develop/CameraSDK-Android-Release/raw/master/'
}
}
}2. Add SDK dependencies
In your android/app/build.gradle:
dependencies {
// Insta360 SDK
implementation 'com.arashivision.sdk:sdkcamera:1.x.x'
implementation 'com.arashivision.sdk:sdkmedia:1.x.x'
// Required dependencies
implementation 'com.github.Jasonchenlijian:FastBle:2.4.0'
}3. Add required permissions
Add the following permissions to your AndroidManifest.xml:
<!-- Bluetooth permissions for Android 12+ (API 31+) -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Bluetooth permissions for older Android versions -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- Location permission required for BLE scanning -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- WiFi and Network -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Camera -->
<uses-permission android:name="android.permission.CAMERA" />4. Request runtime permissions
For Android 6.0+, request permissions at runtime:
import { PermissionsAndroid, Platform } from "react-native";
const requestBlePermissions = async () => {
if (Platform.OS !== "android") return true;
const apiLevel = Platform.Version;
if (apiLevel >= 31) {
// Android 12+
const granted = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
]);
return (
granted["android.permission.BLUETOOTH_SCAN"] === "granted" &&
granted["android.permission.BLUETOOTH_CONNECT"] === "granted" &&
granted["android.permission.ACCESS_FINE_LOCATION"] === "granted"
);
} else {
// Android 11 and below
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
);
return granted === "granted";
}
};iOS
1. Add Insta360 SDK
Add the Insta360 SDK to your ios/Podfile:
pod 'INSCameraSDK', '~> 1.x.x'2. Add required permissions
Add the following to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to connect to Insta360 cameras</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to save captured media</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs Bluetooth to connect to Insta360 cameras</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs Bluetooth to connect to Insta360 cameras</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access for Bluetooth scanning</string>3. Install pods
cd ios && pod install🚀 Quick Start
import React, { useEffect, useState } from 'react';
import * as Insta360 from 'insta-360-expo-module';
function App() {
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
// Initialize SDK
const initSDK = async () => {
try {
await Insta360.initializeSDK();
console.log('SDK initialized');
} catch (error) {
console.error('Failed to initialize SDK:', error);
}
};
initSDK();
// Listen for connection events
const subscription = Insta360.addCameraConnectedListener((event) => {
console.log('Camera connected:', event.type);
setIsConnected(true);
});
return () => subscription.remove();
}, []);
const scanAndConnect = async () => {
try {
// Start BLE scan
await Insta360.startBleScan();
// Listen for found devices
const deviceSubscription = Insta360.addBleDeviceFoundListener((device) => {
console.log('Found device:', device.name);
// Connect to the first device found
Insta360.connectBle(device.mac);
});
} catch (error) {
console.error('Scan error:', error);
}
};
const capturePhoto = async () => {
if (!isConnected) return;
try {
await Insta360.capturePhoto();
console.log('Photo capture initiated');
} catch (error) {
console.error('Capture error:', error);
}
};
return (
// Your UI here
);
}📖 API Reference
SDK Initialization
isSDKInitialized(): boolean
Check if the SDK is initialized.
const isInit = Insta360.isSDKInitialized();initializeSDK(): Promise<{ success: boolean }>
Initialize the Insta360 SDK. This should be called before any other operations.
await Insta360.initializeSDK();Connection Methods
checkBlePermissions(): boolean
Check if Bluetooth permissions are granted.
const hasPermissions = Insta360.checkBlePermissions();isBluetoothEnabled(): boolean
Check if Bluetooth is enabled on the device.
const isEnabled = Insta360.isBluetoothEnabled();startBleScan(): Promise<{ success: boolean }>
Start scanning for nearby Insta360 cameras via BLE.
await Insta360.startBleScan();Prerequisites:
- Bluetooth must be enabled
- Location permissions must be granted (Android)
- BLUETOOTH_SCAN permission (Android 12+)
stopBleScan(): Promise<{ success: boolean }>
Stop the BLE scan.
await Insta360.stopBleScan();connectBle(deviceMac: string): Promise<{ success: boolean; deviceName?: string }>
Connect to a camera via Bluetooth using its MAC address.
await Insta360.connectBle("AA:BB:CC:DD:EE:FF");connectWiFi(): Promise<{ success: boolean; cameraType?: string }>
Connect to a camera via WiFi. The device must be connected to the camera's WiFi network.
await Insta360.connectWiFi();connectUSB(): Promise<{ success: boolean }>
Connect to a camera via USB.
await Insta360.connectUSB();disconnectCamera(): Promise<{ success: boolean }>
Disconnect from the currently connected camera.
await Insta360.disconnectCamera();isConnected(): boolean
Check if a camera is currently connected.
const connected = Insta360.isConnected();getConnectionType(): ConnectionType
Get the current connection type.
type ConnectionType = "none" | "ble" | "wifi" | "usb" | "unknown";
const connType = Insta360.getConnectionType();getCameraType(): string
Get the connected camera model/type.
const cameraType = Insta360.getCameraType();
// e.g., "ONE X2", "ONE RS", etc.Camera Information
fetchCameraOptions(): Promise<CameraOptions>
Fetch comprehensive camera information from the connected device.
interface CameraOptions {
success: boolean;
batteryLevel: number; // 0-100
storageState: number; // 0 = no card, 1 = card available
mediaTime: number; // Available recording time in seconds
}
const options = await Insta360.fetchCameraOptions();getBatteryLevel(): number
Get current battery level (0-100).
const battery = Insta360.getBatteryLevel();getStorageState(): number
Get SD card state (0 = not available, 1 = available).
const storage = Insta360.getStorageState();isBatteryCharging(): boolean
Check if the camera is currently charging.
const isCharging = Insta360.isBatteryCharging();isSdCardEnabled(): boolean
Check if an SD card is inserted and enabled.
const hasCard = Insta360.isSdCardEnabled();getSerialNumber(): string
Get the camera's serial number.
const serial = Insta360.getSerialNumber();getSupportedCaptureModes(): CaptureMode[]
Get all capture modes supported by the connected camera.
type CaptureMode =
| "CAPTURE_NORMAL" // Standard photo
| "RECORD_NORMAL" // Standard video
| "HDR_CAPTURE" // HDR photo
| "HDR_RECORD" // HDR video
| "INTERVAL_SHOOTING" // Interval photos
| "TIMELAPSE" // Timelapse video
| "BULLETTIME" // Bullet time
| "TIME_SHIFT" // TimeShift
| "LOOPER_RECORDING" // Loop recording
| "SUPER_RECORD" // Super resolution
| "SLOW_MOTION" // Slow motion
| "SELFIE_RECORD" // Selfie mode
| "PURE_RECORD" // Pure shot
| "BURST" // Burst mode
| "NIGHT_SCENE" // Night mode
| "STARLAPSE_SHOOTING"; // Star lapse
const modes = Insta360.getSupportedCaptureModes();getCurrentCaptureMode(): string
Get the currently active capture mode.
const mode = Insta360.getCurrentCaptureMode();Preview Operations
startPreview(): Promise<{ success: boolean }>
Start the camera preview stream.
await Insta360.startPreview();stopPreview(): Promise<{ success: boolean }>
Stop the camera preview stream.
await Insta360.stopPreview();isPreviewStreaming(): boolean
Check if preview is currently streaming.
const streaming = Insta360.isPreviewStreaming();Capture Operations
capturePhoto(): Promise<{ success: boolean }>
Capture a photo with current settings.
await Insta360.capturePhoto();Listen to onCaptureFinished event to get the file paths.
startRecording(): Promise<{ success: boolean }>
Start video recording.
await Insta360.startRecording();stopRecording(): Promise<{ success: boolean }>
Stop video recording.
await Insta360.stopRecording();isRecording(): boolean
Check if camera is currently recording.
const recording = Insta360.isRecording();Special Capture Modes
captureHDR(): Promise<{ success: boolean }>
Capture an HDR photo.
await Insta360.captureHDR();startTimelapse(): Promise<{ success: boolean }>
Start timelapse recording.
await Insta360.startTimelapse();stopTimelapse(): Promise<{ success: boolean }>
Stop timelapse recording.
await Insta360.stopTimelapse();startIntervalShooting(): Promise<{ success: boolean }>
Start interval shooting (captures photos at set intervals).
await Insta360.startIntervalShooting();stopIntervalShooting(): Promise<{ success: boolean }>
Stop interval shooting.
await Insta360.stopIntervalShooting();startBulletTime(): Promise<{ success: boolean }>
Start bullet time recording.
await Insta360.startBulletTime();stopBulletTime(): Promise<{ success: boolean }>
Stop bullet time recording.
await Insta360.stopBulletTime();File Management
getCameraFileList(): Promise<{ files: CameraFile[] }>
Get list of all files on the camera.
interface CameraFile {
name: string; // File name
uri: string; // File URI
isVideo: boolean; // true = video, false = photo
width: number; // Resolution width
height: number; // Resolution height
duration: number; // Duration in ms (video only)
createTime: number; // Creation timestamp
size: number; // File size in bytes
urls: string[]; // Array of file URLs
}
const { files } = await Insta360.getCameraFileList();deleteCameraFile(fileUrls: string[]): Promise<{ success: boolean }>
Delete files from the camera.
await Insta360.deleteCameraFile(["file://path/to/file1.jpg"]);🔔 Event Listeners
All event listeners return an EventSubscription object with a remove() method for cleanup.
Connection Events
addCameraConnectedListener(listener: (event: CameraConnectedEvent) => void)
Fired when camera successfully connects.
interface CameraConnectedEvent {
type: ConnectionType; // 'ble' | 'wifi' | 'usb'
}
const subscription = Insta360.addCameraConnectedListener((event) => {
console.log(`Camera connected via ${event.type}`);
});
// Cleanup
subscription.remove();addCameraDisconnectedListener(listener: (event: CameraDisconnectedEvent) => void)
Fired when camera disconnects.
interface CameraDisconnectedEvent {
type?: string;
error?: boolean;
errorCode?: number;
}
const subscription = Insta360.addCameraDisconnectedListener((event) => {
console.log("Camera disconnected", event);
});BLE Scan Events
addBleScanStartListener(listener: (event: BleScanStartEvent) => void)
Fired when BLE scan starts.
interface BleScanStartEvent {
status: "started";
}
const subscription = Insta360.addBleScanStartListener((event) => {
console.log("BLE scan started");
});addBleScanFailedListener(listener: (event: BleScanFailedEvent) => void)
Fired when BLE scan fails to start.
interface BleScanFailedEvent {
status: "failed";
}addBleDeviceFoundListener(listener: (event: BleDeviceFoundEvent) => void)
Fired when a BLE device is discovered during scanning.
interface BleDeviceFoundEvent {
name: string; // Device name
mac: string; // MAC address
rssi: number; // Signal strength
}
const subscription = Insta360.addBleDeviceFoundListener((device) => {
console.log(`Found device: ${device.name} (${device.mac})`);
});addBleScanFinishedListener(listener: (event: BleScanFinishedEvent) => void)
Fired when BLE scan completes.
interface BleScanFinishedEvent {
devices: BleDevice[];
}Preview Events
addPreviewOpenedListener(listener: (event: PreviewOpenedEvent) => void)
Fired when preview stream opens successfully.
const subscription = Insta360.addPreviewOpenedListener((event) => {
console.log("Preview opened");
});addPreviewClosedListener(listener: (event: PreviewClosedEvent) => void)
Fired when preview stream closes.
const subscription = Insta360.addPreviewClosedListener((event) => {
console.log("Preview closed");
});addPreviewErrorListener(listener: (event: PreviewErrorEvent) => void)
Fired when preview encounters an error.
const subscription = Insta360.addPreviewErrorListener((event) => {
console.error("Preview error:", event.error);
});Capture Events
addCaptureStartingListener(listener: (event: CaptureStartingEvent) => void)
Fired when capture is starting.
const subscription = Insta360.addCaptureStartingListener((event) => {
console.log("Capture starting...");
});addCaptureWorkingListener(listener: (event: CaptureWorkingEvent) => void)
Fired when capture is in progress.
const subscription = Insta360.addCaptureWorkingListener((event) => {
console.log("Capture in progress");
});addCaptureStoppingListener(listener: (event: CaptureStoppingEvent) => void)
Fired when capture is stopping.
const subscription = Insta360.addCaptureStoppingListener((event) => {
console.log("Capture stopping...");
});addCaptureFinishedListener(listener: (event: CaptureFinishedEvent) => void)
Fired when capture completes successfully.
interface CaptureFinishedEvent {
status: "finished";
files: string[]; // Array of captured file paths
}
const subscription = Insta360.addCaptureFinishedListener((event) => {
console.log(`Captured ${event.files.length} file(s)`);
event.files.forEach((file) => console.log(file));
});addCaptureErrorListener(listener: (event: CaptureErrorEvent) => void)
Fired when capture fails.
interface CaptureErrorEvent {
error: boolean;
errorCode: number;
}
const subscription = Insta360.addCaptureErrorListener((event) => {
console.error(`Capture error: ${event.errorCode}`);
});addCaptureTimeChangedListener(listener: (event: CaptureTimeChangedEvent) => void)
Fired periodically during video recording with elapsed time.
interface CaptureTimeChangedEvent {
time: number; // Elapsed time in milliseconds
}
const subscription = Insta360.addCaptureTimeChangedListener((event) => {
const seconds = Math.floor(event.time / 1000);
console.log(`Recording: ${seconds}s`);
});Camera Status Events
addBatteryLevelChangedListener(listener: (event: BatteryLevelChangedEvent) => void)
Fired when battery level changes.
interface BatteryLevelChangedEvent {
level: number; // 0-100
isCharging: boolean;
}
const subscription = Insta360.addBatteryLevelChangedListener((event) => {
console.log(`Battery: ${event.level}% ${event.isCharging ? "⚡" : "🔋"}`);
});addStorageStateChangedListener(listener: (event: StorageStateChangedEvent) => void)
Fired when SD card state changes.
interface StorageStateChangedEvent {
enabled: boolean;
}
const subscription = Insta360.addStorageStateChangedListener((event) => {
console.log(`SD Card: ${event.enabled ? "Available" : "Not Available"}`);
});💡 Usage Examples
Complete Connection Flow
import React, { useEffect, useState } from 'react';
import { View, Button, Text, FlatList, Alert } from 'react-native';
import * as Insta360 from 'insta-360-expo-module';
function CameraConnection() {
const [devices, setDevices] = useState([]);
const [isScanning, setIsScanning] = useState(false);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
// Initialize SDK
Insta360.initializeSDK();
// Setup event listeners
const connectedSub = Insta360.addCameraConnectedListener((event) => {
Alert.alert('Success', `Connected via ${event.type}`);
setIsConnected(true);
});
const disconnectedSub = Insta360.addCameraDisconnectedListener(() => {
Alert.alert('Info', 'Camera disconnected');
setIsConnected(false);
});
const deviceFoundSub = Insta360.addBleDeviceFoundListener((device) => {
setDevices(prev => {
if (!prev.find(d => d.mac === device.mac)) {
return [...prev, device];
}
return prev;
});
});
const scanFinishedSub = Insta360.addBleScanFinishedListener(() => {
setIsScanning(false);
});
return () => {
connectedSub.remove();
disconnectedSub.remove();
deviceFoundSub.remove();
scanFinishedSub.remove();
};
}, []);
const startScan = async () => {
try {
setDevices([]);
setIsScanning(true);
await Insta360.startBleScan();
} catch (error) {
setIsScanning(false);
Alert.alert('Error', error.message);
}
};
const connectToDevice = async (mac) => {
try {
await Insta360.stopBleScan();
await Insta360.connectBle(mac);
} catch (error) {
Alert.alert('Error', error.message);
}
};
return (
<View>
<Button
title={isScanning ? "Scanning..." : "Scan for Cameras"}
onPress={startScan}
disabled={isScanning || isConnected}
/>
<FlatList
data={devices}
keyExtractor={(item) => item.mac}
renderItem={({ item }) => (
<Button
title={`${item.name} (${item.rssi}dB)`}
onPress={() => connectToDevice(item.mac)}
/>
)}
/>
{isConnected && (
<Button
title="Disconnect"
onPress={() => Insta360.disconnectCamera()}
/>
)}
</View>
);
}Photo Capture with Progress
function PhotoCapture() {
const [isCapturing, setIsCapturing] = useState(false);
useEffect(() => {
const startingSub = Insta360.addCaptureStartingListener(() => {
setIsCapturing(true);
});
const finishedSub = Insta360.addCaptureFinishedListener((event) => {
setIsCapturing(false);
Alert.alert('Success', `Photo saved: ${event.files[0]}`);
});
const errorSub = Insta360.addCaptureErrorListener((event) => {
setIsCapturing(false);
Alert.alert('Error', `Capture failed: ${event.errorCode}`);
});
return () => {
startingSub.remove();
finishedSub.remove();
errorSub.remove();
};
}, []);
const takePhoto = async () => {
try {
await Insta360.capturePhoto();
} catch (error) {
Alert.alert('Error', error.message);
}
};
return (
<View>
<Button
title={isCapturing ? "Capturing..." : "Take Photo"}
onPress={takePhoto}
disabled={isCapturing}
/>
</View>
);
}Video Recording with Timer
function VideoRecording() {
const [isRecording, setIsRecording] = useState(false);
const [recordingTime, setRecordingTime] = useState(0);
useEffect(() => {
const workingSub = Insta360.addCaptureWorkingListener(() => {
setIsRecording(true);
});
const finishedSub = Insta360.addCaptureFinishedListener((event) => {
setIsRecording(false);
setRecordingTime(0);
Alert.alert('Success', `Video saved: ${event.files[0]}`);
});
const timeSub = Insta360.addCaptureTimeChangedListener((event) => {
setRecordingTime(Math.floor(event.time / 1000));
});
return () => {
workingSub.remove();
finishedSub.remove();
timeSub.remove();
};
}, []);
const toggleRecording = async () => {
try {
if (isRecording) {
await Insta360.stopRecording();
} else {
await Insta360.startRecording();
}
} catch (error) {
Alert.alert('Error', error.message);
}
};
return (
<View>
<Text>{recordingTime}s</Text>
<Button
title={isRecording ? "Stop Recording" : "Start Recording"}
onPress={toggleRecording}
/>
</View>
);
}Battery Monitor
function BatteryMonitor() {
const [battery, setBattery] = useState(0);
const [isCharging, setIsCharging] = useState(false);
useEffect(() => {
const batterySub = Insta360.addBatteryLevelChangedListener((event) => {
setBattery(event.level);
setIsCharging(event.isCharging);
});
// Initial fetch
const fetchBattery = async () => {
if (Insta360.isConnected()) {
const level = Insta360.getBatteryLevel();
const charging = Insta360.isBatteryCharging();
setBattery(level);
setIsCharging(charging);
}
};
fetchBattery();
return () => batterySub.remove();
}, []);
return (
<View>
<Text>
Battery: {battery}% {isCharging ? '⚡ Charging' : '🔋'}
</Text>
</View>
);
}🔧 Troubleshooting
Android
BLE Scan Fails to Start
Problem: startBleScan() fails with permission errors.
Solutions:
- Ensure Bluetooth is enabled on the device
- Check that all required permissions are granted:
- Android 12+:
BLUETOOTH_SCAN,BLUETOOTH_CONNECT,ACCESS_FINE_LOCATION - Android 11-:
ACCESS_FINE_LOCATION
- Android 12+:
- Request permissions at runtime before scanning
- Enable location services (required for BLE scanning on Android)
Camera Not Found During Scan
Problem: BLE scan completes but no devices found.
Solutions:
- Ensure camera is powered on and in pairing mode
- Check if camera is already connected to another device
- Verify camera is within Bluetooth range (~10 meters)
- Reset camera's Bluetooth by turning it off and on
Connection Fails After Scan
Problem: connectBle() fails even though device was found.
Solutions:
- Stop the scan before connecting:
await Insta360.stopBleScan() - Ensure only one connection attempt at a time
- Check if camera requires pairing in its settings first
Preview Not Starting
Problem: startPreview() succeeds but no preview appears.
Solutions:
- This module provides camera control, not preview rendering
- You need to implement your own preview view using the camera stream
- Use a third-party video player component with the preview stream URL
iOS
Camera Permissions Denied
Problem: Camera operations fail with permission errors.
Solutions:
- Ensure
Info.plistcontains required usage descriptions - Request permissions before accessing camera
- Direct users to Settings if permissions were previously denied
Bluetooth Not Working
Problem: BLE operations fail on iOS.
Solutions:
- Add Bluetooth usage descriptions to
Info.plist - Ensure app has Bluetooth permissions
- Check iOS version compatibility (iOS 13+ recommended)
General Issues
SDK Initialization Fails
Problem: initializeSDK() returns error.
Solutions:
- Verify Insta360 SDK is properly installed
- Check that SDK version is compatible with your camera model
- Ensure application context is available (Android)
- Restart the app if SDK state is corrupted
Camera Disconnects Randomly
Problem: Camera disconnects unexpectedly during operation.
Solutions:
- Check camera battery level
- Verify stable Bluetooth/WiFi connection
- Keep device within connection range
- Disable battery optimization for your app (Android)
- Implement reconnection logic with event listeners
File Operations Fail
Problem: getCameraFileList() or file deletion fails.
Solutions:
- Ensure camera is connected
- Check SD card is inserted and formatted correctly
- Verify storage permissions are granted
- Some cameras may have file access limitations
Memory Issues
Problem: App crashes or runs out of memory.
Solutions:
- Clean up event listeners when components unmount
- Close preview streams when not needed
- Limit number of concurrent operations
- Process large file lists in batches
📱 Supported Cameras
This module supports all Insta360 cameras compatible with the Insta360 Camera SDK, including:
- Insta360 ONE X2
- Insta360 ONE RS
- Insta360 ONE R
- Insta360 ONE X
- Insta360 ONE
- Other compatible models
Check your camera's documentation for specific feature support.
🏗️ Architecture
Module Structure
insta-360-expo-module/
├── android/ # Android native implementation
│ ├── src/main/java/expo/modules/insta360expomodule/
│ │ └── Insta360ExpoModule.kt # Kotlin SDK wrapper
│ └── build.gradle
├── ios/ # iOS native implementation
│ ├── Insta360ExpoModule.swift # Swift SDK wrapper
│ └── Insta360ExpoModule.podspec
├── src/ # TypeScript/JavaScript API
│ ├── index.ts # Main export
│ ├── Insta360ExpoModule.ts # Module API
│ ├── Insta360ExpoModule.types.ts # TypeScript definitions
│ └── Insta360ExpoModuleNative.ts # Native bridge
└── example/ # Example app
└── App.tsx # Comprehensive demoNative Implementation (Android)
The Android implementation (Insta360ExpoModule.kt) wraps the Insta360 Camera SDK with the following key features:
SDK Managers
- InstaCameraManager: Core camera control and connection management
- InstaMediaSDK: Media processing and file operations
- WorkUtils: File and media work utilities
Callbacks Implemented
ICameraChangedCallback: Connection state changesIPreviewStatusListener: Preview stream statusICaptureStatusListener: Capture operation statusIScanBleListener: BLE device scanningICameraOperateCallback: Camera operation results
Key Features
- Coroutine-based async operations
- Automatic SDK initialization on module creation
- Comprehensive error handling
- Real-time event emission to JavaScript
- Permission checking utilities
iOS Implementation
The iOS implementation provides basic camera functionality through native iOS APIs. For full Insta360 SDK features on iOS, additional integration work may be required.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT License - see LICENSE file for details.
🔗 Resources
- Insta360 Developer Portal
- Insta360 Camera SDK Documentation
- Expo Modules Documentation
- Example App Source
📞 Support
For issues and questions:
- Open an issue on GitLab
- Check existing issues for solutions
- Review the example app for implementation guidance
📝 Changelog
Version 0.1.0
- Initial release
- Full Android support with Insta360 Camera SDK
- Basic iOS support
- Complete BLE, WiFi, and USB connection support
- Photo and video capture
- Special capture modes (HDR, Timelapse, Interval, Bullet Time)
- File management
- Real-time event system
- Comprehensive example app
Made with ❤️ by VT Netzwelt
