mirror of
https://github.com/Drop-OSS/wry-cef.git
synced 2026-01-30 20:55:24 +01:00
properly select activity, fix messaging for multi webview on android
This commit is contained in:
@@ -14,8 +14,11 @@ pub use jni::{
|
||||
JNIEnv,
|
||||
};
|
||||
pub use ndk;
|
||||
use ndk::looper::{FdEvent, ThreadLooper};
|
||||
use std::os::fd::{AsFd, AsRawFd};
|
||||
|
||||
use super::{
|
||||
main_pipe::{MainPipe, MAIN_PIPE},
|
||||
ASSET_LOADER_DOMAIN, EVAL_CALLBACKS, IPC, ON_LOAD_HANDLER, REQUEST_HANDLER, TITLE_CHANGE_HANDLER,
|
||||
URL_LOADING_OVERRIDE, WITH_ASSET_LOADER,
|
||||
};
|
||||
@@ -32,6 +35,7 @@ macro_rules! android_binding {
|
||||
($domain:ident, $package:ident, $wry:path) => {{
|
||||
use $wry::{android_setup as _, prelude::*};
|
||||
|
||||
android_fn!($domain, $package, Rust, wryCreate, []);
|
||||
android_fn!(
|
||||
$domain,
|
||||
$package,
|
||||
@@ -246,6 +250,27 @@ fn handle_request(
|
||||
Ok(*JObject::null())
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn wryCreate(env: JNIEnv, _: JClass) {
|
||||
let mut main_pipe = MainPipe { env };
|
||||
|
||||
let looper = ThreadLooper::for_thread().unwrap();
|
||||
|
||||
looper
|
||||
.add_fd_with_callback(MAIN_PIPE[0].as_fd(), FdEvent::INPUT, move |fd, _event| {
|
||||
let size = std::mem::size_of::<bool>();
|
||||
let mut wake = false;
|
||||
if libc::read(fd.as_raw_fd(), &mut wake as *mut _ as *mut _, size) == size as libc::ssize_t {
|
||||
// unregister itself on errors
|
||||
main_pipe.recv().is_ok()
|
||||
} else {
|
||||
// unregister itself
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn onWebviewDestroy(mut env: JNIEnv, _: JClass, activity: JObject, webview_id: JString) {
|
||||
let activity_id = env
|
||||
|
||||
@@ -27,6 +27,7 @@ object Rust {
|
||||
@JvmStatic external fun pause()
|
||||
@JvmStatic external fun stop()
|
||||
|
||||
@JvmStatic external fun wryCreate()
|
||||
@JvmStatic external fun onWebviewDestroy(activity: WryActivity, webviewId: String)
|
||||
|
||||
@JvmStatic external fun ipc(webviewId: String, url: String, message: String)
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.webkit.WebViewAssetLoader
|
||||
class RustWebViewClient(webView: RustWebView, context: Context): WebViewClient() {
|
||||
private val interceptedState = mutableMapOf<String, Boolean>()
|
||||
var currentUrl: String = "about:blank"
|
||||
private var lastInterceptedUrl: Uri? = null
|
||||
private var pendingUrlRedirect: String? = null
|
||||
|
||||
private val assetLoader = WebViewAssetLoader.Builder()
|
||||
@@ -35,12 +34,10 @@ class RustWebViewClient(webView: RustWebView, context: Context): WebViewClient()
|
||||
return null
|
||||
}
|
||||
|
||||
lastInterceptedUrl = request.url
|
||||
return if (Rust.withAssetLoader((view as RustWebView).id)) {
|
||||
assetLoader.shouldInterceptRequest(request.url)
|
||||
} else {
|
||||
val rustWebview = view as RustWebView;
|
||||
val response = Rust.handleRequest(rustWebview.id, request, rustWebview.isDocumentStartScriptEnabled)
|
||||
val response = Rust.handleRequest(view.id, request, view.isDocumentStartScriptEnabled)
|
||||
interceptedState[request.url.toString()] = response != null
|
||||
return response
|
||||
}
|
||||
@@ -76,13 +73,17 @@ class RustWebViewClient(webView: RustWebView, context: Context): WebViewClient()
|
||||
// we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol
|
||||
// e.g. oauth flow, because shouldInterceptRequest is not called on redirects
|
||||
// so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in
|
||||
if (error.errorCode == ERROR_CONNECT && request.isForMainFrame && request.url != lastInterceptedUrl) {
|
||||
//
|
||||
// we also get a net::ERR_CONNECTION_REFUSED when a second webview tries to load http://tauri.localhost
|
||||
// so we retry the currentUrl regardless. We do not have a timeout yet due to the amount of retries needed to make it work
|
||||
// but we might add a timeout in the future
|
||||
if (error.errorCode == ERROR_CONNECT) {
|
||||
// prevent the default error page from showing
|
||||
view.stopLoading()
|
||||
// without this initial loadUrl the app is stuck
|
||||
view.loadUrl(request.url.toString())
|
||||
view.loadUrl(currentUrl)
|
||||
// ensure the URL is actually loaded - for some reason there's a race condition and we need to call loadUrl() again later
|
||||
pendingUrlRedirect = request.url.toString()
|
||||
pendingUrlRedirect = currentUrl
|
||||
} else {
|
||||
super.onReceivedError(view, request, error)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package {{package}}
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.webkit.WebView
|
||||
@@ -20,6 +21,7 @@ object WryLifecycleObserver : DefaultLifecycleObserver {
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
super.onCreate(owner)
|
||||
Rust.create()
|
||||
Rust.wryCreate()
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
@@ -90,7 +92,7 @@ abstract class WryActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
id = savedInstanceState?.getInt(ACTIVITY_ID_KEY) ?: hashCode()
|
||||
id = savedInstanceState?.getInt(ACTIVITY_ID_KEY) ?: intent.extras?.getInt(ACTIVITY_ID_KEY) ?: hashCode()
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver)
|
||||
Rust.onActivityCreate(this)
|
||||
}
|
||||
@@ -129,5 +131,13 @@ abstract class WryActivity : AppCompatActivity() {
|
||||
return Class.forName(name)
|
||||
}
|
||||
|
||||
fun startActivity(cls: Class<*>): Int {
|
||||
val intent = Intent(this, cls)
|
||||
val id = kotlin.random.Random.nextInt()
|
||||
intent.putExtra(ACTIVITY_ID_KEY, id)
|
||||
startActivity(intent)
|
||||
return id
|
||||
}
|
||||
|
||||
{{class-extension}}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
void setWebView({{package-unescaped}}.RustWebView);
|
||||
java.lang.Class getAppClass(...);
|
||||
java.lang.String getVersion();
|
||||
int startActivity(...);
|
||||
}
|
||||
|
||||
-keep class {{package-unescaped}}.Ipc {
|
||||
|
||||
@@ -7,10 +7,12 @@ use crossbeam_channel::*;
|
||||
use jni::{
|
||||
errors::Result as JniResult,
|
||||
objects::{GlobalRef, JMap, JObject, JString},
|
||||
JNIEnv,
|
||||
JNIEnv, JavaVM,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
ffi::c_void,
|
||||
os::unix::prelude::*,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
@@ -19,27 +21,40 @@ use super::{find_class, EvalCallback, WebviewId, EVAL_CALLBACKS, EVAL_ID_GENERAT
|
||||
|
||||
pub type ActivityId = i32;
|
||||
|
||||
static CHANNEL: Lazy<(
|
||||
Sender<(ActivityId, WebViewMessage)>,
|
||||
Receiver<(ActivityId, WebViewMessage)>,
|
||||
)> = Lazy::new(|| bounded(8));
|
||||
pub static MAIN_PIPE: Lazy<[OwnedFd; 2]> = Lazy::new(|| {
|
||||
let mut pipe: [RawFd; 2] = Default::default();
|
||||
unsafe { libc::pipe(pipe.as_mut_ptr()) };
|
||||
unsafe { pipe.map(|fd| OwnedFd::from_raw_fd(fd)) }
|
||||
});
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ActivityProxy {
|
||||
pub channel: (Sender<WebViewMessage>, Receiver<WebViewMessage>),
|
||||
pub pipe: Arc<[OwnedFd; 2]>,
|
||||
pub activity: GlobalRef,
|
||||
pub window_manager: GlobalRef,
|
||||
pub webview: Option<GlobalRef>,
|
||||
pub webchrome_client: GlobalRef,
|
||||
pub java_vm: *mut c_void,
|
||||
}
|
||||
|
||||
unsafe impl Send for ActivityProxy {}
|
||||
|
||||
impl ActivityProxy {
|
||||
pub fn new(activity: GlobalRef, webchrome_client: GlobalRef) -> Self {
|
||||
let mut pipe: [RawFd; 2] = Default::default();
|
||||
unsafe { libc::pipe(pipe.as_mut_ptr()) };
|
||||
let pipe = unsafe { pipe.map(|fd| OwnedFd::from_raw_fd(fd)) };
|
||||
let channel = bounded(8);
|
||||
pub fn new(
|
||||
vm: JavaVM,
|
||||
activity: GlobalRef,
|
||||
window_manager: GlobalRef,
|
||||
webchrome_client: GlobalRef,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
pipe: Arc::new(pipe),
|
||||
activity,
|
||||
window_manager,
|
||||
webview: None,
|
||||
webchrome_client,
|
||||
java_vm: vm.get_java_vm_pointer() as *mut _,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,24 +69,42 @@ pub fn activity_proxy(id: ActivityId) -> Option<ActivityProxy> {
|
||||
}
|
||||
|
||||
pub fn register_activity_proxy(
|
||||
vm: JavaVM,
|
||||
id: ActivityId,
|
||||
activity: GlobalRef,
|
||||
window_manager: GlobalRef,
|
||||
webchrome_client: GlobalRef,
|
||||
) -> ActivityProxy {
|
||||
) {
|
||||
let mut activity_proxy = ACTIVITY_PROXY.lock().unwrap();
|
||||
if let Some(proxy) = activity_proxy.get_mut(&id) {
|
||||
proxy.activity = activity;
|
||||
proxy.window_manager = window_manager;
|
||||
proxy.webchrome_client = webchrome_client;
|
||||
proxy.clone()
|
||||
proxy.java_vm = vm.get_java_vm_pointer() as *mut _;
|
||||
} else {
|
||||
let proxy = ActivityProxy::new(activity, webchrome_client);
|
||||
let proxy = ActivityProxy::new(vm, activity, window_manager, webchrome_client);
|
||||
activity_proxy.insert(id, proxy.clone());
|
||||
proxy
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_activity_id() -> Option<ActivityId> {
|
||||
ACTIVITY_PROXY.lock().unwrap().keys().next_back().cloned()
|
||||
pub fn activity_id_for_window_manager(window_manager: JObject) -> Option<ActivityId> {
|
||||
for (activity_id, proxy) in ACTIVITY_PROXY.lock().unwrap().iter() {
|
||||
let vm = unsafe { JavaVM::from_raw(proxy.java_vm.cast()) }.unwrap();
|
||||
let mut env = vm.attach_current_thread_as_daemon().unwrap();
|
||||
let equals = env
|
||||
.call_method(
|
||||
proxy.window_manager.as_obj(),
|
||||
"equals",
|
||||
"(Ljava/lang/Object;)Z",
|
||||
&[(&window_manager).into()],
|
||||
)
|
||||
.and_then(|v| v.z())
|
||||
.unwrap_or_default();
|
||||
if equals {
|
||||
return Some(*activity_id);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn first_activity_id() -> Option<ActivityId> {
|
||||
@@ -89,28 +122,17 @@ pub fn get_webview(activity_id: ActivityId) -> Option<GlobalRef> {
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub enum MainPipeState {
|
||||
Alive,
|
||||
Destroyed,
|
||||
}
|
||||
|
||||
pub struct MainPipe<'a> {
|
||||
pub env: JNIEnv<'a>,
|
||||
pub activity_id: ActivityId,
|
||||
}
|
||||
|
||||
impl<'a> MainPipe<'a> {
|
||||
pub(crate) fn send(activity_id: ActivityId, message: WebViewMessage) {
|
||||
let size = std::mem::size_of::<bool>();
|
||||
let Some(proxy) = activity_proxy(activity_id) else {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("no activity proxy found for activity id: {activity_id}");
|
||||
return;
|
||||
};
|
||||
if let Ok(()) = proxy.channel.0.send(message) {
|
||||
if CHANNEL.0.send((activity_id, message)).is_ok() {
|
||||
unsafe {
|
||||
libc::write(
|
||||
proxy.pipe[1].as_raw_fd(),
|
||||
MAIN_PIPE[1].as_raw_fd(),
|
||||
&true as *const _ as *const _,
|
||||
size,
|
||||
)
|
||||
@@ -118,25 +140,16 @@ impl<'a> MainPipe<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv(&mut self) -> JniResult<MainPipeState> {
|
||||
let Some(proxy) = activity_proxy(self.activity_id) else {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!(
|
||||
"no activity proxy found for activity id: {}",
|
||||
self.activity_id
|
||||
);
|
||||
return Ok(MainPipeState::Destroyed);
|
||||
};
|
||||
let rx = proxy.channel.1;
|
||||
if let Ok(message) = rx.recv() {
|
||||
pub fn recv(&mut self) -> JniResult<()> {
|
||||
if let Ok((activity_id, message)) = CHANNEL.1.recv() {
|
||||
match message {
|
||||
WebViewMessage::CreateWebView(attrs) => {
|
||||
let Some((activity, web_chrome_client)) = activity_proxy(self.activity_id)
|
||||
.map(|p| (p.activity.clone(), p.webchrome_client.clone()))
|
||||
let Some((activity, web_chrome_client)) =
|
||||
activity_proxy(activity_id).map(|p| (p.activity.clone(), p.webchrome_client.clone()))
|
||||
else {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("no activity found for activity id: {}", self.activity_id);
|
||||
return Ok(MainPipeState::Destroyed);
|
||||
eprintln!("no activity found for activity id: {}", activity_id);
|
||||
return Ok(());
|
||||
};
|
||||
let CreateWebViewAttributes {
|
||||
url,
|
||||
@@ -318,13 +331,13 @@ impl<'a> MainPipe<'a> {
|
||||
ACTIVITY_PROXY
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_mut(&self.activity_id)
|
||||
.get_mut(&activity_id)
|
||||
.unwrap()
|
||||
.webview
|
||||
.replace(webview);
|
||||
}
|
||||
WebViewMessage::Eval(script, callback) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
let id = EVAL_ID_GENERATOR.next() as i32;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
@@ -358,12 +371,12 @@ impl<'a> MainPipe<'a> {
|
||||
}
|
||||
}
|
||||
WebViewMessage::SetBackgroundColor(background_color) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
set_background_color(&mut self.env, webview.as_obj(), background_color)?;
|
||||
}
|
||||
}
|
||||
WebViewMessage::GetWebViewVersion(tx) => {
|
||||
if let Some(activity) = activity_proxy(self.activity_id).map(|p| p.activity.clone()) {
|
||||
if let Some(activity) = activity_proxy(activity_id).map(|p| p.activity.clone()) {
|
||||
match self
|
||||
.env
|
||||
.call_method(activity, "getVersion", "()Ljava/lang/String;", &[])
|
||||
@@ -385,7 +398,7 @@ impl<'a> MainPipe<'a> {
|
||||
}
|
||||
}
|
||||
WebViewMessage::GetUrl(tx) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
let url = self
|
||||
.env
|
||||
.call_method(webview.as_obj(), "getUrl", "()Ljava/lang/String;", &[])
|
||||
@@ -403,7 +416,7 @@ impl<'a> MainPipe<'a> {
|
||||
}
|
||||
}
|
||||
WebViewMessage::Jni(f) => {
|
||||
match activity_proxy(self.activity_id).map(|p| (p.activity.clone(), p.webview.clone())) {
|
||||
match activity_proxy(activity_id).map(|p| (p.activity.clone(), p.webview.clone())) {
|
||||
Some((activity, Some(webview))) => {
|
||||
f(&mut self.env, &activity, webview.as_obj());
|
||||
}
|
||||
@@ -416,31 +429,31 @@ impl<'a> MainPipe<'a> {
|
||||
}
|
||||
}
|
||||
WebViewMessage::LoadUrl(url, headers) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
let url = self.env.new_string(url)?;
|
||||
load_url(&mut self.env, webview.as_obj(), &url, headers, false)?;
|
||||
}
|
||||
}
|
||||
WebViewMessage::ClearAllBrowsingData => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
self
|
||||
.env
|
||||
.call_method(webview, "clearAllBrowsingData", "()V", &[])?;
|
||||
}
|
||||
}
|
||||
WebViewMessage::LoadHtml(html) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
let html = self.env.new_string(html)?;
|
||||
load_html(&mut self.env, webview.as_obj(), &html)?;
|
||||
}
|
||||
}
|
||||
WebViewMessage::Reload => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
reload(&mut self.env, webview.as_obj())?;
|
||||
}
|
||||
}
|
||||
WebViewMessage::GetCookies(tx, url) => {
|
||||
if let Some(webview) = get_webview(self.activity_id) {
|
||||
if let Some(webview) = get_webview(activity_id) {
|
||||
let url = self.env.new_string(url)?;
|
||||
let cookies = self
|
||||
.env
|
||||
@@ -478,12 +491,11 @@ impl<'a> MainPipe<'a> {
|
||||
// e.g. rotation, multi-window mode change, etc
|
||||
if !is_changing_configurations {
|
||||
super::destroy_webview(activity_id, &webview_id);
|
||||
return Ok(MainPipeState::Destroyed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(MainPipeState::Alive)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use super::{PageLoadEvent, WebViewAttributes, RGBA};
|
||||
use crate::{RequestAsyncResponder, Result};
|
||||
use crate::{Error, RequestAsyncResponder, Result};
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use crossbeam_channel::*;
|
||||
use html5ever::{interface::QualName, namespace_url, ns, tendril::TendrilSink, LocalName};
|
||||
@@ -17,14 +17,13 @@ use jni::{
|
||||
JNIEnv,
|
||||
};
|
||||
use kuchiki::NodeRef;
|
||||
use ndk::looper::{FdEvent, ThreadLooper};
|
||||
use ndk::looper::ThreadLooper;
|
||||
use once_cell::sync::OnceCell;
|
||||
use raw_window_handle::HasWindowHandle;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
os::fd::{AsFd as _, AsRawFd as _},
|
||||
sync::{mpsc::channel, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
@@ -32,8 +31,8 @@ use std::{
|
||||
pub(crate) mod binding;
|
||||
mod main_pipe;
|
||||
use main_pipe::{
|
||||
first_activity_id, last_activity_id, register_activity_proxy, ActivityId,
|
||||
CreateWebViewAttributes, MainPipe, MainPipeState, WebViewMessage,
|
||||
activity_id_for_window_manager, first_activity_id, register_activity_proxy, ActivityId,
|
||||
CreateWebViewAttributes, MainPipe, WebViewMessage,
|
||||
};
|
||||
|
||||
use crate::util::Counter;
|
||||
@@ -113,17 +112,31 @@ pub fn destroy_webview(activity_id: ActivityId, webview_id: &WebviewId) {
|
||||
pub unsafe fn android_setup(
|
||||
package: &str,
|
||||
mut env: JNIEnv,
|
||||
looper: &ThreadLooper,
|
||||
_looper: &ThreadLooper,
|
||||
activity: GlobalRef,
|
||||
) {
|
||||
PACKAGE.get_or_init(move || package.to_string());
|
||||
|
||||
let vm = env.get_java_vm().unwrap();
|
||||
|
||||
let activity_id = env
|
||||
.call_method(activity.as_obj(), "getId", "()I", &[])
|
||||
.unwrap()
|
||||
.i()
|
||||
.unwrap();
|
||||
|
||||
let window_manager = env
|
||||
.call_method(
|
||||
&activity,
|
||||
"getWindowManager",
|
||||
"()Landroid/view/WindowManager;",
|
||||
&[],
|
||||
)
|
||||
.unwrap()
|
||||
.l()
|
||||
.unwrap();
|
||||
let window_manager = env.new_global_ref(window_manager).unwrap();
|
||||
|
||||
// we must create the WebChromeClient here because it calls `registerForActivityResult`,
|
||||
// which gives an `LifecycleOwners must call register before they are STARTED.` error when called outside the onCreate hook
|
||||
let rust_webchrome_client_class = find_class(
|
||||
@@ -142,36 +155,13 @@ pub unsafe fn android_setup(
|
||||
|
||||
let webchrome_client = env.new_global_ref(webchrome_client).unwrap();
|
||||
|
||||
let activity_proxy = register_activity_proxy(activity_id, activity, webchrome_client);
|
||||
register_activity_proxy(vm, activity_id, activity, window_manager, webchrome_client);
|
||||
|
||||
if let Some(webview_attributes) = WEBVIEW_ATTRIBUTES.lock().unwrap().get(&activity_id) {
|
||||
MainPipe::send(
|
||||
activity_id,
|
||||
WebViewMessage::CreateWebView(webview_attributes.clone()),
|
||||
);
|
||||
} else {
|
||||
let mut main_pipe = MainPipe { env, activity_id };
|
||||
|
||||
looper
|
||||
.add_fd_with_callback(
|
||||
activity_proxy.pipe[0].as_fd(),
|
||||
FdEvent::INPUT,
|
||||
move |fd, _event| {
|
||||
let size = std::mem::size_of::<bool>();
|
||||
let mut wake = false;
|
||||
if libc::read(fd.as_raw_fd(), &mut wake as *mut _ as *mut _, size)
|
||||
== size as libc::ssize_t
|
||||
{
|
||||
let res = main_pipe.recv();
|
||||
// unregister itself on errors or destroy event
|
||||
matches!(res, Ok(MainPipeState::Alive))
|
||||
} else {
|
||||
// unregister itself
|
||||
false
|
||||
}
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,19 +172,27 @@ pub(crate) struct InnerWebView {
|
||||
|
||||
impl InnerWebView {
|
||||
pub fn new_as_child(
|
||||
_window: &impl HasWindowHandle,
|
||||
window: &impl HasWindowHandle,
|
||||
attributes: WebViewAttributes,
|
||||
pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
) -> Result<Self> {
|
||||
Self::new(_window, attributes, pl_attrs)
|
||||
Self::new(window, attributes, pl_attrs)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
_window: &impl HasWindowHandle,
|
||||
window: &impl HasWindowHandle,
|
||||
attributes: WebViewAttributes,
|
||||
pl_attrs: super::PlatformSpecificWebViewAttributes,
|
||||
) -> Result<Self> {
|
||||
let activity_id = last_activity_id().expect("no available activity");
|
||||
let window_manager = match window.window_handle()?.as_raw() {
|
||||
raw_window_handle::RawWindowHandle::AndroidNdk(window_manager) => {
|
||||
window_manager.a_native_window
|
||||
}
|
||||
_ => return Err(Error::UnsupportedWindowHandle),
|
||||
};
|
||||
let window_manager = unsafe { JObject::from_raw(window_manager.as_ptr().cast()) };
|
||||
let activity_id =
|
||||
activity_id_for_window_manager(window_manager).expect("no available activity");
|
||||
let WebViewAttributes {
|
||||
url,
|
||||
html,
|
||||
|
||||
Reference in New Issue
Block a user