From 320b26daaa9baba0fe397355a28515f8787087bc Mon Sep 17 00:00:00 2001 From: Jason Tsai Date: Sun, 8 Sep 2024 16:41:46 +0800 Subject: [PATCH] WIP: refactor(ios): add wkwebview for ios --- Cargo.toml | 49 +- src/lib.rs | 14 +- src/wkwebview/class/url_scheme_handler.rs | 29 +- .../class/wry_navigation_delegate.rs | 7 +- src/wkwebview/class/wry_web_view.rs | 18 +- src/wkwebview/class/wry_web_view_parent.rs | 9 +- .../class/wry_web_view_ui_delegate.rs | 13 +- src/wkwebview/download.rs | 7 +- src/wkwebview/ios/WKWebView.rs | 621 ++++++++++++++++++ src/wkwebview/ios/mod.rs | 1 + src/wkwebview/mod.rs | 77 ++- src/wkwebview/navigation.rs | 10 +- 12 files changed, 777 insertions(+), 78 deletions(-) create mode 100644 src/wkwebview/ios/WKWebView.rs create mode 100644 src/wkwebview/ios/mod.rs diff --git a/Cargo.toml b/Cargo.toml index eafef3fae..1e7e5085e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ workspace = {} [package] name = "wry" version = "0.43.1" -authors = [ "Tauri Programme within The Commons Conservancy" ] +authors = ["Tauri Programme within The Commons Conservancy"] edition = "2021" license = "Apache-2.0 OR MIT" description = "Cross-platform WebView rendering library" @@ -25,16 +25,16 @@ rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"] [features] -default = [ "drag-drop", "objc-exception", "protocol", "os-webview" ] -serde = [ "dpi/serde" ] +default = ["drag-drop", "objc-exception", "protocol", "os-webview"] +serde = ["dpi/serde"] objc-exception = ["objc2/exception"] -drag-drop = [ ] -protocol = [ ] -devtools = [ ] -transparent = [ ] -fullscreen = [ ] -linux-body = [ "webkit2gtk/v2_40", "os-webview" ] -mac-proxy = [ ] +drag-drop = [] +protocol = [] +devtools = [] +transparent = [] +fullscreen = [] +linux-body = ["webkit2gtk/v2_40", "os-webview"] +mac-proxy = [] os-webview = [ "javascriptcore-rs", "webkit2gtk", @@ -51,12 +51,14 @@ tracing = { version = "0.1", optional = true } once_cell = "1" thiserror = "1.0" http = "1.1" -raw-window-handle = { version = "0.6", features = [ "std" ] } +raw-window-handle = { version = "0.6", features = ["std"] } dpi = "0.1" [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] -javascriptcore-rs = { version = "=1.1.2", features = [ "v2_28" ], optional = true } -webkit2gtk = { version = "=2.0.1", features = [ "v2_38" ], optional = true } +javascriptcore-rs = { version = "=1.1.2", features = [ + "v2_28", +], optional = true } +webkit2gtk = { version = "=2.0.1", features = ["v2_38"], optional = true } webkit2gtk-sys = { version = "=2.0.1", optional = true } gtk = { version = "0.18", optional = true } soup3 = { version = "0.5", optional = true } @@ -133,7 +135,21 @@ objc2-foundation = { version = "0.2.0", features = [ "NSDate", "NSBundle", "NSProcessInfo", + "NSValue", + "NSRange", ] } + +[target."cfg(target_os = \"ios\")".dependencies] +objc2-ui-kit = { version = "0.2.2", features = [ + "UIResponder", + "UIScrollView", + "UIView", + "UIWindow", + "UIApplication", + "UIEvent", +] } + +[target."cfg(target_os = \"macos\")".dependencies] objc2-app-kit = { version = "0.2.0", features = [ "NSApplication", "NSEvent", @@ -146,11 +162,6 @@ objc2-app-kit = { version = "0.2.0", features = [ "NSSavePanel", "NSMenu", ] } -objc2-ui-kit = { version = "0.2.2", features = [ - "UIResponder", - "UIScrollView", - "UIView", -] } [target."cfg(target_os = \"android\")".dependencies] crossbeam-channel = "0.5" @@ -174,4 +185,4 @@ percent-encoding = "2.3" [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [ "cfg(linux)", "cfg(gtk)" ] +check-cfg = ["cfg(linux)", "cfg(gtk)"] diff --git a/src/lib.rs b/src/lib.rs index 105102952..6842938c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -230,7 +230,7 @@ use webkitgtk::*; #[cfg(any(target_os = "macos", target_os = "ios"))] use objc2::rc::Retained; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "macos"))] use objc2_app_kit::NSWindow; #[cfg(any(target_os = "macos", target_os = "ios"))] use objc2_web_kit::WKUserContentController; @@ -1685,19 +1685,19 @@ impl WebViewExtMacOS for WebView { #[cfg(target_os = "ios")] pub trait WebViewExtIOS { /// Returns WKWebView handle - fn webview(&self) -> cocoa::base::id; + fn webview(&self) -> Retained; /// Returns WKWebView manager [(userContentController)](https://developer.apple.com/documentation/webkit/wkscriptmessagehandler/1396222-usercontentcontroller) handle - fn manager(&self) -> cocoa::base::id; + fn manager(&self) -> Retained; } #[cfg(target_os = "ios")] impl WebViewExtIOS for WebView { - fn webview(&self) -> cocoa::base::id { - self.webview.webview + fn webview(&self) -> Retained { + self.webview.webview.clone() } - fn manager(&self) -> cocoa::base::id { - self.webview.manager + fn manager(&self) -> Retained { + self.webview.manager.clone() } } diff --git a/src/wkwebview/class/url_scheme_handler.rs b/src/wkwebview/class/url_scheme_handler.rs index 32902417a..d4668350a 100644 --- a/src/wkwebview/class/url_scheme_handler.rs +++ b/src/wkwebview/class/url_scheme_handler.rs @@ -2,25 +2,24 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::borrow::Cow; -use std::ffi::c_void; -use std::panic::AssertUnwindSafe; -use std::ptr::NonNull; -use std::slice; - -use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; -use http::{Request, Response as HttpResponse, StatusCode, Version}; -use objc2::rc::Retained; -use objc2::runtime::{AnyClass, AnyObject, ClassBuilder, ProtocolObject}; -use objc2::ClassType; -use objc2_foundation::NSObjectProtocol; +use std::{borrow::Cow, ffi::c_void, panic::AssertUnwindSafe, ptr::NonNull, slice}; + +use http::{ + header::{CONTENT_LENGTH, CONTENT_TYPE}, + Request, Response as HttpResponse, StatusCode, Version, +}; +use objc2::{ + rc::Retained, + runtime::{AnyClass, AnyObject, ClassBuilder, ProtocolObject}, + ClassType, +}; use objc2_foundation::{ - NSData, NSHTTPURLResponse, NSMutableDictionary, NSObject, NSString, NSURL, NSUUID, + NSData, NSHTTPURLResponse, NSMutableDictionary, NSObject, NSObjectProtocol, NSString, NSURL, + NSUUID, }; use objc2_web_kit::{WKURLSchemeHandler, WKURLSchemeTask}; -use crate::wkwebview::WEBVIEW_IDS; -use crate::{RequestAsyncResponder, WryWebView}; +use crate::{wkwebview::WEBVIEW_IDS, RequestAsyncResponder, WryWebView}; pub fn create(name: &str) -> &AnyClass { unsafe { diff --git a/src/wkwebview/class/wry_navigation_delegate.rs b/src/wkwebview/class/wry_navigation_delegate.rs index 14c644b0d..82cc67a74 100644 --- a/src/wkwebview/class/wry_navigation_delegate.rs +++ b/src/wkwebview/class/wry_navigation_delegate.rs @@ -11,9 +11,14 @@ use objc2::{ use objc2_foundation::{MainThreadMarker, NSObjectProtocol}; use objc2_web_kit::{ WKDownload, WKNavigation, WKNavigationAction, WKNavigationActionPolicy, WKNavigationDelegate, - WKNavigationResponse, WKNavigationResponsePolicy, WKWebView, + WKNavigationResponse, WKNavigationResponsePolicy, }; +#[cfg(target_os = "ios")] +use crate::wkwebview::ios::WKWebView::WKWebView; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKWebView; + use crate::{ url_from_webview, wkwebview::{ diff --git a/src/wkwebview/class/wry_web_view.rs b/src/wkwebview/class/wry_web_view.rs index ef716e75f..0ebd7e762 100644 --- a/src/wkwebview/class/wry_web_view.rs +++ b/src/wkwebview/class/wry_web_view.rs @@ -4,21 +4,26 @@ use std::collections::HashMap; +#[cfg(target_os = "macos")] +use objc2::runtime::ProtocolObject; use objc2::{ - declare_class, - mutability::MainThreadOnly, - rc::Retained, - runtime::{Bool, ProtocolObject}, - ClassType, DeclaredClass, + declare_class, mutability::MainThreadOnly, rc::Retained, runtime::Bool, ClassType, DeclaredClass, }; +#[cfg(target_os = "macos")] use objc2_app_kit::{NSDraggingDestination, NSEvent}; use objc2_foundation::{NSObjectProtocol, NSUUID}; -use objc2_web_kit::WKWebView; +#[cfg(target_os = "ios")] +use crate::wkwebview::ios::WKWebView::WKWebView; +#[cfg(target_os = "macos")] use crate::{ wkwebview::{drag_drop, synthetic_mouse_events}, DragDropEvent, }; +#[cfg(target_os = "ios")] +use objc2_ui_kit::UIEvent as NSEvent; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKWebView; pub struct WryWebViewIvars { pub(crate) is_child: bool, @@ -62,6 +67,7 @@ declare_class!( } } + #[cfg(target_os = "macos")] #[method(acceptsFirstMouse:)] fn accept_first_mouse( &self, diff --git a/src/wkwebview/class/wry_web_view_parent.rs b/src/wkwebview/class/wry_web_view_parent.rs index c212967a9..95ef05c50 100644 --- a/src/wkwebview/class/wry_web_view_parent.rs +++ b/src/wkwebview/class/wry_web_view_parent.rs @@ -5,8 +5,11 @@ use objc2::{ declare_class, msg_send_id, mutability::MainThreadOnly, rc::Retained, ClassType, DeclaredClass, }; -use objc2_app_kit::{NSApp, NSEvent, NSView}; +#[cfg(target_os = "macos")] +use objc2_app_kit::{NSApplication, NSEvent, NSView}; use objc2_foundation::MainThreadMarker; +#[cfg(target_os = "ios")] +use objc2_ui_kit::UIView as NSView; pub struct WryWebViewParentIvars {} @@ -24,13 +27,14 @@ declare_class!( } unsafe impl WryWebViewParent { + #[cfg(target_os = "macos")] #[method(keyDown:)] fn key_down( &self, event: &NSEvent, ) { let mtm = MainThreadMarker::new().unwrap(); - let app = NSApp(mtm); + let app = NSApplication::sharedApplication(mtm); unsafe { if let Some(menu) = app.mainMenu() { menu.performKeyEquivalent(event); @@ -41,6 +45,7 @@ declare_class!( ); impl WryWebViewParent { + #[allow(dead_code)] pub fn new(mtm: MainThreadMarker) -> Retained { let delegate = mtm .alloc::() diff --git a/src/wkwebview/class/wry_web_view_ui_delegate.rs b/src/wkwebview/class/wry_web_view_ui_delegate.rs index d7bbed8fc..d436a29a4 100644 --- a/src/wkwebview/class/wry_web_view_ui_delegate.rs +++ b/src/wkwebview/class/wry_web_view_ui_delegate.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +#[cfg(target_os = "macos")] use std::ptr::null_mut; use block2::Block; @@ -9,11 +10,16 @@ use objc2::{ declare_class, msg_send_id, mutability::MainThreadOnly, rc::Retained, runtime::NSObject, ClassType, DeclaredClass, }; +#[cfg(target_os = "macos")] use objc2_app_kit::{NSModalResponse, NSModalResponseOK, NSOpenPanel}; -use objc2_foundation::{MainThreadMarker, NSArray, NSObjectProtocol, NSURL}; +use objc2_foundation::{MainThreadMarker, NSObjectProtocol}; +#[cfg(target_os = "macos")] +use objc2_foundation::{NSArray, NSURL}; + +#[cfg(target_os = "macos")] +use objc2_web_kit::WKOpenPanelParameters; use objc2_web_kit::{ - WKFrameInfo, WKMediaCaptureType, WKOpenPanelParameters, WKPermissionDecision, WKSecurityOrigin, - WKUIDelegate, + WKFrameInfo, WKMediaCaptureType, WKPermissionDecision, WKSecurityOrigin, WKUIDelegate, }; use crate::WryWebView; @@ -36,6 +42,7 @@ declare_class!( unsafe impl NSObjectProtocol for WryWebViewUIDelegate {} unsafe impl WKUIDelegate for WryWebViewUIDelegate { + #[cfg(target_os = "macos")] #[method(webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:)] fn run_file_upload_panel( &self, diff --git a/src/wkwebview/download.rs b/src/wkwebview/download.rs index cb4da2d33..0f6724a62 100644 --- a/src/wkwebview/download.rs +++ b/src/wkwebview/download.rs @@ -2,7 +2,12 @@ use std::{path::PathBuf, ptr::null_mut}; use objc2::{rc::Retained, runtime::ProtocolObject, DeclaredClass}; use objc2_foundation::{NSData, NSError, NSString, NSURLResponse, NSURL}; -use objc2_web_kit::{WKDownload, WKNavigationAction, WKNavigationResponse, WKWebView}; +use objc2_web_kit::{WKDownload, WKNavigationAction, WKNavigationResponse}; + +#[cfg(target_os = "ios")] +use crate::wkwebview::ios::WKWebView::WKWebView; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKWebView; use super::class::{ wry_download_delegate::WryDownloadDelegate, wry_navigation_delegate::WryNavigationDelegate, diff --git a/src/wkwebview/ios/WKWebView.rs b/src/wkwebview/ios/WKWebView.rs new file mode 100644 index 000000000..72462cda6 --- /dev/null +++ b/src/wkwebview/ios/WKWebView.rs @@ -0,0 +1,621 @@ +#![allow(warnings)] +#![allow(clippy::all)] + +//! This file has been automatically generated by `objc2`'s `header-translator`. +//! DO NOT EDIT +use objc2::__framework_prelude::*; +use objc2_foundation::*; +use objc2_ui_kit::*; +use objc2_web_kit::*; + +use crate::*; + +// NS_ENUM +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct WKMediaPlaybackState(pub NSInteger); +impl WKMediaPlaybackState { + #[doc(alias = "WKMediaPlaybackStateNone")] + pub const None: Self = Self(0); + #[doc(alias = "WKMediaPlaybackStatePlaying")] + pub const Playing: Self = Self(1); + #[doc(alias = "WKMediaPlaybackStatePaused")] + pub const Paused: Self = Self(2); + #[doc(alias = "WKMediaPlaybackStateSuspended")] + pub const Suspended: Self = Self(3); +} + +unsafe impl Encode for WKMediaPlaybackState { + const ENCODING: Encoding = NSInteger::ENCODING; +} + +unsafe impl RefEncode for WKMediaPlaybackState { + const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); +} + +// NS_ENUM +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct WKMediaCaptureState(pub NSInteger); +impl WKMediaCaptureState { + #[doc(alias = "WKMediaCaptureStateNone")] + pub const None: Self = Self(0); + #[doc(alias = "WKMediaCaptureStateActive")] + pub const Active: Self = Self(1); + #[doc(alias = "WKMediaCaptureStateMuted")] + pub const Muted: Self = Self(2); +} + +unsafe impl Encode for WKMediaCaptureState { + const ENCODING: Encoding = NSInteger::ENCODING; +} + +unsafe impl RefEncode for WKMediaCaptureState { + const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); +} + +// NS_ENUM +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct WKFullscreenState(pub NSInteger); +impl WKFullscreenState { + #[doc(alias = "WKFullscreenStateNotInFullscreen")] + pub const NotInFullscreen: Self = Self(0); + #[doc(alias = "WKFullscreenStateEnteringFullscreen")] + pub const EnteringFullscreen: Self = Self(1); + #[doc(alias = "WKFullscreenStateInFullscreen")] + pub const InFullscreen: Self = Self(2); + #[doc(alias = "WKFullscreenStateExitingFullscreen")] + pub const ExitingFullscreen: Self = Self(3); +} + +unsafe impl Encode for WKFullscreenState { + const ENCODING: Encoding = NSInteger::ENCODING; +} + +unsafe impl RefEncode for WKFullscreenState { + const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING); +} + +extern_class!( + #[derive(Debug, PartialEq, Eq, Hash)] + pub struct WKWebView; + + unsafe impl ClassType for WKWebView { + #[inherits(UIResponder, NSObject)] + type Super = UIView; + type Mutability = MainThreadOnly; + } +); + +#[cfg(target_os = "macos")] +unsafe impl NSAccessibility for WKWebView {} + +#[cfg(target_os = "macos")] +unsafe impl NSAccessibilityElementProtocol for WKWebView {} + +#[cfg(target_os = "macos")] +unsafe impl NSAnimatablePropertyContainer for WKWebView {} + +#[cfg(target_os = "macos")] +unsafe impl NSAppearanceCustomization for WKWebView {} + +unsafe impl NSCoding for WKWebView {} + +#[cfg(target_os = "macos")] +unsafe impl NSDraggingDestination for WKWebView {} + +unsafe impl NSObjectProtocol for WKWebView {} + +#[cfg(target_os = "macos")] +unsafe impl NSUserInterfaceItemIdentification for WKWebView {} + +extern_methods!( + unsafe impl WKWebView { + // #[cfg(feature = "WKWebViewConfiguration")] + #[method_id(@__retain_semantics Other configuration)] + pub unsafe fn configuration(&self) -> Retained; + + // #[cfg(feature = "WKNavigationDelegate")] + #[method_id(@__retain_semantics Other navigationDelegate)] + pub unsafe fn navigationDelegate( + &self, + ) -> Option>>; + + // #[cfg(feature = "WKNavigationDelegate")] + #[method(setNavigationDelegate:)] + pub unsafe fn setNavigationDelegate( + &self, + navigation_delegate: Option<&ProtocolObject>, + ); + + // #[cfg(feature = "WKUIDelegate")] + #[method_id(@__retain_semantics Other UIDelegate)] + pub unsafe fn UIDelegate(&self) -> Option>>; + + // #[cfg(feature = "WKUIDelegate")] + #[method(setUIDelegate:)] + pub unsafe fn setUIDelegate(&self, ui_delegate: Option<&ProtocolObject>); + + #[cfg(target_os = "macos")] + // #[cfg(feature = "WKBackForwardList")] + #[method_id(@__retain_semantics Other backForwardList)] + pub unsafe fn backForwardList(&self) -> Retained; + + // #[cfg(feature = "WKWebViewConfiguration")] + #[method_id(@__retain_semantics Init initWithFrame:configuration:)] + pub unsafe fn initWithFrame_configuration( + this: Allocated, + frame: CGRect, + configuration: &WKWebViewConfiguration, + ) -> Retained; + + #[method_id(@__retain_semantics Init initWithCoder:)] + pub unsafe fn initWithCoder(this: Allocated, coder: &NSCoder) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadRequest:)] + pub unsafe fn loadRequest(&self, request: &NSURLRequest) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadFileURL:allowingReadAccessToURL:)] + pub unsafe fn loadFileURL_allowingReadAccessToURL( + &self, + url: &NSURL, + read_access_url: &NSURL, + ) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadHTMLString:baseURL:)] + pub unsafe fn loadHTMLString_baseURL( + &self, + string: &NSString, + base_url: Option<&NSURL>, + ) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadData:MIMEType:characterEncodingName:baseURL:)] + pub unsafe fn loadData_MIMEType_characterEncodingName_baseURL( + &self, + data: &NSData, + mime_type: &NSString, + character_encoding_name: &NSString, + base_url: &NSURL, + ) -> Option>; + + #[cfg(target_os = "macos")] + // #[cfg(all(feature = "WKBackForwardListItem", feature = "WKNavigation"))] + #[method_id(@__retain_semantics Other goToBackForwardListItem:)] + pub unsafe fn goToBackForwardListItem( + &self, + item: &WKBackForwardListItem, + ) -> Option>; + + #[method_id(@__retain_semantics Other title)] + pub unsafe fn title(&self) -> Option>; + + #[method_id(@__retain_semantics Other URL)] + pub unsafe fn URL(&self) -> Option>; + + #[method(isLoading)] + pub unsafe fn isLoading(&self) -> bool; + + #[method(estimatedProgress)] + pub unsafe fn estimatedProgress(&self) -> c_double; + + #[method(hasOnlySecureContent)] + pub unsafe fn hasOnlySecureContent(&self) -> bool; + + #[method(canGoBack)] + pub unsafe fn canGoBack(&self) -> bool; + + #[method(canGoForward)] + pub unsafe fn canGoForward(&self) -> bool; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other goBack)] + pub unsafe fn goBack(&self) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other goForward)] + pub unsafe fn goForward(&self) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other reload)] + pub unsafe fn reload(&self) -> Option>; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other reloadFromOrigin)] + pub unsafe fn reloadFromOrigin(&self) -> Option>; + + #[method(stopLoading)] + pub unsafe fn stopLoading(&self); + + // #[cfg(feature = "block2")] + #[method(evaluateJavaScript:completionHandler:)] + pub unsafe fn evaluateJavaScript_completionHandler( + &self, + java_script_string: &NSString, + completion_handler: Option<&block2::Block>, + ); + + #[cfg(target_os = "macos")] + // #[cfg(all( + // feature = "WKContentWorld", + // feature = "WKFrameInfo", + // feature = "block2" + // ))] + #[method(evaluateJavaScript:inFrame:inContentWorld:completionHandler:)] + pub unsafe fn evaluateJavaScript_inFrame_inContentWorld_completionHandler( + &self, + java_script_string: &NSString, + frame: Option<&WKFrameInfo>, + content_world: &WKContentWorld, + completion_handler: Option<&block2::Block>, + ); + + #[cfg(target_os = "macos")] + // #[cfg(all( + // feature = "WKContentWorld", + // feature = "WKFrameInfo", + // feature = "block2" + // ))] + #[method(callAsyncJavaScript:arguments:inFrame:inContentWorld:completionHandler:)] + pub unsafe fn callAsyncJavaScript_arguments_inFrame_inContentWorld_completionHandler( + &self, + function_body: &NSString, + arguments: Option<&NSDictionary>, + frame: Option<&WKFrameInfo>, + content_world: &WKContentWorld, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[method(closeAllMediaPresentationsWithCompletionHandler:)] + pub unsafe fn closeAllMediaPresentationsWithCompletionHandler( + &self, + completion_handler: Option<&block2::Block>, + ); + + #[deprecated] + #[method(closeAllMediaPresentations)] + pub unsafe fn closeAllMediaPresentations(&self); + + // #[cfg(feature = "block2")] + #[method(pauseAllMediaPlaybackWithCompletionHandler:)] + pub unsafe fn pauseAllMediaPlaybackWithCompletionHandler( + &self, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[deprecated] + #[method(pauseAllMediaPlayback:)] + pub unsafe fn pauseAllMediaPlayback( + &self, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[method(setAllMediaPlaybackSuspended:completionHandler:)] + pub unsafe fn setAllMediaPlaybackSuspended_completionHandler( + &self, + suspended: bool, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[deprecated] + #[method(resumeAllMediaPlayback:)] + pub unsafe fn resumeAllMediaPlayback( + &self, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[deprecated] + #[method(suspendAllMediaPlayback:)] + pub unsafe fn suspendAllMediaPlayback( + &self, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[method(requestMediaPlaybackStateWithCompletionHandler:)] + pub unsafe fn requestMediaPlaybackStateWithCompletionHandler( + &self, + completion_handler: &block2::Block, + ); + + // #[cfg(feature = "block2")] + #[deprecated] + #[method(requestMediaPlaybackState:)] + pub unsafe fn requestMediaPlaybackState( + &self, + completion_handler: &block2::Block, + ); + + #[method(cameraCaptureState)] + pub unsafe fn cameraCaptureState(&self) -> WKMediaCaptureState; + + #[method(microphoneCaptureState)] + pub unsafe fn microphoneCaptureState(&self) -> WKMediaCaptureState; + + // #[cfg(feature = "block2")] + #[method(setCameraCaptureState:completionHandler:)] + pub unsafe fn setCameraCaptureState_completionHandler( + &self, + state: WKMediaCaptureState, + completion_handler: Option<&block2::Block>, + ); + + // #[cfg(feature = "block2")] + #[method(setMicrophoneCaptureState:completionHandler:)] + pub unsafe fn setMicrophoneCaptureState_completionHandler( + &self, + state: WKMediaCaptureState, + completion_handler: Option<&block2::Block>, + ); + + #[cfg(target_os = "macos")] + // #[cfg(all(feature = "WKSnapshotConfiguration", feature = "block2"))] + #[method(takeSnapshotWithConfiguration:completionHandler:)] + pub unsafe fn takeSnapshotWithConfiguration_completionHandler( + &self, + snapshot_configuration: Option<&WKSnapshotConfiguration>, + completion_handler: &block2::Block, + ); + + #[cfg(target_os = "macos")] + // #[cfg(all(feature = "WKPDFConfiguration", feature = "block2"))] + #[method(createPDFWithConfiguration:completionHandler:)] + pub unsafe fn createPDFWithConfiguration_completionHandler( + &self, + pdf_configuration: Option<&WKPDFConfiguration>, + completion_handler: &block2::Block, + ); + + // #[cfg(feature = "block2")] + #[method(createWebArchiveDataWithCompletionHandler:)] + pub unsafe fn createWebArchiveDataWithCompletionHandler( + &self, + completion_handler: &block2::Block, NonNull)>, + ); + + #[method(allowsBackForwardNavigationGestures)] + pub unsafe fn allowsBackForwardNavigationGestures(&self) -> bool; + + #[method(setAllowsBackForwardNavigationGestures:)] + pub unsafe fn setAllowsBackForwardNavigationGestures( + &self, + allows_back_forward_navigation_gestures: bool, + ); + + #[method_id(@__retain_semantics Other customUserAgent)] + pub unsafe fn customUserAgent(&self) -> Option>; + + #[method(setCustomUserAgent:)] + pub unsafe fn setCustomUserAgent(&self, custom_user_agent: Option<&NSString>); + + #[method(allowsLinkPreview)] + pub unsafe fn allowsLinkPreview(&self) -> bool; + + #[method(setAllowsLinkPreview:)] + pub unsafe fn setAllowsLinkPreview(&self, allows_link_preview: bool); + + #[method(allowsMagnification)] + pub unsafe fn allowsMagnification(&self) -> bool; + + #[method(setAllowsMagnification:)] + pub unsafe fn setAllowsMagnification(&self, allows_magnification: bool); + + #[method(magnification)] + pub unsafe fn magnification(&self) -> CGFloat; + + #[method(setMagnification:)] + pub unsafe fn setMagnification(&self, magnification: CGFloat); + + #[method(setMagnification:centeredAtPoint:)] + pub unsafe fn setMagnification_centeredAtPoint(&self, magnification: CGFloat, point: CGPoint); + + #[method(pageZoom)] + pub unsafe fn pageZoom(&self) -> CGFloat; + + #[method(setPageZoom:)] + pub unsafe fn setPageZoom(&self, page_zoom: CGFloat); + + #[cfg(target_os = "macos")] + // #[cfg(all( + // feature = "WKFindConfiguration", + // feature = "WKFindResult", + // feature = "block2" + // ))] + #[method(findString:withConfiguration:completionHandler:)] + pub unsafe fn findString_withConfiguration_completionHandler( + &self, + string: &NSString, + configuration: Option<&WKFindConfiguration>, + completion_handler: &block2::Block)>, + ); + + #[method(handlesURLScheme:)] + pub unsafe fn handlesURLScheme(url_scheme: &NSString, mtm: MainThreadMarker) -> bool; + + // #[cfg(all(feature = "WKDownload", feature = "block2"))] + #[method(startDownloadUsingRequest:completionHandler:)] + pub unsafe fn startDownloadUsingRequest_completionHandler( + &self, + request: &NSURLRequest, + completion_handler: &block2::Block)>, + ); + + // #[cfg(all(feature = "WKDownload", feature = "block2"))] + #[method(resumeDownloadFromResumeData:completionHandler:)] + pub unsafe fn resumeDownloadFromResumeData_completionHandler( + &self, + resume_data: &NSData, + completion_handler: &block2::Block)>, + ); + + #[method_id(@__retain_semantics Other mediaType)] + pub unsafe fn mediaType(&self) -> Option>; + + #[method(setMediaType:)] + pub unsafe fn setMediaType(&self, media_type: Option<&NSString>); + + #[method_id(@__retain_semantics Other interactionState)] + pub unsafe fn interactionState(&self) -> Option>; + + #[method(setInteractionState:)] + pub unsafe fn setInteractionState(&self, interaction_state: Option<&AnyObject>); + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadSimulatedRequest:response:responseData:)] + pub unsafe fn loadSimulatedRequest_response_responseData( + &self, + request: &NSURLRequest, + response: &NSURLResponse, + data: &NSData, + ) -> Retained; + + // #[cfg(feature = "WKNavigation")] + #[deprecated] + #[method_id(@__retain_semantics Other loadSimulatedRequest:withResponse:responseData:)] + pub unsafe fn loadSimulatedRequest_withResponse_responseData( + &self, + request: &NSURLRequest, + response: &NSURLResponse, + data: &NSData, + ) -> Retained; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadFileRequest:allowingReadAccessToURL:)] + pub unsafe fn loadFileRequest_allowingReadAccessToURL( + &self, + request: &NSURLRequest, + read_access_url: &NSURL, + ) -> Retained; + + // #[cfg(feature = "WKNavigation")] + #[method_id(@__retain_semantics Other loadSimulatedRequest:responseHTMLString:)] + pub unsafe fn loadSimulatedRequest_responseHTMLString( + &self, + request: &NSURLRequest, + string: &NSString, + ) -> Retained; + + // #[cfg(feature = "WKNavigation")] + #[deprecated] + #[method_id(@__retain_semantics Other loadSimulatedRequest:withResponseHTMLString:)] + pub unsafe fn loadSimulatedRequest_withResponseHTMLString( + &self, + request: &NSURLRequest, + string: &NSString, + ) -> Retained; + + #[cfg(target_os = "macos")] + #[method_id(@__retain_semantics Other printOperationWithPrintInfo:)] + pub unsafe fn printOperationWithPrintInfo( + &self, + print_info: &NSPrintInfo, + ) -> Retained; + + #[cfg(target_os = "macos")] + #[method_id(@__retain_semantics Other themeColor)] + pub unsafe fn themeColor(&self) -> Option>; + + #[cfg(target_os = "macos")] + #[method_id(@__retain_semantics Other underPageBackgroundColor)] + pub unsafe fn underPageBackgroundColor(&self) -> Retained; + + #[cfg(target_os = "macos")] + #[method(setUnderPageBackgroundColor:)] + pub unsafe fn setUnderPageBackgroundColor(&self, under_page_background_color: Option<&NSColor>); + + #[method(fullscreenState)] + pub unsafe fn fullscreenState(&self) -> WKFullscreenState; + + #[method(minimumViewportInset)] + pub unsafe fn minimumViewportInset(&self) -> NSEdgeInsets; + + #[method(maximumViewportInset)] + pub unsafe fn maximumViewportInset(&self) -> NSEdgeInsets; + + #[method(setMinimumViewportInset:maximumViewportInset:)] + pub unsafe fn setMinimumViewportInset_maximumViewportInset( + &self, + minimum_viewport_inset: NSEdgeInsets, + maximum_viewport_inset: NSEdgeInsets, + ); + + #[method(isInspectable)] + pub unsafe fn isInspectable(&self) -> bool; + + #[method(setInspectable:)] + pub unsafe fn setInspectable(&self, inspectable: bool); + } +); + +extern_methods!( + /// Methods declared on superclass `UIView` + unsafe impl WKWebView { + #[method_id(@__retain_semantics Init initWithFrame:)] + pub unsafe fn initWithFrame(this: Allocated, frame_rect: NSRect) -> Retained; + } +); + +extern_methods!( + /// Methods declared on superclass `UIResponder` + unsafe impl WKWebView { + #[method_id(@__retain_semantics Init init)] + pub unsafe fn init(this: Allocated) -> Retained; + } +); + +extern_methods!( + /// Methods declared on superclass `NSObject` + unsafe impl WKWebView { + #[method_id(@__retain_semantics New new)] + pub unsafe fn new(mtm: MainThreadMarker) -> Retained; + } +); + +extern_methods!( + /// WKIBActions + unsafe impl WKWebView { + #[method(goBack:)] + pub unsafe fn goBack_(&self, sender: Option<&AnyObject>); + + #[method(goForward:)] + pub unsafe fn goForward_(&self, sender: Option<&AnyObject>); + + #[method(reload:)] + pub unsafe fn reload_(&self, sender: Option<&AnyObject>); + + #[method(reloadFromOrigin:)] + pub unsafe fn reloadFromOrigin_(&self, sender: Option<&AnyObject>); + + #[method(stopLoading:)] + pub unsafe fn stopLoading_(&self, sender: Option<&AnyObject>); + } +); + +#[cfg(target_os = "macos")] +unsafe impl NSUserInterfaceValidations for WKWebView {} + +extern_methods!( + /// WKNSTextFinderClient + unsafe impl WKWebView {} +); + +#[cfg(target_os = "macos")] +unsafe impl NSTextFinderClient for WKWebView {} + +extern_methods!( + /// WKDeprecated + unsafe impl WKWebView { + #[deprecated] + #[method_id(@__retain_semantics Other certificateChain)] + pub unsafe fn certificateChain(&self) -> Retained; + } +); diff --git a/src/wkwebview/ios/mod.rs b/src/wkwebview/ios/mod.rs new file mode 100644 index 000000000..64ecbe707 --- /dev/null +++ b/src/wkwebview/ios/mod.rs @@ -0,0 +1 @@ +pub mod WKWebView; diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index b985ecbc9..aad64a461 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -12,35 +12,58 @@ mod proxy; mod synthetic_mouse_events; mod util; +#[cfg(target_os = "ios")] +mod ios; + mod class; -use class::url_scheme_handler; -use class::wry_download_delegate::WryDownloadDelegate; pub use class::wry_web_view::WryWebView; -use class::wry_web_view::WryWebViewIvars; -use class::wry_web_view_delegate::{WryWebViewDelegate, IPC_MESSAGE_HANDLER_NAME}; +#[cfg(target_os = "macos")] use class::wry_web_view_parent::WryWebViewParent; -use class::wry_web_view_ui_delegate::WryWebViewUIDelegate; -use class::{document_title_changed_observer::*, wry_navigation_delegate::WryNavigationDelegate}; +use class::{ + document_title_changed_observer::*, + url_scheme_handler, + wry_download_delegate::WryDownloadDelegate, + wry_navigation_delegate::WryNavigationDelegate, + wry_web_view::WryWebViewIvars, + wry_web_view_delegate::{WryWebViewDelegate, IPC_MESSAGE_HANDLER_NAME}, + wry_web_view_ui_delegate::WryWebViewUIDelegate, +}; use dpi::{LogicalPosition, LogicalSize}; +#[cfg(target_os = "macos")] +use objc2::runtime::Bool; use objc2::{ rc::Retained, - runtime::{AnyObject, Bool, NSObject, ProtocolObject}, + runtime::{AnyObject, NSObject, ProtocolObject}, ClassType, DeclaredClass, }; -use objc2_app_kit::{ - NSApplication, NSAutoresizingMaskOptions, NSTitlebarSeparatorStyle, NSView, NSWindow, -}; +#[cfg(target_os = "macos")] +use objc2_app_kit::{NSApplication, NSAutoresizingMaskOptions, NSTitlebarSeparatorStyle, NSView}; +#[cfg(target_os = "macos")] +use objc2_foundation::CGSize; use objc2_foundation::{ - ns_string, CGPoint, CGRect, CGSize, MainThreadMarker, NSBundle, NSDate, NSError, - NSJSONSerialization, NSMutableURLRequest, NSNumber, NSObjectNSKeyValueCoding, NSObjectProtocol, - NSString, NSUTF8StringEncoding, NSURL, NSUUID, + ns_string, CGPoint, CGRect, MainThreadMarker, NSBundle, NSDate, NSError, NSJSONSerialization, + NSMutableURLRequest, NSNumber, NSObjectNSKeyValueCoding, NSObjectProtocol, NSString, + NSUTF8StringEncoding, NSURL, NSUUID, }; #[cfg(target_os = "ios")] -use objc2_ui_kit::UIScrollView; +use objc2_ui_kit::{UIScrollView, UIViewAutoresizing}; + +#[cfg(target_os = "macos")] +use objc2_app_kit::NSWindow; +#[cfg(target_os = "ios")] +use objc2_ui_kit::UIView as NSView; +// #[cfg(target_os = "ios")] +// use objc2_ui_kit::UIWindow as NSWindow; + +#[cfg(target_os = "ios")] +use crate::wkwebview::ios::WKWebView::WKWebView; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKWebView; + use objc2_web_kit::{ WKAudiovisualMediaTypes, WKURLSchemeHandler, WKUserContentController, WKUserScript, - WKUserScriptInjectionTime, WKWebView, WKWebViewConfiguration, WKWebsiteDataStore, + WKUserScriptInjectionTime, WKWebViewConfiguration, WKWebsiteDataStore, }; use once_cell::sync::Lazy; use raw_window_handle::{HasWindowHandle, RawWindowHandle}; @@ -50,11 +73,13 @@ use std::{ ffi::c_void, os::raw::c_char, panic::AssertUnwindSafe, - ptr::null_mut, str, sync::{Arc, Mutex}, }; +#[cfg(target_os = "macos")] +use std::ptr::null_mut; + #[cfg(feature = "mac-proxy")] use crate::{ proxy::ProxyConfig, @@ -88,6 +113,7 @@ pub struct PrintOptions { pub(crate) struct InnerWebView { pub webview: Retained, pub manager: Retained, + #[allow(dead_code)] is_child: bool, pending_scripts: Arc>>>, // Note that if following functions signatures are changed in the future, @@ -330,7 +356,8 @@ impl InnerWebView { #[cfg(target_os = "ios")] let webview = { let frame = ns_view.frame(); - let webview = WKWebView::initWithFrame_configuration(webview, frame, &config); + let webview: Retained = + objc2::msg_send_id![super(webview), initWithFrame:frame configuration:&**config]; webview }; @@ -356,11 +383,14 @@ impl InnerWebView { #[cfg(target_os = "ios")] { // set all autoresizingmasks - webview.setAutoresizingMask(NSAutoresizingMaskOptions::from_bits(31).unwrap()); + webview.setAutoresizingMask(UIViewAutoresizing::from_bits(31).unwrap()); // let () = msg_send![webview, setAutoresizingMask: 31]; // disable scroll bounce by default - let scroll_view: UIScrollView = webview.scrollView(); // FIXME: not test yet + // https://developer.apple.com/documentation/webkit/wkwebview/1614784-scrollview?language=objc + // But not exist in objc2-web-kit + let scroll_view: Retained = objc2::msg_send_id![&webview, scrollView]; + // let scroll_view: Retained = webview.ivars().scrollView; // FIXME: not test yet scroll_view.setBounces(false) } @@ -733,6 +763,7 @@ r#"Object.defineProperty(window, 'ipc', { } pub fn bounds(&self) -> crate::Result { + #[allow(unused_unsafe)] unsafe { let parent = self.webview.superview().unwrap(); let parent_frame = parent.frame(); @@ -776,8 +807,11 @@ r#"Object.defineProperty(window, 'ipc', { } pub fn focus(&self) -> Result<()> { - let window = self.webview.window().unwrap(); - window.makeFirstResponder(Some(&self.webview)); + #[cfg(target_os = "macos")] + { + let window = self.webview.window().unwrap(); + window.makeFirstResponder(Some(&self.webview)); + } Ok(()) } @@ -856,6 +890,7 @@ impl Drop for InnerWebView { /// Converts from wry screen-coordinates to macOS screen-coordinates. /// wry: top-left is (0, 0) and y increasing downwards /// macOS: bottom-left is (0, 0) and y increasing upwards +#[allow(dead_code)] unsafe fn window_position(view: &NSView, x: i32, y: i32, height: f64) -> CGPoint { let frame: CGRect = view.frame(); CGPoint::new(x as f64, frame.size.height - y as f64 - height) diff --git a/src/wkwebview/navigation.rs b/src/wkwebview/navigation.rs index 4a5d2dbf9..9947412b4 100644 --- a/src/wkwebview/navigation.rs +++ b/src/wkwebview/navigation.rs @@ -1,11 +1,15 @@ use objc2::DeclaredClass; -use objc2_foundation::NSObjectProtocol; -use objc2_foundation::NSString; +use objc2_foundation::{NSObjectProtocol, NSString}; use objc2_web_kit::{ WKNavigation, WKNavigationAction, WKNavigationActionPolicy, WKNavigationResponse, - WKNavigationResponsePolicy, WKWebView, + WKNavigationResponsePolicy, }; +#[cfg(target_os = "ios")] +use crate::wkwebview::ios::WKWebView::WKWebView; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKWebView; + use crate::PageLoadEvent; use super::class::wry_navigation_delegate::WryNavigationDelegate;