Skip to content

Releases: minigame-labs/migo-runtime

v0.9.10

Choose a tag to compare

@github-actions github-actions released this 26 Sep 14:33
a2d2352

Runtime SDKs for Android, Linux, OpenHarmony, Windows, iOS and macOS.

What changed in v0.9.10

Fixed

  • Android C ABI: JPEG images still failed to decode after v0.9.9's fix -- Skia,
    as this engine links it, decodes PNG but not JPEG, and the Java SDK's
    BitmapFactory fallback is out of a C host's reach. The C ABI package now
    carries the Rust image decoders every other platform's C ABI already has; the
    Java SDK's AAR is unchanged. Found by migo-conformance's new image-decode
    bundle, which runs every decode path on both Android embeddings.

Assets

File Size What it is
migo-0.9.10-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.10-android.aar 33 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.10-apple-sdk.zip 330 MB Swift package for iOS (Performance+) and macOS (V8) -- unzip and add as a local package
migo-0.9.10-capi-android-arm64.tar.gz 79 MB C ABI SDK for android-arm64 -- headers, library, CMake package
migo-0.9.10-capi-android-x86_64.tar.gz 76 MB C ABI SDK for android-x86_64 -- headers, library, CMake package
migo-0.9.10-capi-linux-arm64.tar.gz 69 MB C ABI SDK for linux-arm64 -- headers, library, CMake package
migo-0.9.10-capi-linux-x86_64.tar.gz 69 MB C ABI SDK for linux-x86_64 -- headers, library, CMake package
migo-0.9.10-capi-ohos-arm64.tar.gz 90 MB C ABI SDK for ohos-arm64 -- headers, library, CMake package
migo-0.9.10-capi-ohos-x86_64.tar.gz 88 MB C ABI SDK for ohos-x86_64 -- headers, library, CMake package
migo-0.9.10-capi-windows-arm64.tar.gz 27 MB C ABI SDK for windows-arm64 -- headers, library, CMake package
migo-0.9.10-capi-windows-x86_64.tar.gz 27 MB C ABI SDK for windows-x86_64 -- headers, library, CMake package
migo-0.9.10-jni-android-arm64.tar.gz 16 MB see the file
migo-0.9.10-jni-android-x86_64.tar.gz 16 MB see the file

One AAR is published, carrying both ABIs. A shipped app carries one: add
ndk { abiFilters 'arm64-v8a' } to your defaultConfig and the packaged native
library is about half the size, or publish an App Bundle and Play delivers per device.
There is no separate slim build -- the product profile is an internal build axis, not
a choice an integrator can make.

iOS and macOS

migo-0.9.10-apple-sdk.zip unpacks to MigoApple/, a Swift package: add it in
Xcode with File > Add Package Dependencies > Add Local, then link
MigoApplePerformancePlus (iOS) or MigoMacV8 (macOS) and put a MigoGameView
on screen. MigoApple/README.md has the integration steps. On macOS the app must be
signed with the hardened runtime and com.apple.security.cs.allow-jit, and embed ANGLE
with Frameworks/Scripts/embed-apple-angle.sh; the view refuses to start without the
entitlement and says why.

Verifying a download

SHA256SUMS.txt covers every asset built by CI:

sha256sum -c SHA256SUMS.txt 2>/dev/null | grep -v ': OK$' || echo "all verified"

Every runtime payload also has an artifact-bound <asset>.sbom.cdx.json recording
its SHA-256, exact target/profile and reachable dependency graph. Provenance
<asset>.attestation.json sidecars record package identity; the checksum manifest
covers both payloads and sidecars. scripts/verify-release-assets.sh <tag> checks
that no published asset escapes that coverage.

Source code (zip / tar.gz)

Those two links are generated by GitHub from the tag and cannot be removed. Do not
build from them.
They omit submodules and Git LFS content, so a build from the zip
fails in ways that look like repository corruption. Clone the tag instead:

git clone --branch v0.9.10 --recurse-submodules https://github.com/minigame-labs/migo.git

Integration

See migo-examples for runnable
samples, and BUILD.md
for building from source.

What's Changed

  • The C ABI freeze list records Android performance as done, measured against the Java SDK on the published v0.9.9 by @jmcgill-d in #313
  • The Android C ABI carries the Rust image decoders, so a C host decodes JPEG as well as PNG by @jmcgill-d in #314
  • Release v0.9.10 by @jmcgill-d in #315

Full Changelog: v0.9.9...v0.9.10

v0.9.9

Choose a tag to compare

@github-actions github-actions released this 26 Sep 09:17
c1bddfc

Runtime SDKs for Android, Linux, OpenHarmony, Windows, iOS and macOS.

What changed in v0.9.9

Fixed

  • Android C ABI: images never decoded, so every WebGL game rendered black while
    its frame loop kept running. Android builds leave the Rust image decoders out
    and rely on the Java SDK to register BitmapFactory at load time, which a C
    host never runs. The C ABI now registers Skia's decoders -- straight into an
    AHardwareBuffer where the renderer can import one, into RGBA memory where an
    image must be CPU-backed -- at no binary cost, since Skia is already linked
    for rendering. The Android C host's on-device check now paints its first frame
    from decoded images on both paths, so this cannot pass unnoticed again.

Assets

File Size What it is
migo-0.9.9-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.9-android.aar 33 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.9-apple-sdk.zip 330 MB Swift package for iOS (Performance+) and macOS (V8) -- unzip and add as a local package
migo-0.9.9-capi-android-arm64.tar.gz 73 MB C ABI SDK for android-arm64 -- headers, library, CMake package
migo-0.9.9-capi-android-x86_64.tar.gz 71 MB C ABI SDK for android-x86_64 -- headers, library, CMake package
migo-0.9.9-capi-linux-arm64.tar.gz 69 MB C ABI SDK for linux-arm64 -- headers, library, CMake package
migo-0.9.9-capi-linux-x86_64.tar.gz 69 MB C ABI SDK for linux-x86_64 -- headers, library, CMake package
migo-0.9.9-capi-ohos-arm64.tar.gz 90 MB C ABI SDK for ohos-arm64 -- headers, library, CMake package
migo-0.9.9-capi-ohos-x86_64.tar.gz 88 MB C ABI SDK for ohos-x86_64 -- headers, library, CMake package
migo-0.9.9-capi-windows-arm64.tar.gz 27 MB C ABI SDK for windows-arm64 -- headers, library, CMake package
migo-0.9.9-capi-windows-x86_64.tar.gz 27 MB C ABI SDK for windows-x86_64 -- headers, library, CMake package
migo-0.9.9-jni-android-arm64.tar.gz 16 MB see the file
migo-0.9.9-jni-android-x86_64.tar.gz 16 MB see the file

