-
-
Notifications
You must be signed in to change notification settings - Fork 253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android assets not loaded as expected with custom protocol #846
Comments
I pretty sure I added |
Thanks for the response! I went looking for it on the class RustClient(context: Context) : WebViewClient() {
private val assetLoader = WebViewAssetLoader.Builder()
.setDomain("tauri.mobile")
.addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(context))
.addPathHandler("/res/", WebViewAssetLoader.ResourcesPathHandler(context))
.build()
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return false
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
eval()
}
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
return handleRequest(request)
}
companion object {
init {
System.loadLibrary("{{snake-case app.name}}")
}
}
private external fun eval()
private external fun handleRequest(request: WebResourceRequest): WebResourceResponse?
} After the commit class RustClient: WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return false
}
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
return handleRequest(request)
}
companion object {
init {
System.loadLibrary("{{snake-case app.name}}")
}
}
private external fun handleRequest(request: WebResourceRequest): WebResourceResponse?
} Now, however, this is all gone, I can see this code lives now in a function called RustWebViewClient, but I can't find the template for that in dev. Ii looks similar but does not have the
[EDIT] Thanks for the help in sorting this issue! |
I've removed automatic asset loading because Tauri loads assets from memory instead of the assets/ folder. Maybe we should expose a wry method to load an asset instead? I wouldn't do anything automatic though (like having an |
@lucasfernog Okay I looked into a bit and looks like closure from custom protocol can be used on Android now right? |
Indeed the closure works, however I could not find a way to access the files in the I guess we could expose an instance of |
I like your idea @lily-mosquitoes. What do you think @wusyong ? |
Oh sorry for late reply. I'm busy with lunar new year lately. I think it's fine to expose the instance. But consider it will be a platform-specific trait method. Maybe we can add it as an attribute extension like Expose raw instance and require users to call JNI FFI might be difficult for them. But still I'm fine with both methods. |
So far, using One of the simplest methods I've tried: pub fn get_asset(path: &str) -> Option<Vec<u8>> {
let activity = ndk_glue::native_activity();
let asset_manager = activity.asset_manager();
let path_cstring = std::ffi::CString::new(path).ok()?;
let mut asset = asset_manager.open(&path_cstring)?;
Some(asset.get_buffer().ok()?.to_vec())
} Error I get:
Anyone knows what might be the cause? let asset_manager = env
.call_method(
activity.as_obj(),
"getAssets",
"()Landroid/content/res/AssetManager;",
&[],
)
.unwrap()
.l()
.unwrap();
let asset_manager = env.new_global_ref(asset_manager).unwrap();
ASSET_MANGER.get_or_init(move || asset_manager); Where if let Some(am) = ASSET_MANGER.get() {
let am_ptr = am.as_obj().into_raw() as *mut _;
let non_null_am_ptr = core::ptr::NonNull::new(am_ptr)?;
let asset_manager = unsafe { AssetManager::from_ptr(non_null_am_ptr) };
let path_cstring = std::ffi::CString::new(path).ok()?;
let mut asset = asset_manager.open(&path_cstring)?;
Some(asset.get_buffer().ok()?.to_vec())
} else { None } On the meantime I suppose I'll try to implement an extension such as |
I was actually trying one last idea of how to get the asset by only using the JNI, but I'm struggling to find out how I can convert a Java byteArray to a rust if let Some(am) = ASSET_MANGER.get() {
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.expect("vm failed");
let env = vm.attach_current_thread().expect("attach failed");
let asset_manager = am.as_obj();
let asset = env
.call_method(
asset_manager,
"open",
"(Ljava/lang/String;)Ljava/io/InputStream;",
&[env.new_string(path).expect("string failed").into()],
)
.expect("env failed")
.l()
.expect("l failed");
let bytes = env
.call_method(asset, "readAllBytes", "()[B", &[])
.expect("bytes env failed")
.l()
.expect("bytes l failed");
let elements = env
.get_byte_array_elements(bytes.into(), jni::objects::ReleaseMode::CopyBack)
.expect("elements env failed");
Some(\* ??? -> how to make elements into a Vec<u8>? *\))
} else {
None
} |
@lily-mosquitoes We didn't use native activity as our main activity. Native activity is very different from other activities and it also has a totally different API implementation in C. It cannot access many android API since most of them are implemented in Java. The possible way I could think of is a config to to determine whether to use
|
Thank you for the direction @wusyong, I was able to finish the changes using the method you delineated. Here are a few things that I'd like to double check:
For now I'm giving it a useless I believe that's all the questions I have, I'll be creating a PR to accompany this issue so people can take a look at the code and documentation, and see if it is acceptable. |
Implements WebViewAssetLoader to load assets from the asset folder in Android when `with_asset_loader` is called in the builder. The function also sets the desired protocol for use in `with_url`, although the url must always be `<protocol>://assets/<path>`. Refs: tauri-apps#846
I can also propose an update for the template in |
…) (#854) * fix(android): restore asset loading functionality to android Implements WebViewAssetLoader to load assets from the asset folder in Android when `with_asset_loader` is called in the builder. The function also sets the desired protocol for use in `with_url`, although the url must always be `<protocol>://assets/<path>`. Refs: #846 * docs(changes): document changes for android's fix-asset-loading patch * Refactor to prevent additional allocation * Fix merge conflict * Disable default target to android * Pass zero parameter to android fns --------- Co-authored-by: Wu Wayne <yuweiwu@pm.me>
Describe the bug
When using custom protocol to load assets on android, they are not loaded automatically as suggested by documentation.
The
with_custom_protocol
docs suggests that handling assets on the closure is unnecessary as android handles its own assets path:However, using simply
wry://assets/index.html
, leaving the closure to return an empty response (i.e.:Ok(Response::builder().body(Vec::new().into())?)
) does not work, nothing is shown (whereas not using the custom protocol, but insteadfile:///android_asset/index.html
does work and loads the index.html file in the assets folder, however it is my understanding that this has limitations and it is considered an anti-pattern by android docs).I fully assume I'm doing something wrong, so I'd love if someone could let me know how to configure the project to load assets and I'm willing to contribute to the documentation.
Steps To Reproduce
(Assuming toolchain for android development is installed following the hackmd notes)
Install tauri-mobile v0.1.4
mkdir testapp && cd testapp
cargo mobile init
create a minimal
index.html
inside theassets
folder.change code from
.with_url("https://tauri.app")?
to.with_url("wry://assets/index.html")?
.connect android device or run emulator.
run
cargo android run
.Expected behavior
Expected to get the contents of
index.html
to show in webview window. Got completely blank page.Screenshots
![Screenshot_2023-01-15_17-51-14](https://user-images.githubusercontent.com/69756012/212551428-fbed576c-969c-4879-b22d-4ad09c48ba5c.png)
When trying to load assets as suggested by wry documentation:
When using
![Screenshot_2023-01-15_17-52-18](https://user-images.githubusercontent.com/69756012/212551474-57c79ec3-d1ff-47ec-a5ad-80182350f7aa.png)
file:///
, not recommended by android documentation:Platform and Versions (please complete the following information):
OS: Compiling on Debian GNU/Linux 11 (bullseye).
Targets tested: aarch64-linux-android (device Sony XA2 H4113) and x86_64-linux-android (android emulator android-33).
Rustc: 1.67.0-nightly.
Would you want to assign yourself to resolve this bug?
Additional context
I noticed that if I set up the closure to return the contents of the
index.html
file (captured usinginclude_bytes!
) it also works, suggesting that the closure is in fact not ignored as suggested by the docs. I assume actually handling loading the files in the closure is the correct way to do it but I was not able to access theassets
folder inside the apk from within rust, trying to call anything fromndk_glue
there crashes the application.Although this is probably the wrong approach I have also tried to mess with the kotlin code in the
gen
folder, to follow the android docs but had no luck. I'd need a push in the right direction to get this working properly and contribute to documentation.The text was updated successfully, but these errors were encountered: