Configure action-style workflows in Android editors by dispatching
EditorEvents and handling them with EditorConfiguration callbacks.
Android does not expose the Web cesdk.actions registry or cesdk.utils API.
Use the Android editor configuration instead: UI components send events, and
callbacks own export, upload, analytics, and app-specific workflow steps.
The snippets below use the editor-provided editorContext.engine; the editor
owns engine initialization and lifecycle.
Action Hooks on Android#
Action-style work on Android is split between callback hooks and event
dispatch. Configure the hooks in EditorConfiguration.remember.
| Hook | When it runs | Typical use |
|---|---|---|
onCreate |
When the editor and engine are created | Load or build a scene and prepare asset sources. |
onLoaded |
After onCreate finishes on first launch or after process recreation |
Collect editor flows or run setup that depends on a loaded editor. |
onExport |
After EditorEvent.Export.Start() is sent |
Export, validate, upload, or hand the result to your app. |
onUpload |
After the user selects a file for an upload asset source | Replace temporary local URIs with permanent app storage URIs. |
onEvent |
Whenever an editor or custom event is sent | Reduce events into UI state, analytics, or follow-up work. |
onClose |
After EditorEvent.OnClose is sent or the system back action is unhandled |
Confirm close behavior or route the close request to your app UI. |
onError |
When the editor captures a Throwable |
Inspect the Throwable and route failures to your app UI. |
The default export callback only logs a warning. Add onExport whenever an
export action should produce, save, share, or upload a file.
Trigger an Action from UI#
Send EditorEvent.Export.Start() from your own Compose UI to start the export
workflow. The editor’s built-in export controls use the same event path.
Button( modifier = Modifier .align(Alignment.BottomCenter) .padding(24.dp), enabled = !exportState.isExporting, onClick = { editorContext.eventHandler.send(EditorEvent.Export.Start()) },) { Text("Export")}The event is routed through the editor event handler and invokes onExport.
When your UI shows progress, send EditorEvent.Export.Cancel() to cancel the
running export job.
TextButton( onClick = { editorContext.eventHandler.send(EditorEvent.Export.Cancel()) },) { Text("Cancel")}Handle Exports#
Keep custom events small and specific to the workflow state you want to display or track.
object ActionsExportStarted : EditorEvent
data class ActionsExportCompleted( val fileName: String,) : EditorEvent
data class ActionsExportFailed( val message: String,) : EditorEventImplement onExport inside EditorConfiguration.remember. This sample exports
the current scene to PDF, writes it to app cache, and sends a success or failure
event back to the editor.
onExport = { editorContext.eventHandler.send(ActionsExportStarted) try { val file = exportCurrentSceneToCache( engine = editorContext.engine, directory = editorContext.activity.cacheDir, ) editorContext.eventHandler.send(ActionsExportCompleted(file.name)) } catch (throwable: CancellationException) { throw throwable } catch (throwable: Throwable) { editorContext.eventHandler.send( ActionsExportFailed(throwable.message ?: throwable.toString()), ) }}Those custom events are reduced in onEvent below. The reducer turns
ActionsExportStarted, ActionsExportCompleted, and ActionsExportFailed into
state that the overlay uses to show progress, completion, or error dialogs.
The export helper reads the active scene from the editor engine and exports it
with engine.block.export(...).
private suspend fun exportCurrentSceneToCache( engine: Engine, directory: File,): File { val scene = requireNotNull(engine.scene.get()) { "No scene loaded for export." } val buffer = engine.block.export( block = scene, mimeType = MimeType.PDF, ) return writeToCacheFile( byteBuffer = buffer, directory = directory, mimeType = MimeType.PDF, )}Write the returned ByteBuffer to app-controlled storage before sharing,
uploading, or handing it to another Android component.
private suspend fun writeToCacheFile( byteBuffer: ByteBuffer, directory: File, mimeType: MimeType,): File = withContext(Dispatchers.IO) { val extension = when (mimeType) { MimeType.PNG -> "png" MimeType.JPEG -> "jpg" MimeType.TGA -> "tga" MimeType.SVG -> "svg" MimeType.MP4 -> "mp4" MimeType.BINARY -> "bin" MimeType.PDF -> "pdf" } val outputFile = File.createTempFile(UUID.randomUUID().toString(), ".$extension", directory) val sourceBuffer = byteBuffer.asReadOnlyBuffer()
FileOutputStream(outputFile).channel.use { channel -> while (sourceBuffer.hasRemaining()) { channel.write(sourceBuffer) } }
check(outputFile.length() > 0L) { "Exported file is empty." } outputFile}Reflect Results in the UI#
Represent action state with a small data class. Store it with
editorContext.mutableStateOf(...) so it survives configuration changes while
the editor is open; use editorContext.stateOf(...) when another custom
component needs read-only access to the same keyed state. Then reduce editor
events into that state in onEvent.
data class ActionsExportState( val isExporting: Boolean = false, val exportedFileName: String? = null, val errorMessage: String? = null,)var exportState by editorContext.mutableStateOf( key = "actions.export.state", initial = ActionsExportState(),)onEvent = { event -> exportState = when (event) { is ActionsExportStarted -> { ActionsExportState(isExporting = true) }
is ActionsExportCompleted -> { ActionsExportState(exportedFileName = event.fileName) }
is ActionsExportFailed -> { ActionsExportState(errorMessage = event.message) }
is EditorEvent.Export.Cancel -> { ActionsExportState() }
else -> exportState }}onEvent receives both built-in editor events and your custom event classes.
Use it for lightweight state updates, analytics, or follow-up workflow routing.
Customize Uploads#
Use onUpload to replace the Web uploadFile action pattern on Android. The
callback receives the generated AssetDefinition and the upload source that
triggered it.
onUpload = { assetDefinition, uploadSource -> uploadTransientResource( assetDefinition = assetDefinition, uploadSource = uploadSource, )}Upload the local URI to your own storage client, then return an updated
AssetDefinition with permanent metadata. If the asset has a separate
thumbUri, upload that thumbnail separately instead of pointing it at the
media file.
private suspend fun uploadTransientResource( assetDefinition: AssetDefinition, uploadSource: UploadAssetSourceType,): AssetDefinition { val meta = assetDefinition.meta ?: return assetDefinition val localUri = meta["uri"] ?: return assetDefinition val permanentUri = uploadToPermanentStorage( uri = localUri, sourceId = uploadSource.sourceId, ) val permanentMeta = meta.toMutableMap() permanentMeta["uri"] = permanentUri meta["thumbUri"]?.let { thumbnailUri -> permanentMeta["thumbUri"] = if (thumbnailUri == localUri) { permanentUri } else { uploadToPermanentStorage( uri = thumbnailUri, sourceId = uploadSource.sourceId, ) } } return assetDefinition.copy( meta = permanentMeta, )}
private suspend fun uploadToPermanentStorage( uri: String, sourceId: String,): String { check(sourceId.isNotBlank()) { "Upload source id is required." } // Replace this with your app's storage client and return its permanent URI. return uri}API Reference#
| API | Purpose |
|---|---|
EditorConfiguration.remember { onExport = { ... } } |
Handles export actions triggered by EditorEvent.Export.Start(). |
EditorConfiguration.remember { onEvent = { event -> ... } } |
Observes built-in and custom editor events. |
EditorConfiguration.remember { onUpload = { assetDefinition, uploadSource -> ... } } |
Customizes assets selected through upload sources. |
editorContext.mutableStateOf(key=_, initial=_) |
Stores editor-scoped Compose state that survives configuration changes. |
editorContext.stateOf(key=_) |
Reads state previously declared with editorContext.mutableStateOf(...). |
editorContext.eventHandler.send(event=_) |
Dispatches an EditorEvent from callbacks or editor UI components. |
editorContext.engine |
Provides the editor-owned engine for export work inside callbacks. |
editorContext.activity |
Provides the Android Activity, used here for cacheDir. |
EditorEvent.Export.Start() |
Starts the configured export workflow. |
EditorEvent.Export.Cancel() |
Cancels the running export job, if one exists. |
engine.scene.get() |
Reads the currently loaded scene block. |
engine.block.export(block=_, mimeType=_) |
Exports a scene, page, or block to the requested MIME type. |
assetDefinition.meta |
Reads the uploaded asset metadata generated by the editor. |
uploadSource.sourceId |
Identifies the upload asset source that triggered onUpload. |
AssetDefinition.copy(meta=_) |
Returns an updated asset definition from onUpload. |
Related types:
| Type | Role |
|---|---|
EditorEvent |
Base interface for built-in and custom editor events. |
UploadAssetSourceType |
Describes the upload asset source that invoked onUpload. |
MimeType |
Provides Android constants such as MimeType.PDF. |
Next Steps#
- Automation Actions - build a complete editor-driven automation flow with callbacks and custom events.
- To PDF - customize PDF export behavior from the editor.
- UI Events - observe editor events and callback lifecycle details.