One AAR is published, carrying both ABIs. A shipped app carries one: add
ndk { abiFilters 'arm64-v8a' } to your defaultConfig and the packaged native
library is about half the size, or publish an App Bundle and Play delivers per device.
There is no separate slim build -- the product profile is an internal build axis, not
a choice an integrator can make.

iOS and macOS

migo-0.9.9-apple-sdk.zip unpacks to MigoApple/, a Swift package: add it in
Xcode with File > Add Package Dependencies > Add Local, then link
MigoApplePerformancePlus (iOS) or MigoMacV8 (macOS) and put a MigoGameView
on screen. MigoApple/README.md has the integration steps. On macOS the app must be
signed with the hardened runtime and com.apple.security.cs.allow-jit, and embed ANGLE
with Frameworks/Scripts/embed-apple-angle.sh; the view refuses to start without the
entitlement and says why.

Verifying a download

SHA256SUMS.txt covers every asset built by CI:

sha256sum -c SHA256SUMS.txt 2>/dev/null | grep -v ': OK$' || echo "all verified"

Every runtime payload also has an artifact-bound <asset>.sbom.cdx.json recording
its SHA-256, exact target/profile and reachable dependency graph. Provenance
<asset>.attestation.json sidecars record package identity; the checksum manifest
covers both payloads and sidecars. scripts/verify-release-assets.sh <tag> checks
that no published asset escapes that coverage.

Source code (zip / tar.gz)

Those two links are generated by GitHub from the tag and cannot be removed. Do not
build from them.
They omit submodules and Git LFS content, so a build from the zip
fails in ways that look like repository corruption. Clone the tag instead:

git clone --branch v0.9.9 --recurse-submodules https://github.com/minigame-labs/migo.git

Integration

See migo-examples for runnable
samples, and BUILD.md
for building from source.

What's Changed

  • Multi-pointer delivery through the Android C ABI runs on a device, driven by an instrumentation APK and read back as pixels by @jmcgill-d in #307
  • The C ABI freeze blockers say what is done: Android packaging ships and runs at API 26, 31 and 34, and every target gates its exports by @jmcgill-d in #308
  • The Android C host can link a published C ABI package through find_package, so the released bytes run on a device by @jmcgill-d in #309
  • The Android C host takes MIGO_CAPI_LOG from a files/log-level setting, so a benchmark can match the Java SDK's WARN console without a rebuild by @jmcgill-d in #310
  • The Android C ABI registers Skia's image decoders, so a C host's games decode images instead of rendering black by @jmcgill-d in #311
  • Release v0.9.9 by @jmcgill-d in #312

Full Changelog: v0.9.8...v0.9.9

v0.9.8

Choose a tag to compare

@github-actions github-actions released this 26 Sep 05:12
ab902ea

Runtime SDKs for Android, Linux, OpenHarmony, Windows, iOS and macOS.

What changed in v0.9.8

Changed

  • The engine now waits up to ten seconds, not two, for the renderer to report
    its GPU capabilities before it runs content. The wait only guards against a
    renderer that has stopped: one that fails reports it immediately, and one
    that comes up is waited for only as long as it takes. At two seconds, a
    slow but healthy first start -- a cold driver shader cache on a low-end
    device, or software rendering on a loaded machine -- was treated as a failure
    and the session refused its content for good.

Fixed

  • Windows: no session could start when a host's files, cache or code-cache
    directory was spelled with .., such as the examples' <files>\..\cache
    ("initialize sandbox filesystem: failed to pin sandbox roots"). Sandbox roots
    were opened in Win32's \\?\ namespace, where .. is a file name rather
    than a step up. A root is now given the meaning Win32 itself gives it before
    it is opened; relative roots are still refused. The Windows arms of the
    sandbox filesystem and the atomic writer now run in CI, which they had never
    done.
  • Linux: the offscreen (headless) target needed a window server after all.
    It asked EGL for the default display, which Mesa resolves to X11, so it
    failed to start wherever DISPLAY was unset -- every CI runner and server.
    It now uses Mesa's surfaceless platform when the driver offers it, and asks
    only for the pbuffer configuration a headless target renders into.
  • iOS and macOS: after migo_surface_release_query reported RELEASED, the
    host's CAMetalLayer could still be alive for a moment, released on the
    render thread just afterwards. Objects ANGLE autoreleased during the surface
    teardown lived until the render loop's pool drained, which came after
    RELEASED. Teardown now drains them before RELEASED is published, on detach,
    on surface replacement and at shutdown.

Assets

File Size What it is
migo-0.9.8-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.8-android.aar 33 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.8-apple-sdk.zip 330 MB Swift package for iOS (Performance+) and macOS (V8) -- unzip and add as a local package
migo-0.9.8-capi-android-arm64.tar.gz 73 MB C ABI SDK for android-arm64 -- headers, library, CMake package
migo-0.9.8-capi-android-x86_64.tar.gz 71 MB C ABI SDK for android-x86_64 -- headers, library, CMake package
migo-0.9.8-capi-linux-arm64.tar.gz 69 MB C ABI SDK for linux-arm64 -- headers, library, CMake package
migo-0.9.8-capi-linux-x86_64.tar.gz 69 MB C ABI SDK for linux-x86_64 -- headers, library, CMake package
migo-0.9.8-capi-ohos-arm64.tar.gz 90 MB C ABI SDK for ohos-arm64 -- headers, library, CMake package
migo-0.9.8-capi-ohos-x86_64.tar.gz 88 MB C ABI SDK for ohos-x86_64 -- headers, library, CMake package
migo-0.9.8-capi-windows-arm64.tar.gz 27 MB C ABI SDK for windows-arm64 -- headers, library, CMake package
migo-0.9.8-capi-windows-x86_64.tar.gz 27 MB C ABI SDK for windows-x86_64 -- headers, library, CMake package
migo-0.9.8-jni-android-arm64.tar.gz 16 MB see the file
migo-0.9.8-jni-android-x86_64.tar.gz 16 MB see the file

