Skip to content
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

refactor(macos): migrate to objc2 #1316

Draft
wants to merge 39 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0da1952
migrate drag & drop
pewsheen Mar 27, 2024
73f0541
refactor: migrate to `dpi` crate (#1202)
amrbashir Mar 28, 2024
93f608f
fix(windows): avoid double-free the controller (#1206)
amrbashir Apr 1, 2024
990759f
fix(linux): Disable deprecated applicationCache web api. (#1207)
FabianLars Apr 1, 2024
7c2cbcd
fix(wkwebview): menu shortcuts (#1208)
thewh1teagle Apr 1, 2024
97ad528
Apply Version Updates From Current Changes (#1203)
github-actions[bot] Apr 1, 2024
4f445fa
migrate to `objc2`
pewsheen Apr 2, 2024
1bcbde0
fix(macos): response body being double freed
pewsheen Jul 8, 2024
ec9f3c3
fix(macos): eval callback NSStrgin convertion error
pewsheen Jul 8, 2024
8dbd6cf
chore: remove objc dependency
pewsheen Jul 8, 2024
cf2ac97
refactor(macos): migrate WebViewDelegate
pewsheen Jul 9, 2024
2e5d9fe
refactor(macos): migrate proxy to objc2
pewsheen Jul 9, 2024
f4309e7
refactor(macos): migrate document title change observer to objc2
pewsheen Jul 9, 2024
b4e51ed
refactor(macos): move drag&drop handler to delegate
pewsheen Jul 9, 2024
be6d74e
refactor(macos): move ipc_handler into WryWebViewDelegate
pewsheen Jul 9, 2024
e62e116
refactor(macos): migrate download handler
pewsheen Jul 9, 2024
986cecd
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Jul 10, 2024
2fb6be9
fix(macos): prevent unsafe async custom protocol panic
pewsheen Jul 10, 2024
4eec6fb
chore: target os import
pewsheen Jul 10, 2024
78c5bf2
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Jul 10, 2024
a6f7ce4
refactor(ios): migrate to objc2
pewsheen Jul 10, 2024
ce7b9d0
refactor(macos): migrate WebViewUIDelegate to objc2
pewsheen Jul 11, 2024
1abff79
refactor(macos): migrate WryWebViewParent to objc2
pewsheen Jul 11, 2024
e8d2c6e
refactor(macos): move custom class to individual files
pewsheen Jul 11, 2024
ab9804b
chore: fix clippy
pewsheen Jul 11, 2024
5f55c39
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Jul 16, 2024
f889b7c
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Jul 22, 2024
92a0242
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Aug 14, 2024
a769067
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Aug 23, 2024
a741fef
refector: use reference for task. use objc2::exception::catch.
pewsheen Aug 24, 2024
47140fa
fix(dnd): use msg_send super and impl NSDraggingDestination
pewsheen Aug 26, 2024
880e798
chore: call msg_send super
pewsheen Aug 26, 2024
23444cb
fix: wrap Box<dyn FnMut(..)> with RefCell
pewsheen Aug 29, 2024
7674bf3
chore(deps): update rust crate tao to 0.29 (#1343)
renovate[bot] Aug 26, 2024
796b6ec
refactor: use bitflags way to handle mask bit manipulation
pewsheen Aug 29, 2024
a7919ca
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Sep 8, 2024
56a5616
WIP: refactor(ios): add wkwebview for ios
pewsheen Sep 8, 2024
7f19a2f
Merge branch 'dev' into refactor/migrate-to-objc2
pewsheen Sep 18, 2024
d0f6990
Update Cargo.toml
pewsheen Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 71 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
workspace = { }
workspace = {}

[package]
name = "wry"
Expand All @@ -10,24 +10,24 @@ description = "Cross-platform WebView rendering library"
readme = "README.md"
repository = "https://github.com/tauri-apps/wry"
documentation = "https://docs.rs/wry"
categories = [ "gui" ]
exclude = [ "/.changes", "/.github", "/audits", "/wry-logo.svg" ]
categories = ["gui"]
exclude = ["/.changes", "/.github", "/audits", "/wry-logo.svg"]

[package.metadata.docs.rs]
no-default-features = true
features = [ "drag-drop", "protocol", "os-webview" ]
features = ["drag-drop", "protocol", "os-webview"]
targets = [
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
"x86_64-apple-darwin"
"x86_64-apple-darwin",
]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = [ "drag-drop", "objc-exception", "protocol", "os-webview" ]
serde = [ "dpi/serde" ]
objc-exception = [ "objc/exception" ]
objc-exception = ["objc2/exception"]
drag-drop = [ ]
pewsheen marked this conversation as resolved.
Show resolved Hide resolved
protocol = [ ]
devtools = [ ]
Expand All @@ -42,9 +42,9 @@ os-webview = [
"dep:gtk",
"soup3",
"x11-dl",
"gdkx11"
"gdkx11",
]
tracing = [ "dep:tracing" ]
tracing = ["dep:tracing"]

[dependencies]
tracing = { version = "0.1", optional = true }
Expand Down Expand Up @@ -87,15 +87,70 @@ features = [
"Win32_Globalization",
"Win32_UI_HiDpi",
"Win32_UI_Input",
"Win32_UI_Input_KeyboardAndMouse"
"Win32_UI_Input_KeyboardAndMouse",
]

[target."cfg(any(target_os = \"ios\", target_os = \"macos\"))".dependencies]
block = "0.1"
cocoa = "0.26"
core-graphics = "0.24"
objc = "0.2"
objc_id = "0.1"
block2 = "0.5"
objc2 = "0.5"
objc2-web-kit = { version = "0.2.0", features = [
"objc2-app-kit",
"block2",
"WKWebView",
"WKWebViewConfiguration",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

objc2-web-kit not support WKWebView on iOS (madsmtm/objc2#637)

I think the easiest approach for now might be for you to copy objc2-web-kit's definition from the source into a file in this repo, remove the #[cfg(feature = "objc2-app-kit")], change NSWindow to UIWindow, and import it from that file on iOS instead of from objc2-web-kit.

"WKWebsiteDataStore",
"WKDownload",
"WKDownloadDelegate",
"WKNavigation",
"WKNavigationDelegate",
"WKUserContentController",
"WKURLSchemeHandler",
"WKPreferences",
"WKURLSchemeTask",
"WKScriptMessageHandler",
"WKUIDelegate",
"WKOpenPanelParameters",
"WKFrameInfo",
"WKSecurityOrigin",
"WKScriptMessage",
"WKNavigationAction",
"WKWebpagePreferences",
"WKNavigationResponse",
"WKUserScript",
] }
objc2-foundation = { version = "0.2.0", features = [
"NSURLRequest",
"NSURL",
"NSString",
"NSKeyValueCoding",
"NSStream",
"NSDictionary",
"NSObject",
"NSData",
"NSKeyValueObserving",
"NSThread",
"NSJSONSerialization",
"NSDate",
"NSBundle",
"NSProcessInfo",
] }
objc2-app-kit = { version = "0.2.0", features = [
"NSApplication",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should only be enabled under [target."cfg(target_os = \"macos\")".dependencies]. Reversed for objc2-ui-kit.

"NSEvent",
"NSWindow",
"NSView",
"NSPasteboard",
"NSPanel",
"NSResponder",
"NSOpenPanel",
"NSSavePanel",
"NSMenu",
] }
objc2-ui-kit = { version = "0.2.2", features = [
"UIResponder",
"UIScrollView",
"UIView",
] }

[target."cfg(target_os = \"android\")".dependencies]
crossbeam-channel = "0.5"
Expand Down
7 changes: 5 additions & 2 deletions examples/reparent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use tao::{
use wry::WebViewBuilder;

#[cfg(target_os = "macos")]
use {tao::platform::macos::WindowExtMacOS, wry::WebViewExtMacOS};
use {
objc2::rc::Retained, objc2_app_kit::NSWindow, tao::platform::macos::WindowExtMacOS,
wry::WebViewExtMacOS,
};
#[cfg(target_os = "windows")]
use {tao::platform::windows::WindowExtWindows, wry::WebViewExtWindows};

Expand Down Expand Up @@ -91,7 +94,7 @@ fn main() -> wry::Result<()> {

#[cfg(target_os = "macos")]
webview
.reparent(new_parent.ns_window() as cocoa::base::id)
.reparent(new_parent.ns_window() as *mut NSWindow)
.unwrap();
#[cfg(not(any(
target_os = "windows",
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub enum Error {
#[cfg(target_os = "android")]
#[error(transparent)]
CrossBeamRecvError(#[from] crossbeam_channel::RecvError),
#[error("not on the main thread")]
NotMainThread,
#[error("Custom protocol task is invalid.")]
CustomProtocolTaskInvalid,
#[error("Failed to register URL scheme: {0}, could be due to invalid URL scheme or the scheme is already registered.")]
Expand Down
52 changes: 23 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@
#![allow(clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
// #[cfg(any(target_os = "macos", target_os = "ios"))]
// #[macro_use]
// extern crate objc;

mod error;
mod proxy;
Expand Down Expand Up @@ -228,12 +228,18 @@ use raw_window_handle::HasWindowHandle;
#[cfg(gtk)]
use webkitgtk::*;

#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2::rc::Retained;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2_app_kit::NSWindow;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2_web_kit::WKUserContentController;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub(crate) mod wkwebview;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use wkwebview::*;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub use wkwebview::{PrintMargin, PrintOptions};
pub use wkwebview::{PrintMargin, PrintOptions, WryWebView};

#[cfg(target_os = "windows")]
pub(crate) mod webview2;
Expand Down Expand Up @@ -408,7 +414,7 @@ pub struct WebViewAttributes {
/// second is a mutable `PathBuf` reference that (possibly) represents where the file will be downloaded to. The latter
/// parameter can be used to set the download location by assigning a new path to it, the assigned path _must_ be
/// absolute. The closure returns a `bool` to allow or deny the download.
pub download_started_handler: Option<Box<dyn FnMut(String, &mut PathBuf) -> bool>>,
pub download_started_handler: Option<Box<dyn FnMut(String, &mut PathBuf) -> bool + 'static>>,

/// A download completion handler to manage downloads that have finished.
///
Expand Down Expand Up @@ -1052,20 +1058,11 @@ impl<'a> WebViewBuilder<'a> {
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
#[derive(Clone)]
#[derive(Clone, Default)]
pub(crate) struct PlatformSpecificWebViewAttributes {
data_store_identifier: Option<[u8; 16]>,
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
impl Default for PlatformSpecificWebViewAttributes {
fn default() -> Self {
Self {
data_store_identifier: None,
}
}
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
pub trait WebViewBuilderExtDarwin {
/// Initialize the WebView with a custom data store identifier.
Expand Down Expand Up @@ -1650,35 +1647,32 @@ impl WebViewExtUnix for WebView {
#[cfg(target_os = "macos")]
pub trait WebViewExtMacOS {
/// Returns WKWebView handle
fn webview(&self) -> cocoa::base::id;
fn webview(&self) -> Retained<WryWebView>;
/// Returns WKWebView manager [(userContentController)](https://developer.apple.com/documentation/webkit/wkscriptmessagehandler/1396222-usercontentcontroller) handle
fn manager(&self) -> cocoa::base::id;
fn manager(&self) -> Retained<WKUserContentController>;
/// Returns NSWindow associated with the WKWebView webview
fn ns_window(&self) -> cocoa::base::id;
fn ns_window(&self) -> Retained<NSWindow>;
/// Attaches this webview to the given NSWindow and removes it from the current one.
fn reparent(&self, window: cocoa::base::id) -> Result<()>;
fn reparent(&self, window: *mut NSWindow) -> Result<()>;
// Prints with extra options
fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
}

#[cfg(target_os = "macos")]
impl WebViewExtMacOS for WebView {
fn webview(&self) -> cocoa::base::id {
self.webview.webview
fn webview(&self) -> Retained<WryWebView> {
self.webview.webview.clone()
}

fn manager(&self) -> cocoa::base::id {
self.webview.manager
fn manager(&self) -> Retained<WKUserContentController> {
self.webview.manager.clone()
}

fn ns_window(&self) -> cocoa::base::id {
unsafe {
let ns_window: cocoa::base::id = msg_send![self.webview.webview, window];
ns_window
}
fn ns_window(&self) -> Retained<NSWindow> {
self.webview.webview.window().unwrap().clone()
}

fn reparent(&self, window: cocoa::base::id) -> Result<()> {
fn reparent(&self, window: *mut NSWindow) -> Result<()> {
self.webview.reparent(window)
}

Expand Down
98 changes: 98 additions & 0 deletions src/wkwebview/class/document_title_changed_observer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2020-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::{ffi::c_void, ptr::null_mut};

use objc2::{
declare_class, msg_send, msg_send_id,
mutability::InteriorMutable,
rc::Retained,
runtime::{AnyObject, NSObject},
ClassType, DeclaredClass,
};
use objc2_foundation::{
NSDictionary, NSKeyValueChangeKey, NSKeyValueObservingOptions,
NSObjectNSKeyValueObserverRegistration, NSObjectProtocol, NSString,
};

use crate::WryWebView;
pub struct DocumentTitleChangedObserverIvars {
pub object: Retained<WryWebView>,
pub handler: Box<dyn Fn(String)>,
}

declare_class!(
pub struct DocumentTitleChangedObserver;

unsafe impl ClassType for DocumentTitleChangedObserver {
type Super = NSObject;
type Mutability = InteriorMutable;
const NAME: &'static str = "DocumentTitleChangedObserver";
}

impl DeclaredClass for DocumentTitleChangedObserver {
type Ivars = DocumentTitleChangedObserverIvars;
}

unsafe impl DocumentTitleChangedObserver {
#[method(observeValueForKeyPath:ofObject:change:context:)]
fn observe_value_for_key_path(
&self,
key_path: Option<&NSString>,
of_object: Option<&AnyObject>,
_change: Option<&NSDictionary<NSKeyValueChangeKey, AnyObject>>,
_context: *mut c_void,
) {
if let (Some(key_path), Some(object)) = (key_path, of_object) {
if key_path.to_string() == "title" {
unsafe {
let handler = &self.ivars().handler;
// if !handler.is_null() {
let title: *const NSString = msg_send![object, title];
handler((*title).to_string());
// }
}
}
}
}
}

unsafe impl NSObjectProtocol for DocumentTitleChangedObserver {}
);

impl DocumentTitleChangedObserver {
pub fn new(webview: Retained<WryWebView>, handler: Box<dyn Fn(String)>) -> Retained<Self> {
let observer = Self::alloc().set_ivars(DocumentTitleChangedObserverIvars {
object: webview,
handler,
});

let observer: Retained<Self> = unsafe { msg_send_id![super(observer), init] };

unsafe {
observer
.ivars()
.object
.addObserver_forKeyPath_options_context(
&observer,
&NSString::from_str("title"),
NSKeyValueObservingOptions::NSKeyValueObservingOptionNew,
null_mut(),
);
}

observer
}
}

impl Drop for DocumentTitleChangedObserver {
fn drop(&mut self) {
unsafe {
self
.ivars()
.object
.removeObserver_forKeyPath(self, &NSString::from_str("title"));
}
}
}
12 changes: 12 additions & 0 deletions src/wkwebview/class/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2020-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

pub mod document_title_changed_observer;
pub mod url_scheme_handler;
pub mod wry_download_delegate;
pub mod wry_navigation_delegate;
pub mod wry_web_view;
pub mod wry_web_view_delegate;
pub mod wry_web_view_parent;
pub mod wry_web_view_ui_delegate;
Loading
Loading