Add Android AAR project for embedding Babylon Native#1682
Add Android AAR project for embedding Babylon Native#1682CedricGuillemet wants to merge 3 commits intoBabylonJS:masterfrom
Conversation
Adds Install/AndroidAAR/ - a standalone Gradle project that builds a publishable AAR (libBabylonNativeJNI.so + BabylonView/Wrapper Java classes) tuned for the smallest possible footprint: - QuickJS engine, libc++ statically linked - Only arm64-v8a / x86_64 ABIs - OpenGL ES 3.0 only (no Vulkan/D3D/Metal compiled into bgfx) - Image loading, shader compiler, NativeInput, XMLHttpRequest, NativeXr plugins disabled - Release build uses MinSizeRel (-Os, hidden visibility, --gc-sections, --strip-all) Embedding application is expected to drive script loading via BabylonView.loadScript() - nothing is auto-loaded by the AAR. Optional shader cache is read from the embedding application's 'shadercache.bin' asset. Includes: - README.md documenting the contract and footprint optimizations - build-release.ps1 helper that builds and prints AAR/.so sizes - New CI job Android_AAR (build-android-aar.yml) that builds the AAR, prints artifact sizes and uploads the AAR as a workflow artifact Note: temporarily pins JsRuntimeHost to CedricGuillemet/JsRuntimeHost fork until the upstream QuickJS support PR is merged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…JsRuntimeHost
- Restore JsRuntimeHost FetchContent declaration without EXCLUDE_FROM_ALL
(per the comment block above, JsRuntimeHost is intentionally an exception
because it exposes top-level targets like AppRuntime that are part of
the Babylon Native contract).
- Rename Install/AndroidAAR -> Install/AndroidQuickJSMinimal and align all
related identifiers:
* workflow file: build-android-aar.yml -> build-android-quickjs-minimal.yml
* CI job: Android_AAR -> Android_QuickJSMinimal
* gradle root project: BabylonNativeAAR -> BabylonNativeQuickJSMinimal
* uploaded artifact: BabylonNative-release-aar -> BabylonNative-QuickJSMinimal-release-aar
* build staging dir: Build/Android-AAR -> Build/Android-QuickJSMinimal
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The minimal AAR does not link NativeXr, so xrSurfaceChanged() and
isXRActive() are dead surface area. Drop them from:
- BabylonNativeJNI.cpp (the two stub JNI exports)
- Wrapper.java (the two native declarations)
- BabylonView.java (the secondary xrSurfaceView, its callback and
the isXRActive() check in onDraw)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| embedding application as an asset named **`shadercache.bin`**: | ||
|
|
||
| ``` | ||
| app/src/main/assets/shadercache.bin |
There was a problem hiding this comment.
How would a consumer of this package generate the shadercache.bin file? It seems like they would have to write some other BN code that loads their js bundle and then they save the shader cache or something?
Would it make more sense to have this lib save the shadercache.bin on first run, and automatically re-use it on subsequent runs, and allow the consumer to choose to grab that file off the device and include it in the app package if they want to avoid even the first run hit?
There was a problem hiding this comment.
shadercache.bin is generated by a specific user process (on the CI, or user is responsible to cache and push to repo) so glslang/spirv do not need to be linked with app (it's multiple Mb). Some users already use the cache the way you describe but it's for server side rendering. Here, the goal is to have a limited set of shaders that are bundled in the app.
There was a problem hiding this comment.
Ok so effectively, the consumer would create a different app using the full BN api and the same shaders, and run that app in a CI to generate the shaderCache.bin, and then that cache is used with their client side app that can load that shaderCache.bin?
There was a problem hiding this comment.
As discussed we can probably replace this with a reusable/shared interop layer, but that could be done in a separate PR.
There was a problem hiding this comment.
Maybe! I'm curious to see if it's possible to have gradle/cmake/cpp sources in an aar.
There was a problem hiding this comment.
I was thinking more that you just use a shared layer up to the cpp/jni, and then provide your own Java layer and compile it all into your aar. Not a blocker for this PR.
| * Image loading, shader compiler, NativeInput and XMLHttpRequest plugins | ||
| are disabled. | ||
| * Release build uses `MinSizeRel` (`-Os`), function/data sections, | ||
| hidden visibility, dead-code elimination and `--strip-all`. |
There was a problem hiding this comment.
Does it include debug symbols? I assume it would need to so that if there are crash reports, we'd be able to understand what is going on.
There was a problem hiding this comment.
I guess it's possible. User would be responsible for stripping debug infos. Here, infos are stripped on purpose.
There was a problem hiding this comment.
I don't think stripped binaries are really usable in production. @bghgary
| Wrapper.eval(source, sourceURL); | ||
| } | ||
|
|
||
| public void onPause() { |
There was a problem hiding this comment.
Could BabylonView self-register with the host Activity''s lifecycle so consumers don''t have to manually forward onPause / onResume from their Activity?
Since the constructor already takes a Context (and effectively an Application via getApplication()), the view could call Application.registerActivityLifecycleCallbacks(...) and react to onActivityPaused / onActivityResumed for the Activity that hosts it (filtering by walking getContext() up to the Activity). Unregister on onDetachedFromWindow to avoid leaks.
A more idiomatic alternative would be DefaultLifecycleObserver against the host''s Lifecycle, but that pulls in AndroidX which conflicts with the "smallest possible footprint" goal — so ActivityLifecycleCallbacks is probably the better fit here.
onRequestPermissionsResult would still need to be forwarded manually (it''s not part of ActivityLifecycleCallbacks), but eliminating the pause/resume boilerplate would noticeably simplify the embedding contract documented in the README.
There was a problem hiding this comment.
I have no idea. :)
|
[Responded by Copilot on behalf of @bghgary] Stepping back from the inline comments — I want to raise an architectural-direction concern with this PR before we go deeper on the bug-level review. This is the first time we'd publish a packaged binary artifact from this repo's CI:
The configuration is also very opinionated for one shape of consumer:
A consumer with different needs (XR, HTTP fetches, V8 perf, Vulkan, touch input, debuggable production binaries, etc.) would not use this AAR — they'd need their own. So one AAR per consumer-shape doesn't scale in the upstream repo. The ownership questions that follow:
Without rejecting the work — there's a real value capture here regardless of where it lives — a few alternatives I'd want to consider:
My take: (a) or (b). The build smoke test is genuinely valuable — without something like it, the Curious what you both think before I do another pass through the inline review notes. |
Adds
Install/AndroidAAR/— a self-contained Gradle project producing a publishable Android AAR (BabylonNative-release.aar) intended to embed Babylon Native inside any Android application with the smallest possible footprint.Footprint optimizations
arm64-v8a+x86_64onlyNativeInput,XMLHttpRequest,NativeXrplugins disabledMinSizeRel(-Os), function/data sections, hidden visibility,--gc-sections,--strip-allPublic contract
BabylonView.loadScript()— nothing is auto-loaded by the AAR.shadercache.binasset.Includes
README.mddocumenting the contract and footprint optimizationsbuild-release.ps1helper that builds + prints AAR / .so sizesAndroid_AAR(build-android-aar.yml) that builds the AAR, prints artifact sizes and uploads the AAR as a workflow artifactNote
Temporarily pins
JsRuntimeHostto theCedricGuillemet/JsRuntimeHostfork until the upstream QuickJS support PR is merged.Naming is hard. I'm using generic/stupid names like 'Android-AAR'. Please provide your ideas.