One AAR is published, carrying both ABIs. A shipped app carries one: add
ndk { abiFilters 'arm64-v8a' } to your defaultConfig and the packaged native
library is about half the size, or publish an App Bundle and Play delivers per device.
There is no separate slim build -- the product profile is an internal build axis, not
a choice an integrator can make.

iOS and macOS

migo-0.9.8-apple-sdk.zip unpacks to MigoApple/, a Swift package: add it in
Xcode with File > Add Package Dependencies > Add Local, then link
MigoApplePerformancePlus (iOS) or MigoMacV8 (macOS) and put a MigoGameView
on screen. MigoApple/README.md has the integration steps. On macOS the app must be
signed with the hardened runtime and com.apple.security.cs.allow-jit, and embed ANGLE
with Frameworks/Scripts/embed-apple-angle.sh; the view refuses to start without the
entitlement and says why.

Verifying a download

SHA256SUMS.txt covers every asset built by CI:

sha256sum -c SHA256SUMS.txt 2>/dev/null | grep -v ': OK$' || echo "all verified"

Every runtime payload also has an artifact-bound <asset>.sbom.cdx.json recording
its SHA-256, exact target/profile and reachable dependency graph. Provenance
<asset>.attestation.json sidecars record package identity; the checksum manifest
covers both payloads and sidecars. scripts/verify-release-assets.sh <tag> checks
that no published asset escapes that coverage.

Source code (zip / tar.gz)

Those two links are generated by GitHub from the tag and cannot be removed. Do not
build from them.
They omit submodules and Git LFS content, so a build from the zip
fails in ways that look like repository corruption. Clone the tag instead:

git clone --branch v0.9.8 --recurse-submodules https://github.com/minigame-labs/migo.git

Integration

See migo-examples for runnable
samples, and BUILD.md
for building from source.

What's Changed

  • Headless Linux renders on Mesa's surfaceless display, so the presentation gate paints on a runner with no window server by @jmcgill-d in #298
  • read_file's path counters are per thread, so a test sees only its own reads by @jmcgill-d in #300
  • Windows VFS roots take the meaning Win32 gives them before going verbatim, so a root spelled with .. pins by @jmcgill-d in #299
  • Surface teardown drains its autoreleased objects before the lease drops, so RELEASED follows the layer's last release by @jmcgill-d in #301
  • 0.9.7 docs by @jmcgill-d in #302
  • The GPU readiness deadline is a watchdog for a stuck renderer, so it is ten seconds rather than two by @jmcgill-d in #303
  • The docs smoke test asserts the English 0.9 archive is translated and stays in its version, now that it is no longer a stub by @jmcgill-d in #304
  • The hygiene gate exempts the English 0.9 concept page like its three siblings, and matches the hostname as a token by @jmcgill-d in #305
  • Release v0.9.8: Windows sessions start again, headless Linux needs no window server, Change Date 2030-09-26, all eight snapshots regenerated by @jmcgill-d in #306

Full Changelog: v0.9.7...v0.9.8

v0.9.7

Choose a tag to compare

@github-actions github-actions released this 26 Sep 00:39
4ba8bf7

Runtime SDKs for Android, Linux, OpenHarmony, Windows, iOS and macOS.

What changed in v0.9.7

Added

  • iOS and macOS SDK: migo-<version>-apple-sdk.zip, a Swift package with one
    view per platform. MigoGameView (MigoApplePerformancePlus on iOS,
    MigoMacV8 on macOS) takes an installed game and owns everything between it
    and pixels -- engine session, CAMetalLayer, display clock, input, app
    lifecycle, and on iOS the audio session and WebContent crash recovery.
    MigoGameInstaller installs a package atomically and skips a version that is
    already there. Both products ship a privacy manifest that a gate checks
    against the engine's sources in both directions. The zip carries its own
    .attestation.json, like every other SDK archive, and a runnable app for
    each platform is apple-swift/ in migo-examples.

  • iOS and macOS: the soft keyboard. migo.showKeyboard opens the system
    keyboard on iOS and a text field along the game's bottom edge on macOS; the
    player's text comes back as onKeyboardInput/Confirm/Complete. On the
    iOS lane the three keyboard ops became host commands to the same keyboard
    service the embedded runtime calls, so a host with no keyboard refuses them
    in the same words.

  • iOS and macOS: the device. vibrateShort/vibrateLong drive the Taptic
    Engine on iOS; setKeepScreenOn holds the display awake (the idle timer on
    iOS, a power assertion on macOS) and gives it back when the game ends;
    getGameLogManager().log entries reach the app as MigoGameView.Event.gameLog;
    getNetworkType/onNetworkStatusChange follow NWPathMonitor, and on iOS
    getBatteryInfo reports the battery and Low Power Mode. A Mac has nothing to
    vibrate and no battery API a game should need, so those answer "not
    supported" there, as on a device without the hardware.

  • C ABI: device capabilities. Three optional, independent callbacks appended to
    MigoHostCallbacks -- on_vibrate, on_keep_screen_on, on_game_log -- each
    offered to content exactly when installed, and two report functions,
    migo_session_set_network_status and migo_session_set_battery_status,
    whose last report the engine answers content's synchronous reads from and
    forwards a network change while content listens. An older host is
    zero-extended to none of them, which is the previous behaviour.

  • C ABI: MigoEngineConfig.code_signing_public_key, the Ed25519 key signed
    content is verified against. Until now a C ABI host could not supply one, so
    its only configuration that loaded content was
    MIGO_ENGINE_FLAG_ALLOW_UNSIGNED_CONTENT. Appended to the record: a host
    passing the old size is zero-extended to "no key" and behaves as before.
    Setting the key and the unsigned flag together is refused.

  • macOS: a host-owned CAMetalLayer can be attached through the C ABI.
    MIGO_PLATFORM_MACOS_CA_METAL_LAYER now appears in the library's advertised
    attachable kinds, and it appears because an attach ran, not because a backend
    compiled: apple-sdk.yml run 34017950809 built a real CAMetalLayer on a
    hosted macOS runner, carried it through migo_session_attach_surface as
    generation 1, and completed the whole retirement handshake — begin_detach,
    poll to MIGO_SURFACE_RELEASE_RELEASED, migo_surface_release_destroy,
    migo_session_destroy, migo_engine_destroy — before releasing the layer.
    An NSView is refused rather than resolved to a layer, so the host keeps
    ownership of its own drawable. The same run loaded the pinned ANGLE under the
    name the recipe declares and got an EGL display back from it. iOS is
    deliberately not included: its arm of the same module compiles everywhere and
    has attached nothing anywhere.

  • Images with transparency are transcoded to ASTC at package ingest on devices
    whose GPU decodes it, and stay on ETC2 elsewhere. The block footprint is
    chosen per image by what it reconstructs: the encoder grades its own output
    against the source and takes the largest block whose worst channel error stays
    within budget, so a smooth image lands at 0.25 bytes per pixel — a quarter of
    ETC2 RGBA, at higher fidelity — while a sprite with a hard alpha edge stays at
    one byte per pixel rather than losing the edge. Opaque images stay on ETC2 RGB
    everywhere, because at half a byte per pixel it is smaller than any ASTC
    footprint. The choice is per image and per device, which is only possible
    because ingest runs on the device.

  • Apple: ANGLE over Metal is built from source and pinned
    (contracts/artifact-manifest/apple-angle.lock.json +
    scripts/build-angle-apple.sh + scripts/fetch-apple-angle.sh) for every
    slice group the engine is built for — iOS, the iOS simulator and macOS, five
    configurations in all. ANGLE publishes no official prebuilt binaries for any
    platform, so these are self-hosted and hash-verified before use, the same
    model the Windows ANGLE runtime and the V8 archives already follow. It exists
    because there is no GL framework on iOS: rustc's own link line for the Apple
    slices asks for -framework OpenGL on macOS and for no GL framework at all on
    iOS, while Skia is configured for its GL backend. Metal is the only backend
    built; the desktop GL backend, which defaults to on for macOS, is pinned off
    so both Apple platforms resolve the same renderer. The published shape differs
    per platform because upstream's does — a framework bundle on iOS, where Apple
    accepts an embedded framework and rejects a bare dylib, and a shared library
    on macOS — and it is deliberately not evened out: libEGL locates libGLESv2
    at run time by composing a name against a directory, and that name and
    directory are platform-specific, so repackaging either side would leave ANGLE
    searching where its dispatch library is not. --print-loader-layout is what
    answers where each library has to sit; the xcframeworks are split along the
    same axis instead, one per library per platform family.

  • The runtime reports how many times a frame's drawing crossed from JavaScript
    into native, on a five-second window, at info level: [boundary] frames=… crossings/frame=… worst=… commands/frame=… commands/crossing=…. The ratio is
    what a command stream exists to move, and it was previously only observable
    from inside a test.

