用JNI在Rust中创建Android WebView
我正在尝试将android.webkit.webview对象连接到nativeactitive,但是我只是不简单地尝试创建WebView对象即可。 该代码看起来像这样
#[cfg(target_os = "android")]
pub fn setup(ctx: AndroidContext, env: AttachGuard) -> JObject {
let class = env.find_class("android/webkit/WebView").unwrap();
let context: *mut _jobject = ctx.context().cast();
let webview = env
.new_object(
class,
"(Landroid/content/Context;)V",
&[JValue::Object(context.into())],
)
.unwrap();
env.call_method(
context,
"setContentView",
"(Landroid/view/View;)V",
&[webview.into()],
)
.unwrap()
.v()
.unwrap();
...
}
当我尝试创建WebView时,
06-26 23:17:30.471 30695 30727 E AndroidRuntime: FATAL EXCEPTION: Thread-2
06-26 23:17:30.471 30695 30727 E AndroidRuntime: Process: rust.example.android, PID: 30695
06-26 23:17:30.471 30695 30727 E AndroidRuntime: java.lang.RuntimeException: WebView cannot be initialized on a thread that has no Looper.
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:670)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:604)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:587)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:574)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:564)
,我会看到与logCat的崩溃,看来从Rust side上的上下文中,有一个looper(基于通过呼叫for for_thread获取Threadlooper,并检查其不存储它是否存储空指针)。但是,从JVM的角度来看,似乎没有一个,因为试图通过JNI在Android.os.os.oper对象上登录对Mylooper的结果会产生无效的循环器。我想这是有道理的,因为UI循环未按照Java / Kotlin Android应用程序的方式设置。问题是,有办法解决这个问题吗?
我可以在非循环器的一部分的上下文中执行JNI调用,或与JNI上下文共享该循环,或通过JNI在JVM中通过JNI创建一个循环器。由于这应该是生锈库的一部分,因此我试图避免需要添加任何Java锅炉板。有没有办法避免这种情况?我并不是一个Android或JNI专家,所以我对这个项目的滑雪板很远。任何帮助都将受到赞赏。
I'm trying to connect a android.webkit.WebView object to a NativeActivity, but I'm failing simply trying to create the WebView object. That code looks like this
#[cfg(target_os = "android")]
pub fn setup(ctx: AndroidContext, env: AttachGuard) -> JObject {
let class = env.find_class("android/webkit/WebView").unwrap();
let context: *mut _jobject = ctx.context().cast();
let webview = env
.new_object(
class,
"(Landroid/content/Context;)V",
&[JValue::Object(context.into())],
)
.unwrap();
env.call_method(
context,
"setContentView",
"(Landroid/view/View;)V",
&[webview.into()],
)
.unwrap()
.v()
.unwrap();
...
}
When I try to create the WebView I see this crash with logcat
06-26 23:17:30.471 30695 30727 E AndroidRuntime: FATAL EXCEPTION: Thread-2
06-26 23:17:30.471 30695 30727 E AndroidRuntime: Process: rust.example.android, PID: 30695
06-26 23:17:30.471 30695 30727 E AndroidRuntime: java.lang.RuntimeException: WebView cannot be initialized on a thread that has no Looper.
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:670)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:604)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:587)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:574)
06-26 23:17:30.471 30695 30727 E AndroidRuntime: at android.webkit.WebView.<init>(WebView.java:564)
It appears that from the context on the rust side there is a looper (based on getting the ThreadLooper via a call to for_thread and checking that it's not storing a null pointer). However it does appear that there isn't one from the JVM perspective since attempts to log the results of a call to myLooper on the android.os.Looper object via JNI yields a null looper. I suppose this makes sense since the UI loop was not setup the way it normally would be with a Java / Kotlin Android app. The question is, is there a way around this?
Can I execute the JNI calls within a context that's part of the the non-null looper, or share that looper with the JNI context, or create a looper via JNI for the context within the JVM. Since this is supposed to be part of a rust library I'm try to avoid needing to add any java boiler plate. Is there a way to avoid that? I'm not exactly an Android or JNI expert so I'm pretty far out over my skis with this project. Any help is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
到目前为止,最简单的解决方案只是在Web交互期间启动新的(非本地)活动。
如果您不能这样做,则必须(至少)(至少)以下操作:
looper.prepare()
方法才能将线程与looper相关联quit()
在looper实例上被调用,looper.loop()
放弃对当前线程的控制。By far the simplest solution is simply to launch a new (non-native) activity for the duration of the web interaction.
If you cannot do that, you will have to do (at least) the following:
Looper.prepare()
method to associate your thread with a Looperquit()
is called on the Looper instanceLooper.loop()
.