Manage external media files—images, videos, audio, and fonts—that blocks reference via URIs in CE.SDK.
Resources are external media files that blocks reference through URI properties like fill/image/imageFileURI or fill/video/fileURI. CE.SDK loads resources automatically when needed, but you can preload them for better performance. When working with transient resources whose data would be lost during serialization, upload their data and relocate them to permanent URLs before saving. If resource URLs change, you can update the mappings without modifying scene data.
This guide covers on-demand and preloaded resource loading, identifying transient resources, relocating them to permanent URLs before serialization, and discovering all media URIs in a scene.
| Method | Category | Purpose |
|---|---|---|
engine.block.forceLoadResources(blocks=_) | Preloading | Load resources for blocks and their children |
engine.block.forceLoadAVResource(block=_) | Preloading | Load audio or video resource data for a block |
engine.block.getAVResourceTotalDuration(block=_) | Properties | Get the duration of an audio or video resource |
engine.block.getVideoWidth(videoFill=_) | Properties | Get the width of a loaded video resource |
engine.block.getVideoHeight(videoFill=_) | Properties | Get the height of a loaded video resource |
engine.editor.findAllTransientResources() | Discovery | Find resources whose data would be lost during serialization |
engine.editor.getResourceData(uri=_, chunkSize=_, onData=_) | Discovery | Read resource bytes in chunks before uploading |
engine.editor.findAllMediaURIs() | Discovery | List serializable media URIs referenced in the scene |
engine.block.findAllUnused() | Cleanup | Find detached blocks before relocating or destroying resources |
engine.editor.getMimeType(uri=_) | Discovery | Detect the MIME type of a resource |
engine.editor.relocateResource(currentUri=_, relocatedUri=_) | Management | Update URI mappings after assets move |
engine.scene.saveToString(scene=_, allowedResourceSchemes=_) | Serialization | Save the scene after transient resources are relocated |
On-Demand Loading#
The engine fetches resources automatically when rendering blocks or preparing exports. This approach requires no extra code but may delay the first render while assets download.
val imageBlock = engine.block.create(DesignBlockType.Graphic)val imageFill = engine.block.createFill(FillType.Image)engine.block.setShape(imageBlock, shape = engine.block.createShape(ShapeType.Rect))engine.block.setPositionX(imageBlock, value = 30F)engine.block.setPositionY(imageBlock, value = 30F)engine.block.setWidth(imageBlock, value = 300F)engine.block.setHeight(imageBlock, value = 200F)
val imageUri = Uri.parse("https://img.ly/static/ubq_samples/sample_4.jpg")engine.block.setUri( block = imageFill, property = "fill/image/imageFileURI", value = imageUri,)engine.block.setFill(block = imageBlock, fill = imageFill)engine.block.setContentFillMode(block = imageBlock, mode = ContentFillMode.COVER)engine.block.appendChild(parent = page, child = imageBlock)When you create a graphic block with an image fill, the engine downloads that image only when the block is needed for rendering or export.
Preloading Resources#
Load resources before they are needed with forceLoadResources(). Pass the scene to preload everything in that scene, pass an empty list to load every resource currently known to the engine, or pass a smaller set of blocks to control the load order.
// Preload every resource referenced by the scene and its children.engine.block.forceLoadResources(blocks = listOf(scene))
// Pass an empty list to preload all resources currently known to the engine.engine.block.forceLoadResources(blocks = emptyList())
// Or preload only the blocks whose resources are needed next.val graphics = engine.block.findByType(DesignBlockType.Graphic)engine.block.forceLoadResources(blocks = graphics)Use this when you want a scene fully ready before showing it to users or before starting an export workflow.
Preloading Audio and Video#
Audio and video resources require forceLoadAVResource() for full metadata access. The engine needs to download and parse the media file before you query properties like duration or dimensions.
val videoBlock = engine.block.create(DesignBlockType.Graphic)val videoFill = engine.block.createFill(FillType.Video)engine.block.setShape(videoBlock, shape = engine.block.createShape(ShapeType.Rect))engine.block.setPositionX(videoBlock, value = 350F)engine.block.setPositionY(videoBlock, value = 30F)engine.block.setWidth(videoBlock, value = 300F)engine.block.setHeight(videoBlock, value = 200F)val videoUri = Uri.parse("https://img.ly/static/ubq_video_samples/bbb.mp4")engine.block.setUri( block = videoFill, property = "fill/video/fileURI", value = videoUri,)engine.block.setFill(block = videoBlock, fill = videoFill)engine.block.setContentFillMode(block = videoBlock, mode = ContentFillMode.COVER)engine.block.appendChild(parent = page, child = videoBlock)
engine.block.forceLoadAVResource(block = videoFill)
val duration = engine.block.getAVResourceTotalDuration(block = videoFill)val videoWidth = engine.block.getVideoWidth(videoFill = videoFill)val videoHeight = engine.block.getVideoHeight(videoFill = videoFill)Without preloading, methods like getAVResourceTotalDuration(), getVideoWidth(), and getVideoHeight() may return zero or incomplete values.
Finding Transient Resources#
Transient resources are scene resources whose data would be lost during scene serialization. Use findAllTransientResources() to discover them before saving.
// No preload call is required; this inspects resource references that cannot be serialized.val transientResources = engine.editor.findAllTransientResources()Each pair contains the resource Uri and its size in bytes. In this example, a generated image fill uses a buffer URI, so the scene reports a transient resource that must be uploaded or otherwise persisted.
Finding Media URIs#
Get all serializable media URIs referenced in the scene with findAllMediaURIs(). This returns a deduplicated list of valid http://, https://, and file:// media URIs from image, video, audio, and other media sources.
val mediaUris = engine.editor.findAllMediaURIs()val persistentMediaUris = mediaUris.filter { it.scheme in listOf("http", "https", "file") }Transient buffer resources are intentionally excluded, which makes this API useful for building a manifest of assets that already exist in persistent storage.
Finding Unused Blocks#
Once a scene has gone through several edits, it can accumulate blocks that are no longer attached to any scene. These dangling blocks still hold references to images, videos, and audio resources. Use findAllUnused to enumerate them so you can free the memory or skip relocating their resources.
val unusedBlock = engine.block.create(DesignBlockType.Graphic)val unusedBlocks = engine.block.findAllUnused()check(unusedBlock in unusedBlocks)unusedBlocks.forEach { engine.block.destroy(it) }Pair this with findAllMediaURIs() to skip relocating resources for blocks that are no longer reachable, or call destroy() on each block to free memory before saving.
Detecting MIME Types#
Determine a resource’s content type with getMimeType(). The engine downloads the resource if it is not already cached.
val mimeType = engine.editor.getMimeType(uri = imageUri)Common return values include image/jpeg, image/png, video/mp4, and audio/mpeg.
Relocating Resources#
Update URL mappings when resources move with relocateResource(). This changes the URI associated with a resource so the scene can keep working after you upload data to a CDN or migrate assets between storage locations.
val relocatedImageUri = Uri.parse("https://img.ly/static/ubq_samples/sample_1.jpg")engine.editor.relocateResource( currentUri = imageUri, relocatedUri = relocatedImageUri,)Relocation lets you keep working with the existing scene graph while switching resource access over to permanent URLs.
Persisting Transient Resources#
Android exposes saveToString() with allowedResourceSchemes. Persist transient resources by reading their bytes with getResourceData(), uploading those bytes, calling relocateResource() with the returned permanent URI, and then serializing the scene with only the schemes you want to allow.
val relocatedResources = transientResources.map { (transientUri, _) -> val resourceBytes = ByteArrayOutputStream() engine.editor.getResourceData( uri = transientUri, chunkSize = 64 * 1024, ) { chunk -> val copy = chunk.duplicate() val bytes = ByteArray(copy.remaining()) copy.get(bytes) resourceBytes.write(bytes) true }
val permanentUri = uploadTransientResourceToPermanentStorage( sourceUri = transientUri, data = resourceBytes.toByteArray(), ) engine.editor.relocateResource( currentUri = transientUri, relocatedUri = permanentUri, ) transientUri to permanentUri }
val remainingTransientResources = engine.editor.findAllTransientResources()val sceneString = engine.scene.saveToString( scene = scene, allowedResourceSchemes = listOf("http", "https"), )The sample upload helper stands in for your app’s storage client and must return the URI of the uploaded bytes.
private suspend fun uploadTransientResourceToPermanentStorage( sourceUri: Uri, data: ByteArray,): Uri { check(data.isNotEmpty()) { "Cannot upload an empty resource." }
// Upload the bytes with your app's storage client here, then return its permanent URI. // This sample only creates a placeholder URL so the guide can focus on the CE.SDK flow. val fileName = sourceUri .lastPathSegment ?.takeIf { it.isNotBlank() } ?: "transient-resource-${data.size}" return Uri.parse("https://your-storage.example/uploads/$fileName")}If any transient URI remains in the scene, saveToString() throws because the serialized scene would reference data that cannot be restored later.
Troubleshooting#
- Slow initial render: Preload resources with
forceLoadResources()before showing the scene or starting an export. - Video metadata returns
0: Load the video resource withforceLoadAVResource()before querying duration or dimensions. - Unexpected transient resources: Call
findAllTransientResources()after paste, capture, or buffer workflows to see what still needs persistence. saveToString()fails: Relocate every transient URI to a supported scheme such ashttpsbefore serializing the scene.
Next Steps#
- Buffers — Work with in-memory data
- Scenes — Understand scene serialization and persistence
- Export — Explore export options, supported formats, and configuration features for sharing or rendering output.
- Assets — Learn how assets provide external content to CE.SDK designs and how asset sources make them available programmatically.