Changed

  • Canvas2D commands cross the JavaScript/native boundary as a binary command
    stream rather than one op per call, sharing one buffer and one opcode space
    with the WebGL stream so the order between the two survives the crossing
    without a barrier between every pair of commands. A frame that issues three
    hundred 2D calls now crosses once.

Fixed

  • iOS: installing an update over a game that had already run under code
    signing failed on an iPhone ("you don't have permission"): Darwin refuses to
    rename a directory its caller cannot write, and the engine seals the package
    read-only. The installer now restores the owner's write bit on the sealed
    root alone before moving it aside. The simulator's host file system had let
    the rename through.

  • iOS and macOS: the engine's render and session threads ran at the default
    quality-of-service class, so the main thread waiting on the session's
    startup was a priority inversion and the frame work could land on efficiency
    cores. They are now user-interactive; decode and IO threads are utility.

  • iOS: signed content was not verified. The Performance+ lane mounted the
    installed package as it was, so a host that configured a signing key got no
    verification at all. It now runs the embedded execution's launch sequence
    before anything is mounted -- sealed-receipt check, else a full manifest and
    file-hash verification that seals the tree -- and refuses the load on any
    mismatch, or on signing with no key.

  • MigoGameInstaller could not update a game that had run under signing: the
    engine seals a verified tree read-only, and the installer replaced it in
    place. An update now renames the sealed tree aside, renames the new one in
    and removes the old one as a trusted uninstall.

  • iOS: a game that called migo.exitMiniProgram() stopped drawing and the app
    was never told. The external-frame session ended on the request without the
    exit notification the in-process runtime sends; it now sends it.

  • The Apple SDK could not put its iOS and macOS engines in one xcframework:
    assembly required byte-identical header directories, and each group's module
    map lists the frameworks its own archive links. Only the C headers are now
    compared across groups.

  • SBOMs listed crates the shipped build never compiles. cargo metadata
    resolves features for the whole workspace, so a crate any member enabled was
    in every artifact's graph -- the iOS SDK, built without a JavaScript engine,
    would have listed v8. Each SBOM is now cut to its build's own cargo tree.

  • ASTC 8x8 textures upload again. The engine mapped
    VK_FORMAT_ASTC_8x8_UNORM_BLOCK to 0x93B9, which is the token for a 10x6
    block, so glCompressedTexImage2D rejected every such texture with
    GL_INVALID_VALUE. It had never fired because nothing produced ASTC 8x8, and
    the test that covered it asserted the same wrong number, copied from the
    constant it was checking; the tokens are now derived from the block size the
    extension assigns them to.

  • ctx.fillStyle = "transparent" no longer paints opaque black. The keyword was
    missing from the engine's named-colour table, so it fell through to the
    unknown-name branch, which reads black -- the loudest possible wrong answer for
    a keyword whose meaning is "do not paint". strokeStyle and shadowColor had
    the same fault, and gradient colour stops were unaffected.

Assets

