Search Docs
Loading...
Skip to content

Assets

Understand the asset system on Android, including how CE.SDK models asset data, exposes assets through sources, and turns those assets into blocks in a scene.

5 mins
estimated time
GitHub

Images, videos, audio, fonts, stickers, and templates are all assets in CE.SDK. The Android engine gets access to them through asset sources. When you apply an asset, CE.SDK creates or updates a block so that the asset becomes visible in the scene.

The example accepts license: String?. Pass null to run in evaluation mode during development, then replace it with your production key when you wire the code into your app.

This guide covers the core concepts of the asset system. For a concrete media workflow, see the Images guide. For related concepts, see Blocks and Resources.

Assets vs Blocks#

Assets are content definitions with metadata such as URIs, dimensions, tags, and grouping information. They exist outside the scene tree. Blocks are the visual elements in the scene that render or reference that content.

When you apply an asset, CE.SDK creates a block configured from the asset metadata or updates an existing block with new asset data. Multiple blocks can reuse the same asset definition, and an asset can exist in a source without being used in the scene yet.

The Asset Data Model#

On Android, findAssets() returns Asset objects and local sources accept AssetDefinition objects. They share the same core ideas: IDs, localized labels, tags, groups, structured payload data, and meta entries that describe how the asset should be handled.

Asset(
id = "imgly-logo",
context = AssetContext(sourceId = sourceId),
label = "IMG.LY Logo",
locale = "en",
tags = listOf("logo", "brand", "header"),
groups = listOf("logos"),
meta = mapOf(
"uri" to "https://img.ly/static/ubq_samples/imgly_logo.jpg",
"thumbUri" to "https://img.ly/static/ubq_samples/imgly_logo.jpg",
"mimeType" to "image/jpeg",
"kind" to "image",
"blockType" to DesignBlockType.Graphic.key,
"fillType" to FillType.Image.key,
"shapeType" to ShapeType.Rect.key,
"width" to "640",
"height" to "320",
),
),

Key properties include:

  • id for the stable asset identifier.
  • context for the sourceId that produced the asset.
  • label and locale for localized display text.
  • tags and groups for search and filtering.
  • meta for content-specific fields such as uri, thumbUri, mimeType, blockType, fillType, shapeType, width, and height.
  • payload for structured values such as colors, typefaces, source sets, or transform presets when plain string metadata is not enough.

Asset Sources#

Asset sources provide assets to the editor and the engine APIs. On Android, a custom source subclasses AssetSource and implements at least findAssets(query) and getGroups().

override suspend fun getGroups(): List<String>? = brandedAssets.flatMap { it.groups.orEmpty() }.distinct()
override suspend fun findAssets(query: FindAssetsQuery): FindAssetsResult {
val searchQuery = query.query
val queryGroups = query.groups.orEmpty()
val filteredAssets = brandedAssets.filter { asset ->
val matchesQuery =
searchQuery.isNullOrBlank() ||
buildList {
asset.label?.let(::add)
addAll(asset.tags.orEmpty())
}.any { value ->
value.contains(searchQuery, ignoreCase = true)
}
val matchesGroups =
queryGroups.isEmpty() ||
asset.groups.orEmpty().any(queryGroups::contains)
matchesQuery && matchesGroups
}
val startIndex = query.page * query.perPage
val pageAssets = filteredAssets.drop(startIndex).take(query.perPage)
val nextPage =
if (startIndex + pageAssets.size < filteredAssets.size) {
query.page + 1
} else {
-1
}
return FindAssetsResult(
assets = pageAssets,
currentPage = query.page,
nextPage = nextPage,
total = filteredAssets.size,
)
}
override suspend fun fetchAsset(
id: String,
options: FetchAssetOptions,
): Asset? = brandedAssets.firstOrNull { it.id == id }

The FindAssetsQuery object contains paging, text search, sorting, tag, and group filters. Your source responds with a FindAssetsResult that contains the assets for the requested page, the total match count, and nextPage, which is -1 when there are no more results.

Sources can also expose supportedMimeTypes, credits, license, fetchAsset(), and custom applyAsset() behavior when you need more than the default block creation logic.

Querying Assets#

Use engine.asset.findAssets() to search a source. Android pages are zero-based, so the first request uses page = 0.

val queriedAssets = engine.asset.findAssets(
sourceId = source.sourceId,
query = FindAssetsQuery(
perPage = 10,
page = 0,
query = "logo",
groups = listOf("logos"),
),
)
val queriedAsset = queriedAssets.assets.first()
val groups = engine.asset.getGroups(sourceId = source.sourceId)
println("Found ${queriedAssets.total} assets in groups $groups")

This is the point where you typically combine free-text search with groups, tags, or sorting. You can also call engine.asset.getGroups() to inspect the filters that a source exposes before you build your own asset browser UI.

Applying Assets#

Use engine.asset.applyAssetSourceAsset() when you want the source’s custom apply behavior. If the source does not override applyAsset(), CE.SDK falls back to defaultApplyAsset() and creates a block from the asset’s meta fields.

val appliedBlock = engine.asset.applyAssetSourceAsset(
sourceId = source.sourceId,
asset = queriedAsset,
)
if (appliedBlock != null) {
engine.block.setPositionX(appliedBlock, 64F)
engine.block.setPositionY(appliedBlock, 64F)
}

That block can then be positioned, resized, or otherwise modified through the regular block APIs.

Local Asset Sources#

Local asset sources keep their assets in memory and are ideal for uploads, generated media, or app-specific catalogs that you construct at runtime.

engine.asset.addLocalSource(
sourceId = "my-local-images",
supportedMimeTypes = listOf("image/jpeg"),
)
val localAsset = AssetDefinition(
id = "sunrise-poster",
label = mapOf("en" to "Sunrise Poster"),
tags = mapOf("en" to listOf("poster", "sunrise", "brand")),
groups = listOf("posters"),
meta = mapOf(
"uri" to "https://img.ly/static/ubq_samples/sample_1.jpg",
"thumbUri" to "https://img.ly/static/ubq_samples/sample_1.jpg",
"mimeType" to "image/jpeg",
"kind" to "image",
"blockType" to DesignBlockType.Graphic.key,
"fillType" to FillType.Image.key,
"shapeType" to ShapeType.Rect.key,
"width" to "1080",
"height" to "1080",
),
)
engine.asset.addAsset(sourceId = "my-local-images", asset = localAsset)
engine.asset.assetSourceContentsChanged(sourceId = "my-local-images")

AssetDefinition uses localized label and tags maps, while meta carries the URI, MIME type, and block creation hints that defaultApplyAsset() needs later on.

Source Events#

The asset API exposes Flow<String> streams for source lifecycle changes. These are useful when your UI needs to refresh its filters or grid contents after sources are added, removed, or updated.

sourceEventJobs += engine.asset.onAssetSourceAdded()
.onEach { println("Asset source added: $it") }
.launchIn(this)
sourceEventJobs += engine.asset.onAssetSourceRemoved()
.onEach { println("Asset source removed: $it") }
.launchIn(this)
sourceEventJobs += engine.asset.onAssetSourceUpdated()
.onEach { println("Asset source updated: $it") }
.launchIn(this)

After mutating a source, call engine.asset.assetSourceContentsChanged(sourceId) so subscribers know they should re-query the source.

Next Steps#

  • Blocks - Learn about design blocks that display assets
  • Resources - Understand how CE.SDK loads external files