The Android host for AppRuntime
apps. An AppRuntime app is guest code only: a universal bundle with
App.wasm and native libapp.a slices. This repository will turn one into
an Android app:
- the host runtime, in Swift: the Activity shell, the main looper, the
runtime core behind
rt.h, and the contract implementations over the Android SDK. Each contract module is Swift over a small Kotlin class, bound with swift-java; Motion reads the NDK's sensors directly; - the SwiftUI player: AndroidSwiftUI's Compose interpreter, behind an adapter for AppRuntime's render IR;
- the packager,
android-app, which turns a universal bundle into a signed APK or App Bundle.
Status: phase 3 of the plan: every AppRuntime
contract module runs on Android, checked on the emulator by
Scripts/contracts-check.sh. In phase 2, android-app packages a universal
bundle as a debug APK, or as a signed release APK or App Bundle. Before
that, in phase 1: AppRuntime's ExampleUI runs from its universal bundle in
the emulator, rendered by AndroidSwiftUI's composeui. Taps, typing, the lazy
list, navigation and the back gesture all reach the guest and come back.
Phase 0 ran AppRuntime's ExampleApp from its sealed Android slice, with
every check of AppRuntime's linked-slice test passing.
It is the counterpart of DarwinAppRuntime and LinuxAppRuntime.
Swift 6.4 is required (.swift-version pins 6.4.2), with the Swift SDK
for Android set up with NDK r30. Its runtime needs r30's libc++_shared.so,
although its setup script accepts r27:
swift sdk install https://download.swift.org/swift-6.4.2-release/android-sdk/swift-6.4.2-RELEASE/swift-6.4.2-RELEASE_android.artifactbundle.tar.gz \
--checksum 4d6ad63ea74becd58e123ff58b1b48c3be5ec0db0dff0ea5abe37ac007dd3233
ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/30.0.16248370 \
~/Library/org.swift.swiftpm/swift-sdks/swift-6.4.2-RELEASE_android.artifactbundle/swift-android/scripts/setup-android-sdk.shThen, with an emulator running and these checkouts next to this one:
- AppRuntime, with its
RuntimeHostmodule (orAPPRUNTIME_PATH); - AndroidSwiftUI, for composeui (or
ANDROIDSWIFTUI_PATH).
Scripts/example-ui.sh --runThe script:
- builds
ExampleUI's universal bundle with AppRuntime'sguest.py; - links its slice into
libapp.sowith the host; - builds
Android/example-uiwith Gradle, on a JDK from 17 to 21; - installs it, and drives it with UI Automator
(
Scripts/example-ui-check.py).
It uses a running emulator unless ANDROID_SERIAL names a device.
Scripts/example-app.sh --run does the same for phase 0.
The host implements AppRuntime's contract modules: Device, Formatting,
Location, Networking, Bluetooth (the central role), Motion and NFC (the
reader role), and the Permissions built-in over Android's runtime
permissions.
Scripts/contracts-check.shThe script builds Examples/ContractsCheck, a guest app that calls every
contract and shows one ok or FAIL line per check, and packages it with
android-app run. Scripts/contracts-check.py then reads the lines from
the player's trace in logcat, and makes things happen for the app to see:
- it changes the emulator's battery and GPS position;
- it answers the location, Nearby devices and physical activity prompts.
Networking's checks need the Internet (httpbin.org). Bluetooth scans, and connects to the first connectable device it finds, if any. NFC needs a device with NFC; on the emulator, the check confirms the session fails as it should.
android-app turns a universal bundle from AppRuntime's guest.py bundle
into an Android app:
swift run android-app validate App.appswift run android-app run App.appANDROID_KEYSTORE_PASSWORD=… swift run android-app package App.app --aab --keystore release.jks --alias releasevalidatechecks the app against this host: its keys, its contracts and its slices.runbuilds a debug APK, installs it on a running emulator (or--device), and starts it.packagebuilds a debug APK, or a signed release with--releaseor--aab. Release passwords come fromANDROID_KEYSTORE_PASSWORDandANDROID_KEY_PASSWORD.gradlewrites the app's Gradle project, for Android Studio.
Each ABI the bundle has is built, unless --abi picks some. The work goes
in .build/android-app/<identifier>/.
swift test runs the host's and the packager's unit tests on macOS. Run the player's tests
from Android/:
./gradlew :appruntime-ui:desktopTest