Skip to content

Resources

Where to put your API key, your glasses content (M2Image, M2Font, AR meshes, sounds), and your phone-UI assets — and what build steps and resolver code each platform needs. Pure rules. Pick your project type and follow the recipe.

At-a-glance

Your project API key (sdk.key / app.key) Glasses content (M2Image, M2Font, AR .obj/.png) Phone-UI assets Build script Resolver
Native Android app/src/main/assets/sdk.key app/src/main/assets/<your-path> app/src/main/res/... (R.drawable.foo) None Don't add one
Native iOS (SPM) App bundle root (Xcode → "Copy Bundle Resources") App bundle root or folder reference (Xcode → "Copy Bundle Resources") Assets.xcassets, UIImage(named:) One Xcode Run Script (rsync, see iOS section) Don't add one
KMP Compose composeApp/src/commonMain/composeResources/files/sdk.key composeApp/src/commonMain/composeResources/files/<your-path> composeApp/src/commonMain/composeResources/{drawable,font,values}/... (Res.drawable.foo) Append :composeApp:syncComposeResourcesForIos to the iOS Run Script (or use CocoaPods which handles it) Yes — register one resolver, see KMP section

That's the whole rule set. The rest of this page is the per-platform recipe.


Native Android

Where to put files

Kind Location
API key app/src/main/assets/sdk.key (or app.key)
Glasses content app/src/main/assets/<your-path> (e.g. assets/files/images/apple.png)
Phone-UI assets app/src/main/res/... accessed via R.drawable.foo / painterResource(R.drawable.foo)

Initialize the SDK

MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Evs.init(applicationContext)
        // Do NOT register an IM2ResourcesResolver. The SDK reads from assets/ directly.
        setContent { /* your UI */ }
    }
    override fun onDestroy() { Evs.stop(); super.onDestroy() }
}

Don't

  • Don't register an IM2ResourcesResolver. It's redundant on native Android.
  • Don't put glasses content under res/ — only under assets/.

Native iOS

Where to put files

Kind Location
API key iOS app bundle root: drop sdk.key into the iOS target → "Copy Bundle Resources"
Glasses content iOS app bundle: drop into the target → "Copy Bundle Resources". Use folder references (blue folders) to keep sub-paths so <App>.app/files/images/foo.png works
Phone-UI assets Standard iOS — Assets.xcassets, UIImage(named:), NSLocalizedString

Required Xcode Run Script (one-time setup)

In Xcode → your app target → Build Phases → click +New Run Script Phase. Name it Copy Maverick AI Compose Resources and place it after "Copy Bundle Resources":

for FW in "${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Frameworks/"*.framework; do
    if [ -d "$FW/compose-resources" ]; then
        rsync -av "$FW/compose-resources" \
            "${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/"
    fi
done

In the Run Script's settings, uncheck "Based on dependency analysis" (or in the pbxproj add alwaysOutOfDate = 1; to the script phase). This silences a Xcode warning and is harmless — rsync is idempotent.

Initialize the SDK

ViewController.swift
import MaverickAI

Evs.shared.doInit()
// Do NOT register an IM2ResourcesResolver. The SDK reads from the bundle directly.

Don't

  • Don't register an IM2ResourcesResolver. It's redundant on native iOS.
  • Don't skip the Run Script — without it, calling Evs.shared.showUI(...) will throw MissingResourceException ... compose-resources/....

KMP Compose Multiplatform

Where to put files

Kind Location
API key composeApp/src/commonMain/composeResources/files/sdk.key. For different keys per app store: composeApp/src/androidMain/assets/sdk.key + composeApp/src/iosMain/resources/sdk.key.
Glasses content composeApp/src/commonMain/composeResources/files/<your-path> (e.g. composeResources/files/images/apple.png, composeResources/files/fonts/foo.evfn, composeResources/files/obj_files/earth/earth.obj)
Phone-UI assets composeApp/src/commonMain/composeResources/{drawable,font,values}/..., accessed via painterResource(Res.drawable.foo) / stringResource(Res.string.foo)

iOS build step

In your existing Compile Kotlin Framework Xcode Run Script, append :composeApp:syncComposeResourcesForIos:

cd "$SRCROOT/.."
./gradlew \
    :composeApp:embedAndSignAppleFrameworkForXcode \
    :composeApp:syncComposeResourcesForIos

If your project uses CocoaPods (kotlin("native.cocoapods")), the [CP] Copy Pods Resources build phase already handles this — no manual addition needed.

Required resolver (one-time setup)

Register exactly one IM2ResourcesResolver immediately after Evs.init(...) on each platform. Identical body in androidMain and iosMain:

@OptIn(ExperimentalResourceApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Evs.init(applicationContext)
    Evs.resourcesService.setResourcesResolver(object : IM2ResourcesResolver {
        override fun loadResource(path: String): ByteArray? = try {
            runBlocking { Res.readBytes("files/$path") }
        } catch (e: Exception) { null }
    })
    setContent { /* your UI */ }
}
@OptIn(ExperimentalResourceApi::class)
fun MainViewController(): UIViewController {
    Evs.init()
    Evs.resourcesService.setResourcesResolver(object : IM2ResourcesResolver {
        override fun loadResource(path: String): ByteArray? = try {
            runBlocking { Res.readBytes("files/$path") }
        } catch (e: Exception) { null }
    })
    return ComposeUIViewController { App() }
}

Res is your app's generated <your-app-package>.generated.resources.Res. The files/ prefix is required.

Do

  • Put each file once in commonMain/composeResources/files/... and use it from both platforms.
  • Use the same resolver one-liner on both source sets.

Don't

  • Don't add sourceSets["main"].assets.srcDirs("src/commonMain/composeResources/files") to composeApp/build.gradle.kts. It is a workaround for an outdated resolver pattern; if you have it, remove it.
  • Don't add a custom Xcode Run Script that dittos commonMain/composeResources/files into <App>.app/files/. Same workaround. Remove it.
  • Don't write a resolver that hand-builds paths like compose-resources/composeResources/com.everysight.mav2.sdk.generated.resources/.... That points at the SDK's package, not yours; it will not find your files.
  • Don't skip :composeApp:syncComposeResourcesForIos (unless you're using CocoaPods, which handles it). Without it your own Res.drawable.* and the SDK's UI both fail on iOS.

Troubleshooting

Symptom Likely cause Fix
MissingResourceException ... compose-resources/... (native iOS) rsync Run Script missing or in the wrong order Add the Run Script from the Native iOS section after "Copy Bundle Resources"
MissingResourceException ... compose-resources/... (KMP iOS) syncComposeResourcesForIos not invoked Append :composeApp:syncComposeResourcesForIos to the Xcode Run Script (or use CocoaPods)
API key not found / authentication failure (KMP) Resolver not installed, or installed in the wrong place Install the resolver from the KMP section right after Evs.init(...) on both platforms
M2Image / M2Font shows nothing on the glasses (KMP) Same as above Same as above
Xcode warning "Run script build phase ... will be run during every build because it does not specify any outputs" Resolved Uncheck "Based on dependency analysis" on the Run Script (or set alwaysOutOfDate = 1; in pbxproj). The script is idempotent and intentionally always runs.
Files in iosMain/resources/foo.png not found by Swift UIImage(named:) Files placed there land at <App>.app/compose-resources/foo.png, not the bundle root Either use Bundle.main.url(forResource: "foo", withExtension: "png", subdirectory: "compose-resources"), or move the file into the Xcode project under "Copy Bundle Resources"

See Also