File Size What it is
migo-0.9.7-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.7-android.aar 33 MB Android library for Java/Kotlin, arm64-v8a + x86_64
`mig...
Read more

v0.9.7-rc.2

v0.9.7-rc.2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Sep 23:05
7467c2b

Runtime SDKs for Android, Linux, OpenHarmony, Windows, iOS and macOS.

What changed in v0.9.7-rc.2

Added

  • iOS and macOS SDK: migo-<version>-apple-sdk.zip, a Swift package with one
    view per platform. MigoGameView (MigoApplePerformancePlus on iOS,
    MigoMacV8 on macOS) takes an installed game and owns everything between it
    and pixels -- engine session, CAMetalLayer, display clock, input, app
    lifecycle, and on iOS the audio session and WebContent crash recovery.
    MigoGameInstaller installs a package atomically and skips a version that is
    already there. Both products ship a privacy manifest that a gate checks
    against the engine's sources in both directions.

  • iOS and macOS: the soft keyboard. migo.showKeyboard opens the system
    keyboard on iOS and a text field along the game's bottom edge on macOS; the
    player's text comes back as onKeyboardInput/Confirm/Complete. On the
    iOS lane the three keyboard ops became host commands to the same keyboard
    service the embedded runtime calls, so a host with no keyboard refuses them
    in the same words.

  • iOS and macOS: the device. vibrateShort/vibrateLong drive the Taptic
    Engine on iOS; setKeepScreenOn holds the display awake (the idle timer on
    iOS, a power assertion on macOS) and gives it back when the game ends;
    getGameLogManager().log entries reach the app as MigoGameView.Event.gameLog;
    getNetworkType/onNetworkStatusChange follow NWPathMonitor, and on iOS
    getBatteryInfo reports the battery and Low Power Mode. A Mac has nothing to
    vibrate and no battery API a game should need, so those answer "not
    supported" there, as on a device without the hardware.

  • C ABI: device capabilities. Three optional, independent callbacks appended to
    MigoHostCallbacks -- on_vibrate, on_keep_screen_on, on_game_log -- each
    offered to content exactly when installed, and two report functions,
    migo_session_set_network_status and migo_session_set_battery_status,
    whose last report the engine answers content's synchronous reads from and
    forwards a network change while content listens. An older host is
    zero-extended to none of them, which is the previous behaviour.

  • C ABI: MigoEngineConfig.code_signing_public_key, the Ed25519 key signed
    content is verified against. Until now a C ABI host could not supply one, so
    its only configuration that loaded content was
    MIGO_ENGINE_FLAG_ALLOW_UNSIGNED_CONTENT. Appended to the record: a host
    passing the old size is zero-extended to "no key" and behaves as before.
    Setting the key and the unsigned flag together is refused.

  • macOS: a host-owned CAMetalLayer can be attached through the C ABI.
    MIGO_PLATFORM_MACOS_CA_METAL_LAYER now appears in the library's advertised
    attachable kinds, and it appears because an attach ran, not because a backend
    compiled: apple-sdk.yml run 34017950809 built a real CAMetalLayer on a
    hosted macOS runner, carried it through migo_session_attach_surface as
    generation 1, and completed the whole retirement handshake — begin_detach,
    poll to MIGO_SURFACE_RELEASE_RELEASED, migo_surface_release_destroy,
    migo_session_destroy, migo_engine_destroy — before releasing the layer.
    An NSView is refused rather than resolved to a layer, so the host keeps
    ownership of its own drawable. The same run loaded the pinned ANGLE under the
    name the recipe declares and got an EGL display back from it. iOS is
    deliberately not included: its arm of the same module compiles everywhere and
    has attached nothing anywhere.

  • Images with transparency are transcoded to ASTC at package ingest on devices
    whose GPU decodes it, and stay on ETC2 elsewhere. The block footprint is
    chosen per image by what it reconstructs: the encoder grades its own output
    against the source and takes the largest block whose worst channel error stays
    within budget, so a smooth image lands at 0.25 bytes per pixel — a quarter of
    ETC2 RGBA, at higher fidelity — while a sprite with a hard alpha edge stays at
    one byte per pixel rather than losing the edge. Opaque images stay on ETC2 RGB
    everywhere, because at half a byte per pixel it is smaller than any ASTC
    footprint. The choice is per image and per device, which is only possible
    because ingest runs on the device.

  • Apple: ANGLE over Metal is built from source and pinned
    (contracts/artifact-manifest/apple-angle.lock.json +
    scripts/build-angle-apple.sh + scripts/fetch-apple-angle.sh) for every
    slice group the engine is built for — iOS, the iOS simulator and macOS, five
    configurations in all. ANGLE publishes no official prebuilt binaries for any
    platform, so these are self-hosted and hash-verified before use, the same
    model the Windows ANGLE runtime and the V8 archives already follow. It exists
    because there is no GL framework on iOS: rustc's own link line for the Apple
    slices asks for -framework OpenGL on macOS and for no GL framework at all on
    iOS, while Skia is configured for its GL backend. Metal is the only backend
    built; the desktop GL backend, which defaults to on for macOS, is pinned off
    so both Apple platforms resolve the same renderer. The published shape differs
    per platform because upstream's does — a framework bundle on iOS, where Apple
    accepts an embedded framework and rejects a bare dylib, and a shared library
    on macOS — and it is deliberately not evened out: libEGL locates libGLESv2
    at run time by composing a name against a directory, and that name and
    directory are platform-specific, so repackaging either side would leave ANGLE
    searching where its dispatch library is not. --print-loader-layout is what
    answers where each library has to sit; the xcframeworks are split along the
    same axis instead, one per library per platform family.

  • The runtime reports how many times a frame's drawing crossed from JavaScript
    into native, on a five-second window, at info level: [boundary] frames=… crossings/frame=… worst=… commands/frame=… commands/crossing=…. The ratio is
    what a command stream exists to move, and it was previously only observable
    from inside a test.

Changed

  • Canvas2D commands cross the JavaScript/native boundary as a binary command
    stream rather than one op per call, sharing one buffer and one opcode space
    with the WebGL stream so the order between the two survives the crossing
    without a barrier between every pair of commands. A frame that issues three
    hundred 2D calls now crosses once.

Fixed

  • iOS: installing an update over a game that had already run under code
    signing failed on an iPhone ("you don't have permission"): Darwin refuses to
    rename a directory its caller cannot write, and the engine seals the package
    read-only. The installer now restores the owner's write bit on the sealed
    root alone before moving it aside. The simulator's host file system had let
    the rename through.

  • iOS and macOS: the engine's render and session threads ran at the default
    quality-of-service class, so the main thread waiting on the session's
    startup was a priority inversion and the frame work could land on efficiency
    cores. They are now user-interactive; decode and IO threads are utility.

  • iOS: signed content was not verified. The Performance+ lane mounted the
    installed package as it was, so a host that configured a signing key got no
    verification at all. It now runs the embedded execution's launch sequence
    before anything is mounted -- sealed-receipt check, else a full manifest and
    file-hash verification that seals the tree -- and refuses the load on any
    mismatch, or on signing with no key.

  • MigoGameInstaller could not update a game that had run under signing: the
    engine seals a verified tree read-only, and the installer replaced it in
    place. An update now renames the sealed tree aside, renames the new one in
    and removes the old one as a trusted uninstall.

  • iOS: a game that called migo.exitMiniProgram() stopped drawing and the app
    was never told. The external-frame session ended on the request without the
    exit notification the in-process runtime sends; it now sends it.

  • The Apple SDK could not put its iOS and macOS engines in one xcframework:
    assembly required byte-identical header directories, and each group's module
    map lists the frameworks its own archive links. Only the C headers are now
    compared across groups.

  • SBOMs listed crates the shipped build never compiles. cargo metadata
    resolves features for the whole workspace, so a crate any member enabled was
    in every artifact's graph -- the iOS SDK, built without a JavaScript engine,
    would have listed v8. Each SBOM is now cut to its build's own cargo tree.

  • ASTC 8x8 textures upload again. The engine mapped
    VK_FORMAT_ASTC_8x8_UNORM_BLOCK to 0x93B9, which is the token for a 10x6
    block, so glCompressedTexImage2D rejected every such texture with
    GL_INVALID_VALUE. It had never fired because nothing produced ASTC 8x8, and
    the test that covered it asserted the same wrong number, copied from the
    constant it was checking; the tokens are now derived from the block size the
    extension assigns them to.

  • ctx.fillStyle = "transparent" no longer paints opaque black. The keyword was
    missing from the engine's named-colour table, so it fell through to the
    unknown-name branch, which reads black -- the loudest possible wrong answer for
    a keyword whose meaning is "do not paint". strokeStyle and shadowColor had
    the same fault, and gradient colour stops were unaffected.

Assets

File Size What it is
migo-0.9.7-rc.2-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.7-rc.2-android.aar 33 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.7-rc.2-apple-sdk.zip 330 MB Swift package for iOS (Performance+) and macOS (V8) -- unzip and add as a local package
`migo-...
Read more

Skia for Apple, built with skia_gl_standard="" for macOS 11.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 01:49
1c0caff

Built by .github/workflows/apple-skia-binaries.yml from scripts/package-apple-skia-binaries.sh. These are skia-bindings archives for the darwin triples, built from source with the GN argument that lets Skia accept an ANGLE ES context (see scripts/apple-skia-gl-env.sh for why the stock ones cannot) and against the macOS 11.0 deployment floor in contracts/apple/deployment-floor.json.

Skia for Apple, built with skia_gl_standard=""

Choose a tag to compare

@github-actions github-actions released this 11 Sep 15:36
0d5d92c

Built by .github/workflows/apple-skia-binaries.yml from scripts/package-apple-skia-binaries.sh. These are skia-bindings archives for the darwin triples, built from source with the GN argument that lets Skia accept an ANGLE ES context; see scripts/apple-skia-gl-env.sh for why the stock ones cannot.

ANGLE for Apple (52f59428)

Choose a tag to compare

@jmcgill-d jmcgill-d released this 05 Sep 15:27
6edd7fa

ANGLE built from source for every Apple slice group migo's engine is built for.

These are dependency artifacts, not a product release. They exist because ANGLE
(google/angle) publishes no official prebuilt binaries for any platform, so there
is no upstream URL to pin — only a self-built, fully-provenanced archive, the same
position contracts/artifact-manifest/windows-angle.lock.json records for Windows.

Why the engine needs them: there is no GL framework on iOS. rustc's own link line
for each Apple slice says so — macOS answers -framework OpenGL and iOS answers
nothing — and Skia is configured for its GL backend. ANGLE over Metal fills that
gap.

ANGLE revision 52f594287836c9970b67920da0633077aee42649
Built by .github/workflows/apple-angle.yml on macos-15
Pinned by contracts/artifact-manifest/apple-angle.lock.json
Fetched by scripts/fetch-apple-angle.sh (checks sha256 before use)

Backends: Metal only. angle_enable_gl=false is deliberate rather than default —
GL defaults to on for macOS, and leaving it on would let EGL_DEFAULT_DISPLAY
resolve macOS to a desktop GL backend while iOS resolved to Metal, so the two Apple
platforms would not be running the same renderer. Vulkan, WebGPU and the null
backend are off.

Shapes differ by platform because upstream's own template does: angle_shared_library
switches to ios_framework_bundle when is_ios, so iOS ships framework bundles and
macOS ships shared libraries. That is the right split — Apple accepts an embedded
framework in an app and rejects a bare dylib.

How they have to be laid out, which is not a matter of taste. libEGL does not
link libGLESv2 — otool -L names only system frameworks — it opens it at run time
under a name it composes against a directory (libEGL_autogen.cpp:41,
system_utils.cpp:221-234, system_utils_{ios,mac,posix}.cpp at this revision):

where ANGLE looks for its dispatch library
macOS <the directory libEGL was loaded from>/libGLESv2.dylib
iOS / iOS simulator <the app bundle>/Frameworks/libGLESv2.framework/libGLESv2

So the two products go side by side, unpacked as they are. Repackaging the macOS
libraries into framework bundles — the obvious way to get one xcframework holding
every platform, since xcodebuild -create-xcframework refuses to mix frameworks and
libraries — moves libEGL into Versions/A/ and the search follows it somewhere
libGLESv2.dylib is not. Nothing fails at build time; the first symptom is an
application that cannot get an EGL display. scripts/build-angle-apple.sh --print-loader-layout <platform> answers this, and the xcframeworks are split by
platform family instead: one per library per family.

Not byte-reproducible: gzip stores an mtime. The pin is trust-on-first-use — the
hash proves the bytes have not changed since they were hashed.

v0.9.6

Choose a tag to compare

@github-actions github-actions released this 30 Aug 04:59
ae67d00

Runtime SDKs for Android, Linux, OpenHarmony and Windows.

What changed in v0.9.6

A hotfix for a WebGL regression in v0.9.5.

