Search
Loading...
Skip to content

Mobile Camera Configuration

The @imgly/camera-flutter Flutter module is built on top of the native Android and iOS UI implementation and has no dedicated Flutter UI. However, you still have access to the same customization options as for iOS and an interface for Android. To use them you need to configure them natively for both platforms. Further, the most important settings can be set from Flutter directly.

Flutter Customization#

From within Flutter directly, you can modify the most important camera behavior settings.

CameraSettings#

All the basic configuration settings are part of the EngineSettings which are required to initialize the camera.

  • license – the license to activate the Engine with.
  • userID – an optional unique ID tied to your application’s user. This helps us accurately calculate monthly active users (MAU). Especially useful when one person uses the app on multiple devices with a sign-in feature, ensuring they’re counted once. Providing this aids in better data accuracy. The default value is nil.
final settings =
CameraSettings(license: "YOUR_LICENSE", userId: "YOUR_USER_ID");

Reactions#

You can optionally provide a video parameter which lets the user react to that video.

final _ = await IMGLYCamera.openCamera(
settings,
// Optional, if you want to react to a video
video: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_2mb.mp4',
)

Native Customization#

In order to fully utilize the natively available customizations, the module comes with native interfaces for both iOS and Android.

iOS#

The customization layer for iOS is written in Swift and available via the IMGLYCameraModuleSwiftAdapter.shared instance. The camera that is opened via the IMGLYCameraModuleSwiftAdapter.openCamera() function can be completely customized and exchanged. For this to work you can use the IMGLYCameraModuleSwiftAdapter.builderClosure which provides optional metadata with which you can provide any prebuilt or custom camera view. The metadata parameter of the openCamera function can be utilized to provide customization details from the React Native side of your app to the native side:

You can either use the CameraBuilder.default implementation or in case you want a completely custom UI, you can use the CameraBuilder.custom function that allows you to return a custom View based on a given CameraSettings, URL, metadata and an CameraBuilderResult:

// Configure the [CaptureVideo.Input].
IMGLYCameraPlugin.configurationClosure = {
/*
* This closure requires returning a [CaptureVideo.Input].
*
* You can access the following parameters:
* - "cameraSettings": The CameraSettings passed from the Flutter side.
* - "engineConfiguration": The EngineConfiguration that includes your license.
* - "metadata": Metadata passed from the Flutter side.
* - "videoUri": The video reaction URL passed from Flutter, or null.
*/
if (metadata["is_reactions"] == true) {
CaptureVideo.Input(
engineConfiguration = engineConfiguration,
cameraMode = CameraMode.Reaction(
videoUri ?: throw RuntimeException("Missing video URL."),
cameraLayoutMode = CameraLayoutMode.Horizontal,
positionsSwapped = false,
),
)
} else {
// Simply return null to use the default camera configuration.
null
}
}
// Adding custom metadata to the CameraResult.
IMGLYCameraPlugin.resultClosure = {
/*
* This closure allows you to add custom metadata of type [Map<String, Any?>] to the CameraResult.
* You can access the following values:
* - "cameraResult": The native CameraResult returned by the camera.
* - "inputMetadata": Metadata passed from the Flutter side when the camera was opened.
*
* The return value must be a [Map<String, Any?>], which will be passed to the Dart-side
* representation of the CameraResult.
*
* Notes:
* - Use `mapOf<String, Any?>()` to return key-value pairs.
* - Return `null` if no metadata should be added.
*/
// Example: Read the result data...
val recordings = when (val result = cameraResult) {
is CameraResult.Record -> result.recordings
is CameraResult.Reaction -> result.reaction
else -> emptyList()
}
// Return a custom metadata map
mapOf(
"MY_CUSTOM_KEY" to "MY_CUSTOM_VALUE",
)
}

Android#

On Android, the module comes with two interfaces for modifications:

CameraInputClosure#

The CameraInputClosure can be used to provide a custom CaptureVideo.Input based on given metadata. It is accessible via the IMGLYCameraModule.configurationClosure.

// Configure the [CaptureVideo.Input].
IMGLYCameraPlugin.configurationClosure = {
/*
* This closure requires returning a [CaptureVideo.Input].
*
* You can access the following parameters:
* - "cameraSettings": The CameraSettings passed from the Flutter side.
* - "engineConfiguration": The EngineConfiguration that includes your license.
* - "metadata": Metadata passed from the Flutter side.
* - "videoUri": The video reaction URL passed from Flutter, or null.
*/
if (metadata["is_reactions"] == true) {
CaptureVideo.Input(
engineConfiguration = engineConfiguration,
cameraMode = CameraMode.Reaction(
videoUri ?: throw RuntimeException("Missing video URL."),
cameraLayoutMode = CameraLayoutMode.Horizontal,
positionsSwapped = false,
),
)
} else {
// Simply return null to use the default camera configuration.
null
}
}

CameraResultClosure#

The CameraResultClosure can be used to return a custom CameraResult based on the result returned by the camera. It is accessible via the IMGLYCameraModule.resultClosure.

