From 633f1e6f96c407005ea44ca11766abf66c377069 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Thu, 3 Oct 2024 22:42:12 +0200 Subject: [PATCH] WebView: implement file:///android_asset/... URIs --- src/api-impl-jni/util.c | 3 +++ src/api-impl-jni/util.h | 4 +++ .../widgets/android_webkit_WebView.c | 25 +++++++++++++++++++ src/api-impl/android/webkit/WebView.java | 8 ++++++ 4 files changed, 40 insertions(+) diff --git a/src/api-impl-jni/util.c b/src/api-impl-jni/util.c index 6c2aefdb..0fa58623 100644 --- a/src/api-impl-jni/util.c +++ b/src/api-impl-jni/util.c @@ -161,6 +161,9 @@ void set_up_handle_cache(JNIEnv *env) handle_cache.intent.class = _REF((*env)->FindClass(env, "android/content/Intent")); handle_cache.intent.putExtraCharSequence = _METHOD(handle_cache.intent.class, "putExtra", "(Ljava/lang/String;Ljava/lang/CharSequence;)Landroid/content/Intent;"); + + handle_cache.webview.class = _REF((*env)->FindClass(env, "android/webkit/WebView")); + handle_cache.webview.internalGetAssetManager = _METHOD(handle_cache.webview.class, "internalGetAssetManager", "()Landroid/content/res/AssetManager;"); } void extract_from_apk(const char *path, const char *target) { diff --git a/src/api-impl-jni/util.h b/src/api-impl-jni/util.h index 9e4a715d..5218e27e 100644 --- a/src/api-impl-jni/util.h +++ b/src/api-impl-jni/util.h @@ -111,6 +111,10 @@ struct handle_cache { jclass class; jmethodID putExtraCharSequence; } intent; + struct { + jclass class; + jmethodID internalGetAssetManager; + } webview; }; extern struct handle_cache handle_cache; diff --git a/src/api-impl-jni/widgets/android_webkit_WebView.c b/src/api-impl-jni/widgets/android_webkit_WebView.c index 6a29a59c..c8c84c60 100644 --- a/src/api-impl-jni/widgets/android_webkit_WebView.c +++ b/src/api-impl-jni/widgets/android_webkit_WebView.c @@ -1,5 +1,8 @@ #include #include +#include + +#include #include "../defines.h" #include "../util.h" @@ -9,6 +12,27 @@ #include "../generated_headers/android_view_View.h" #include "../generated_headers/android_webkit_WebView.h" +static void asset_uri_scheme_request_cb(WebKitURISchemeRequest *request, gpointer user_data) +{ + const gchar *path = webkit_uri_scheme_request_get_path(request); + if (path == NULL) + return; + path += 1; // remove the leading '/' + JNIEnv *env = get_jni_env(); + WrapperWidget *wrapper = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(webkit_uri_scheme_request_get_web_view(request)))); + jobject asset_manager_obj = (*env)->CallObjectMethod(env, wrapper->jobj, handle_cache.webview.internalGetAssetManager); + struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(asset_manager_obj, "mObject")); + struct Asset *asset = AssetManager_openNonAsset(asset_manager, path, ACCESS_STREAMING); + off_t offset; + off_t size; + int fd = Asset_openFileDescriptor(asset, &offset, &size); + Asset_delete(asset); + GInputStream *stream = g_unix_input_stream_new(fd, TRUE); + g_input_stream_skip(stream, offset, NULL, NULL); + webkit_uri_scheme_request_finish(request, stream, size, NULL); + g_object_unref(stream); +} + JNIEXPORT jlong JNICALL Java_android_webkit_WebView_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { /* @@ -23,6 +47,7 @@ JNIEXPORT jlong JNICALL Java_android_webkit_WebView_native_1constructor(JNIEnv * GtkWidget *webview = webkit_web_view_new(); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), webview); wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this); + webkit_web_context_register_uri_scheme(webkit_web_view_get_context(WEBKIT_WEB_VIEW(webview)), "android-asset", asset_uri_scheme_request_cb, NULL, NULL); return _INTPTR(webview); } diff --git a/src/api-impl/android/webkit/WebView.java b/src/api-impl/android/webkit/WebView.java index ffd650a0..eec02a6c 100644 --- a/src/api-impl/android/webkit/WebView.java +++ b/src/api-impl/android/webkit/WebView.java @@ -1,6 +1,7 @@ package android.webkit; import android.content.Context; +import android.content.res.AssetManager; import android.util.AttributeSet; import android.view.View; @@ -47,6 +48,8 @@ public class WebView extends View { public void destroy() {} public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) { + // webkit doesn't allow overwriting the file:// uri scheme. So we replace it with the android-asset:// scheme + data = data.replace("file:///android_asset/", "android-asset:///assets/"); native_loadDataWithBaseURL(widget, baseUrl, data, mimeType, encoding); } @@ -60,6 +63,11 @@ public class WebView extends View { public void stopLoading() {} + // to be used by native code + AssetManager internalGetAssetManager() { + return getContext().getResources().getAssets(); + } + @Override protected native long native_constructor(Context context, AttributeSet attrs); private native void native_loadDataWithBaseURL(long widget, String baseUrl, String data, String mimeType, String encoding);