Fixed

  • bufferData(target, ArrayBuffer, usage) uploads its data again. v0.9.5 added
    a size < 0 guard to bufferData that ran before the code checked whether a
    payload was supplied, and the JS binding passes size = -1 on the data path
    because the field is unused there. So the most common WebGL upload -- vertex
    and index buffers -- became a silent no-op that also recorded a spurious
    INVALID_VALUE, and every WebGL draw painted black. The op had no test;
    migo-conformance's webgl-basics bundle caught it on the first run against
    the v0.9.5 release AAR. The negative-size check now runs only on the
    size-only form, and op_buffer_data has a regression test on both forms.

Assets

File Size What it is
migo-0.9.6-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.6-android.aar 32 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.6-capi-android-arm64.tar.gz 72 MB C ABI SDK for android-arm64 -- headers, library, CMake package
migo-0.9.6-capi-android-x86_64.tar.gz 69 MB C ABI SDK for android-x86_64 -- headers, library, CMake package
migo-0.9.6-capi-linux-arm64.tar.gz 69 MB C ABI SDK for linux-arm64 -- headers, library, CMake package
migo-0.9.6-capi-linux-x86_64.tar.gz 69 MB C ABI SDK for linux-x86_64 -- headers, library, CMake package
migo-0.9.6-capi-ohos-arm64.tar.gz 88 MB C ABI SDK for ohos-arm64 -- headers, library, CMake package
migo-0.9.6-capi-ohos-x86_64.tar.gz 87 MB C ABI SDK for ohos-x86_64 -- headers, library, CMake package
migo-0.9.6-capi-windows-arm64.tar.gz 27 MB C ABI SDK for windows-arm64 -- headers, library, CMake package
migo-0.9.6-capi-windows-x86_64.tar.gz 27 MB C ABI SDK for windows-x86_64 -- headers, library, CMake package
migo-0.9.6-jni-android-arm64.tar.gz 16 MB see the file
migo-0.9.6-jni-android-x86_64.tar.gz 16 MB see the file

One AAR is published, carrying both ABIs. A shipped app carries one: add
ndk { abiFilters 'arm64-v8a' } to your defaultConfig and the packaged native
library is about half the size, or publish an App Bundle and Play delivers per device.
There is no separate slim build -- the product profile is an internal build axis, not
a choice an integrator can make.

Verifying a download

SHA256SUMS.txt covers every asset built by CI:

sha256sum -c SHA256SUMS.txt 2>/dev/null | grep -v ': OK$' || echo "all verified"

Every runtime payload also has an artifact-bound <asset>.sbom.cdx.json recording
its SHA-256, exact target/profile and reachable dependency graph. Provenance
<asset>.attestation.json sidecars record package identity; the checksum manifest
covers both payloads and sidecars. scripts/verify-release-assets.sh <tag> checks
that no published asset escapes that coverage.

Source code (zip / tar.gz)

Those two links are generated by GitHub from the tag and cannot be removed. Do not
build from them.
They omit submodules and Git LFS content, so a build from the zip
fails in ways that look like repository corruption. Clone the tag instead:

git clone --branch v0.9.6 --recurse-submodules https://github.com/minigame-labs/migo.git

Integration

See migo-examples for runnable
samples, and BUILD.md
for building from source.

What's Changed

  • Restore bufferData(target, ArrayBuffer, usage) — the size guard was dropping every WebGL upload by @jmcgill-d in #171

Full Changelog: v0.9.5...v0.9.6

v0.9.5

Choose a tag to compare

@github-actions github-actions released this 30 Aug 01:34
71a361f

Warning

WebGL is broken in this release. bufferData(target, ArrayBuffer, usage) — the
vertex/index-buffer upload every WebGL app makes — is a silent no-op here, so WebGL
content renders black. Canvas2D is unaffected. Fixed in v0.9.6; use that instead.

Runtime SDKs for Android, Linux, OpenHarmony and Windows.

What changed in v0.9.5

A correctness and efficiency pass over io, graphics and audio. Redundant GL
calls that slipped past the state shadow are deduplicated and the shadow itself
stopped hashing to decide; measureText and per-sample AudioParam automation
stop allocating and re-walking on every call; AnalyserNode's scalar
parameters take effect; compressImage shares a two-thread pool instead of
spawning one thread per image. A symlink race in sub-package and ZIP extraction
is closed, a WebGL context loss no longer strands a game between frames, and
getUpdateManager() stops inventing updates. Host frame-timestamp jitter no
longer drops frames for the rest of a session, and MigoRuntime reports the
real engine version.

Added

  • AnalyserNode's scalar parameters take effect. minDecibels, maxDecibels
    and smoothingTimeConstant were accepted and then ignored, so
    getByteFrequencyData / getFloatFrequencyData returned unsmoothed data over
    a fixed range regardless of what content set. They now reach the audio thread
    through a dedicated op and apply.
  • scripts/build-aar.sh --jitless builds an engine that asks V8 to stop
    generating machine code (--jitless). HarmonyOS 5.0.0(12) forbids a
    third-party VM from making memory executable, so Migo runs interpreted on
    NEXT whether it asks to or not; this is the build that produces the size of
    that penalty rather than guessing at it. Off by default, selected by no
    release path, and the artifact is named so it cannot be mistaken for one. The
    measured numbers are in migo-bench/JITLESS.md.