// Adding custom metadata to the CameraResult.
IMGLYCameraPlugin.resultClosure = {
/*
* This closure allows you to add custom metadata of type [Map<String, Any?>] to the CameraResult.
* You can access the following values:
* - "cameraResult": The native CameraResult returned by the camera.
* - "inputMetadata": Metadata passed from the Flutter side when the camera was opened.
*
* The return value must be a [Map<String, Any?>], which will be passed to the Dart-side
* representation of the CameraResult.
*
* Notes:
* - Use `mapOf<String, Any?>()` to return key-value pairs.
* - Return `null` if no metadata should be added.
*/
// Example: Read the result data...
val recordings = when (val result = cameraResult) {
is CameraResult.Record -> result.recordings
is CameraResult.Reaction -> result.reaction
else -> emptyList()
}
// Return a custom metadata map
mapOf(
"MY_CUSTOM_KEY" to "MY_CUSTOM_VALUE",
)
}

Full Code#

Here’s the code for all three files:

camera_flutter.dart#

import "package:imgly_camera/imgly_camera.dart";
class CameraFlutter {
/// Opens the camera.
void openCamera() async {
final settings =
CameraSettings(license: "YOUR_LICENSE", userId: "YOUR_USER_ID");
final _ = await IMGLYCamera.openCamera(
settings,
// Optional, if you want to react to a video
video: 'https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_2mb.mp4',
)
}
}

ConfigurationGuide.swift#

import imgly_camera
import imgly_editor
import SwiftUI
func useCustomEditor() {
IMGLYEditorPlugin.builderClosure = { _, metadata in
// Make decisions based on your own metadata.
if metadata?["use_custom_editor"] as? Bool == true {
// Return your custom editor.
EditorBuilder.custom { settings, _, _, result in
CustomEditor(settings: settings, result: result)
}
} else {
// Return a custom or prebuilt editor.
EditorBuilder.design()
}
}
}
private struct CustomEditor: View {
init(settings _: EditorSettings, result _: @escaping EditorBuilder.EditorBuilderResult) {}
var body: some View {
Text("Custom Editor")
}
}
func configureCamera() {
IMGLYCameraPlugin.builderClosure = { metadata in
// Make decisions based on your own metadata.
if metadata?["use_custom_camera"] as? Bool == true {
// Return your custom camera.
CameraBuilder.custom { settings, url, metadata, result in
CustomCamera(settings: settings, url: url, metadata: metadata, result: result)
}
} else {
// Return a custom or prebuilt camera.
CameraBuilder.default()
}
}
}
private struct CustomCamera: View {
init(
settings _: CameraSettings,
url _: URL?,
metadata _: [String: Any]?,
result _: @escaping CameraBuilder.CameraBuilderResult
) {}
var body: some View {
Text("Custom Camera")
}
}

ConfigurationGuide.kt#

package ly.img.editor.flutter.showcases.guides
import androidx.compose.runtime.Composable
import ly.img.camera.core.CameraLayoutMode
import ly.img.camera.core.CameraMode
import ly.img.camera.core.CameraResult
import ly.img.camera.core.CaptureVideo
import ly.img.camera.flutter.plugin.IMGLYCameraPlugin
import ly.img.editor.flutter.plugin.IMGLYEditorPlugin
import ly.img.editor.flutter.plugin.builder.EditorBuilder
import ly.img.editor.flutter.plugin.builder.EditorBuilderResult
import ly.img.editor.flutter.plugin.model.EditorSettings
private fun useCustomEditor() {
IMGLYEditorPlugin.builderClosure = { _, metadata ->
if (metadata?.get("custom") == true) {
EditorBuilder.custom { settings, _, _, result, onClose ->
@Composable {
CustomEditor(settings, result, onClose)
}
}
} else {
EditorBuilder.design()
}
}
}
private fun customizeCamera() {
// Configure the [CaptureVideo.Input].
IMGLYCameraPlugin.configurationClosure = {
/*
* This closure requires returning a [CaptureVideo.Input].
*
* You can access the following parameters:
* - "cameraSettings": The CameraSettings passed from the Flutter side.
* - "engineConfiguration": The EngineConfiguration that includes your license.
* - "metadata": Metadata passed from the Flutter side.
* - "videoUri": The video reaction URL passed from Flutter, or null.
*/
if (metadata["is_reactions"] == true) {
CaptureVideo.Input(
engineConfiguration = engineConfiguration,
cameraMode = CameraMode.Reaction(
videoUri ?: throw RuntimeException("Missing video URL."),
cameraLayoutMode = CameraLayoutMode.Horizontal,
positionsSwapped = false,
),
)
} else {
// Simply return null to use the default camera configuration.
null
}
}
// Adding custom metadata to the CameraResult.
IMGLYCameraPlugin.resultClosure = {
/*
* This closure allows you to add custom metadata of type [Map<String, Any?>] to the CameraResult.
* You can access the following values:
* - "cameraResult": The native CameraResult returned by the camera.
* - "inputMetadata": Metadata passed from the Flutter side when the camera was opened.
*
* The return value must be a [Map<String, Any?>], which will be passed to the Dart-side
* representation of the CameraResult.
*
* Notes:
* - Use `mapOf<String, Any?>()` to return key-value pairs.
* - Return `null` if no metadata should be added.
*/
// Example: Read the result data...
val recordings = when (val result = cameraResult) {
is CameraResult.Record -> result.recordings
is CameraResult.Reaction -> result.reaction
else -> emptyList()
}
// Return a custom metadata map
mapOf(
"MY_CUSTOM_KEY" to "MY_CUSTOM_VALUE",
)
}
}
@Composable
private fun CustomEditor(
settings: EditorSettings,
result: EditorBuilderResult,
onClose: (Throwable?) -> Unit,
) {
}