Search Docs
Loading...
Skip to content

To v1.77

This guide covers what changed for iOS in v1.77: an asset-source registration migration, and new structured engine error codes. Both are described below.

Asset sources#

Version 1.77 moves asset-source registration out of the engine binding and updates the default asset content. As part of this update, several built-in asset source IDs were renamed or merged.

Two things change for your iOS app:

  • The Engine.addDefaultAssetSources(...) and Engine.addDemoAssetSources(...) helpers, the Engine.DefaultAssetSource and Engine.DemoAssetSource enums, and the Engine.assetBaseURL constant are deprecated. Register sources directly with engine.asset.addLocalAssetSourceFromJSON(_:matcher:).
  • Because the default base URL now serves the updated content, the deprecated helpers can no longer load the renamed or merged source IDs. Those sources are skipped silently, so the affected asset-library panels appear empty until you migrate.

Do I need to migrate?#

You are affected if any of the following apply:

  • You call engine.addDefaultAssetSources() or engine.addDemoAssetSources().
  • You reference a built-in source by one of the renamed IDs in the table below.
  • You self-host the CE.SDK assets.

If you never registered asset sources yourself and do not self-host, the Starter Kits already register the current sources for you—bump the SDK and you are done.

Asset Source ID Changes#

Renamed sources#

Old ID (up to v1.76)New ID (v1.77+)
ly.img.vectorpathly.img.vector.shape
ly.img.colors.defaultPalettely.img.color.palette
ly.img.textComponentsly.img.text.components

Merged sources#

Old IDs (up to v1.76)New ID (v1.77+)Notes
ly.img.filter.lut + ly.img.filter.duotonely.img.filterA single source now covers LUT and duotone filters

Newly registered sources#

The default starter kits now register three text sources from the CDN. ly.img.text replaces the previous in-app programmatic text source (ly.img.asset.source.text):

  • ly.img.text—plain text presets (title, headline, body).
  • ly.img.text.styles—decorative text styles.
  • ly.img.text.curves—curved text presets.

Scenario A: You use the default asset library#

If you relied on addDefaultAssetSources or addDemoAssetSources (directly, or through a pre-v1.73 solution view), replace those calls with explicit addLocalAssetSourceFromJSON registrations that use the new IDs.

Before#

try await engine.addDefaultAssetSources()
try await engine.addDemoAssetSources()

Now#

let baseURL = URL(string: "https://cdn.img.ly/packages/imgly/cesdk-swift/1.77.1/assets")!
// Default content sources, plus the demo image source.
for id in [
"ly.img.sticker",
"ly.img.vector.shape",
"ly.img.filter",
"ly.img.color.palette",
"ly.img.effect",
"ly.img.blur",
"ly.img.typeface",
"ly.img.crop.presets",
"ly.img.page.presets",
"ly.img.text",
"ly.img.text.styles",
"ly.img.text.curves",
"ly.img.text.components",
"ly.img.image",
] {
let contentURL = baseURL.appendingPathComponent(id).appendingPathComponent("content.json")
_ = try await engine.asset.addLocalAssetSourceFromJSON(contentURL)
}
try engine.asset.addLocalSource(
sourceID: "ly.img.image.upload",
supportedMimeTypes: ["image/jpeg", "image/png", "image/svg+xml", "image/gif", "image/apng", "image/bmp"],
)
// A video editor also registers the video and audio sources (content + uploads):
for id in ["ly.img.video", "ly.img.audio"] {
let contentURL = baseURL.appendingPathComponent(id).appendingPathComponent("content.json")
_ = try await engine.asset.addLocalAssetSourceFromJSON(contentURL)
}
try engine.asset.addLocalSource(
sourceID: "ly.img.video.upload",
supportedMimeTypes: ["video/mp4", "video/quicktime"],
)
try engine.asset.addLocalSource(
sourceID: "ly.img.audio.upload",
supportedMimeTypes: ["audio/mpeg", "audio/mp4", "audio/wav", "audio/x-wav", "audio/ogg", "audio/aac"],
)