Changed

  • migo.compressImage no longer starts one OS thread per call. A batch — a
    screenshot sheet, an avatar pipeline — got a thread per image, each with a
    1 MB stack, all competing with the render thread. It now uses a shared,
    daemon pool of two.
  • PRESCREEN.md and the prescreen report now say which published names are
    no-op stubs and which fail loudly, rather than covering all of them with one
    sentence true of only some. The two stubs that were failing silently now
    answer "<api>:fail not supported" like the other 86.
  • On Android, requestVsync resolves its Java method ID once per process
    instead of hashing the method name and signature against the JNI method cache
    on every frame. The lookup is off the frame-scheduling path now; the id is a
    process-lifetime constant.
  • The GitHub Release notes now lead with this file's ## v<version> section.
    They previously carried only the asset table, verification steps, and GitHub's
    raw commit list — the curated record of what changed was in the repo but not
    on the release page. write-release-notes.sh refuses to write notes for a
    version whose section is missing or empty.
  • Redundant GL calls stop reaching the driver on two more paths. glScissor
    could not be deduplicated before, because the dirty-region Canvas2D batcher
    and the DrawingBuffer blit both moved the scissor box outside the state
    shadow; both now route through it. The texture-unit, glEnable/glDisable
    and vertex-attribute shadows were rebuilt from hash maps and sets keyed by GL
    enum or (vao, index) into arrays and bitmasks, so deciding that a call is
    redundant no longer hashes.
  • AudioParam automation is evaluated once per 128-sample block instead of once
    per sample. A parameter driven by setValueAtTime, a ramp, setTargetAtTime
    or setValueCurveAtTime walked its whole event timeline for every sample in
    the block; it now makes one forward pass.
  • measureText and the Canvas2D font ops no longer allocate on every call. They
    cloned the whole text string to keep a character count for a render-thread
    timeout branch they rarely reach; they now take the count first and move the
    original.
  • WebGL error reporting under queue pressure follows the spec. Past the
    per-context cap the queue used to discard the oldest un-retrieved error; it
    now keeps the oldest, drops the newest, reserves the last slot for a sticky
    OUT_OF_MEMORY, and counts the drops in the render diagnostics.
  • chacha20 (pulled in transitively by rand) is updated off a yanked
    release. No advisory attached; cargo audit stays clean.

Fixed

  • A re-linked WebGL program's uniforms reach the driver again. glLinkProgram
    gives a program fresh, zeroed uniform storage; the per-(program, location)
    dedup cache was not cleared across it, so content that re-linked a program and
    then re-uploaded an unchanged uniform value had that upload silently dropped —
    the draw used the reset value, with no GL error and nothing in a log.
  • Sub-package and ZIP extraction is no longer open to a symlink race. An entry's
    path was validated as a string and then resolved again by a separate syscall;
    a path component could turn into a symlink in between and let the entry write
    outside its destination directory. Every component is now reached with
    openat under O_NOFOLLOW from a held directory descriptor, so a swapped
    component fails with ELOOP at the moment of use rather than after a passed
    check.
  • fetch no longer puts the sandbox's internal path layout in a request to a
    remote server.
  • Terminating a Worker while it is still starting up is no longer a silent
    no-op. The handle the host holds was published only after the worker runtime
    finished initialising, so terminate() called in that window did nothing and
    the worker ran to completion.
  • A game is no longer stranded after a WebGL context loss and restore. The
    render drain dispatches webglcontextlost / webglcontextrestored into JS;
    a handler that resolves a promise or requests a frame leaves a pending task,
    and the event loop stayed parked on it until some unrelated host command
    arrived — which, for a game between frames, it never did.
  • The C ABI's minimum struct_size for MigoHostCallbacks was wrong on ILP32.
    It used a literal 32, correct for LP64's pointer width; a 32-bit host
    passing a struct that fully contained dispatch (minimum 20 there) was
    refused with MIGO_ERROR_INVALID_ARGUMENT. The minimum is now derived from
    the field offset.
  • migo.getUpdateManager() no longer invents updates. It was deciding with
    Math.random() < 0.3 at construction whether to fire
    onCheckForUpdate({hasUpdate: true}), so roughly a quarter of launches
    showed the game's own "new version — restart?" prompt and then applyUpdate()
    restarted nothing. This runtime has no update channel; the manager now says so
    instead of pretending.
  • Non-Android hosts (Linux, Windows, OpenHarmony, bare C embedders) now remove
    a session's sandbox /tmp directory when the session ends. GamePaths::clean_temp
    had no caller outside Android's Java SDK, so every session left its
    tmp/{id} subtree under the cache root for the life of the install.
  • Host timestamp jitter no longer drops frames for the rest of a session. The
    vsync decimator admitted a frame within a fixed 0.25 ms of its deadline, and
    every useful cadence puts that deadline exactly on a vsync — so a host whose
    frame-callback timestamps jittered by more than that dropped frames
    permanently: a replayed 60 Hz stream with 0.4 ms of jitter rendered 14 of 24
    vsyncs, a 60 fps request running at ~35 and staying there. The tolerance is
    now half the smaller of the last two delivered-vsync gaps, taking the frame
    nearest its deadline rather than the first past it. The frame rate the
    content asked for now also reaches Android's display-mode hint, so a request
    that is a whole divisor of the panel's rate gets an even cadence; and the
    requested-rate range and default, which four copies of the rule disagreed on
    (2^31 and non-finite handled differently on each side, a 24 fps request
    silently raised to 30, a ceiling of 120 that left 144 Hz panels unreachable),
    now live in one module.
  • MigoRuntime.getNativeVersion() and the public MigoRuntime.SDK_VERSION
    constant report the running engine's version. Both had frozen to an early
    release's number while the AAR's own versionName tracked release/VERSION,
    and since they were the same frozen string the SDK's skew check compared a
    value against itself and could never fire. The JNI version() now derives
    from CARGO_PKG_VERSION and SDK_VERSION from BuildInfo.VERSION, both of
    which scripts/test-release-version-contract.sh holds equal to
    release/VERSION.

Assets

File Size What it is
migo-0.9.5-android-nojni.aar 0 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.5-android.aar 32 MB Android library for Java/Kotlin, arm64-v8a + x86_64
migo-0.9.5-capi-android-arm64.tar.gz 72 MB C ABI SDK for android-arm64 -- headers, library, CMake package
migo-0.9.5-capi-android-x86_64.tar.gz 69 MB C ABI SDK for android-x86_64 -- headers, library, CMake package
migo-0.9.5-capi-linux-arm64.tar.gz 69 MB C ABI SDK for linux-arm64 -- headers, library, CMake package
migo-0.9.5-capi-linux-x86_64.tar.gz 69 MB C ABI SDK for linux-x86_64 -- headers, library, CMake package
migo-0.9.5-capi-ohos-arm64.tar.gz 88 MB C ABI SDK for ohos-arm64 -- headers, library, CMake package
migo-0.9.5-capi-ohos-x86_64.tar.gz 87 MB C ABI SDK for ohos-x86_64 -- headers, library, CMake package
migo-0.9.5-capi-windows-arm64.tar.gz 27 MB C ABI SDK for windows-arm64 -- headers, library, CMake package
migo-0.9.5-capi-windows-x86_64.tar.gz 27 MB C ABI SDK for windows-x86_64 -- headers, library, CMake package
`migo-0.9.5-jni-android-arm64.ta...
Read more