如何在Android JavaScriptSandbox中直接用JS加载WebAssembly文件
解决方案
方法1:给JS Isolate添加自定义的Assets读取API
你使用的是独立JS Isolate环境(非WebView),默认没有fetch这类浏览器/Node.js专属API,最直接的解决方式是在Kotlin端为Isolate注册自定义方法,让JS主动调用该方法读取Assets文件夹下的Wasm文件,避免提前将30MB大文件加载到Kotlin内存中。
Kotlin端修改代码
创建Isolate后,注册用于读取Assets的宿主方法:
suspend fun runWebAssembly(): Result<String> = runCatchingCo { val isolate = getSandbox().createIsolate() // 注册自定义方法,供JS调用读取Assets文件 isolate.registerHostFunction("readAssetAsArrayBuffer") { args -> val assetFileName = args.firstOrNull()?.asString() ?: throw IllegalArgumentException("缺少文件名参数") // 从Assets读取文件并转为ArrayBuffer返回给JS applicationContext.assets.open(assetFileName).use { inputStream -> val byteArray = ByteArray(inputStream.available()) inputStream.read(byteArray) isolate.createArrayBuffer(byteArray) } } val jsCode = "(async ()=>{" + "const wasmBuffer = await android.readAssetAsArrayBuffer('test.wasm');" + "const module = await WebAssembly.compile(wasmBuffer);" + "const instance = new WebAssembly.Instance(module);" + "return instance.exports.addTwo(20, 22).toString();" + "})()" isolate.evaluateJavaScriptAsync(jsCode).await().also { isolate.close() } }
注意事项
- 此方式下,Kotlin不会提前加载整个30MB的Wasm文件,只有当JS调用
readAssetAsArrayBuffer时才会读取文件并返回,大幅降低内存占用。 - 确保Wasm文件直接放在
src/main/assets目录下,文件名与JS中传入的参数一致。
方法2:WebView环境专属方案(可选)
如果你是在WebView中运行JS,可通过配置WebSettings允许访问本地文件,直接使用file:///android_asset/路径加载:
// WebView配置 webView.settings.apply { allowFileAccess = true allowFileAccessFromFileURLs = true } // 对应JS代码 const response = await fetch('file:///android_asset/test.wasm'); const wasmBuffer = await response.arrayBuffer(); // 后续Wasm编译、实例化逻辑同上
此方法仅适用于WebView环境,不适用于你当前使用的独立Isolate环境。
为什么fetch无法直接使用?
独立JS Isolate(如QuickJS、V8 Isolate)是轻量级运行环境,默认不包含fetch、fs等平台相关API,这类API需要浏览器、Node.js等宿主环境提供支持。因此你必须通过Kotlin(宿主)注册自定义方法来补充文件读取能力。
内容的提问来源于stack exchange,提问作者lagoru
相关产品推荐
相关产品推荐