If you use a Starter Kit, this registration already lives in the defaultLoadAssetSources callback in OnCreate+<Solution>.swift and is updated for you. See Serve Assets for the complete, current source list and registration reference.

Scenario B: You self-host your assets#

If you serve the assets from your own location, download the updated asset bundle and point your base URL at it:

  1. Download https://cdn.img.ly/packages/imgly/cesdk-swift/1.77.1/imgly-assets.zip and copy the assets/ directory to your hosting location.
  2. Update your baseURL to your hosted path.
  3. Register the renamed and newly added source IDs from the tables above. The old IDs no longer resolve.

Why is my asset library empty or showing “Cannot connect to service”?#

After upgrading, an empty shapes, filter, color-palette, or text panel means a source ID no longer resolves at the base URL. This happens when:

  • The deprecated addDefaultAssetSources or addDemoAssetSources helpers requested an old ID (for example ly.img.vectorpath) that the CDN no longer serves. Register the new ID instead, following Scenario A.
  • You self-host and still serve content from v1.76 or earlier. Serve the updated assets and register the new IDs, following Scenario B.

Engine error codes#

Engine errors now carry a stable catalog code, a developer-facing hint, typed args, and an optional docs anchor. Existing code that reads localizedDescription keeps working; new code can branch on the stable code.

Engine APIs throw NSError for Objective-C interop (no change from before). The NSError.domain ("ly.img", exposed as the EngineErrorDomain constant) and code (0) are unchanged; the NSError.userInfo now carries the structured payload additively. The catalog hint and docs URL ride on Foundation’s standard slots — localizedRecoverySuggestion (the “what to do next” hint) and helpAnchor (the fully-qualified docs URL) — so plain-NSError consumers such as Apple frameworks and loggers pick them up without the wrapper. The remaining structured fields — code, category, args, and silent — are read through EngineError.

EngineError bridges from the thrown NSError, so you can catch it directly with a typed catch and branch on the stable catalog code. Errors from other domains skip the typed catch and propagate unchanged:

import IMGLYEngine
do {
try await engine.scene.create()
} catch let engineError as EngineError {
switch EngineErrorCode(rawValue: engineError.code) {
case .sceneNotValid:
toast.show("No scene is loaded.")
default:
// Any code you don't handle explicitly (including unrecognized ones, which map to nil)
// — fall back to localizedDescription.
toast.show(engineError.localizedDescription)
}
if let url = engineError.docsURL {
UIApplication.shared.open(url)
}
}

EngineErrorCode is a String-backed enum: construct it with EngineErrorCode(rawValue: engineError.code) and branch on cases such as .sceneNotValid. The code itself stays a plain string, so an unrecognized or future code maps to nil and never breaks your build — always keep a default branch.

In positions where you receive an untyped Error value rather than a catch clause — for example the error delivered to an AsyncThrowingStream consumer or a completion callback — wrap it with the failable initializer instead: if let engineError = EngineError(error) { … }. It returns nil for errors from other domains.

NSError.code stays 0; the stable identifier is the string EngineError.code. Branch on that rather than the numeric NSError.code.

What is not a breaking change#

  • localizedDescription still returns the engine’s rendered English string, so existing logging keeps working.
  • The change is additive — every previous error-handling pattern still works.

What might surprise you#

  • Trailing newlines are gone. localizedDescription no longer carries the trailing "\n" that the engine’s internal getMessage() added for log formatting. Code that explicitly trimmed it still works; code that depended on it being there will not.
  • code is an append-only contract. Existing codes are never renamed or repurposed, and new codes are added over time — which is why you should always keep a default branch. Generic failures wrapped from third-party libraries surface under a catch-all code such as UTILS.STD_EXPECTED_STRING_ERROR.
  • silent: true flags errors the catalog marks as expected limitations — programmatically observable but suppressed from logs.