Skip to content

Commit f7781a7

Browse files
lucasfernogjyc5120
andauthored
feat(ios): allow changing or removing input accessory view (#1544)
* feat(ios): allow changing or removing input accessory view see https://developer.apple.com/documentation/uikit/uiresponder/inputaccessoryview?language=objc for more information * lint Co-authored-by: jyc5120 <jason@livingskytech.com> --------- Co-authored-by: jyc5120 <jason@livingskytech.com>
1 parent b7644ba commit f7781a7

5 files changed

Lines changed: 69 additions & 8 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wry": patch
3+
---
4+
5+
Allow modifying or removing the input accessory view on iOS via `WebViewBuilderExtIos::with_input_accessory_view_builder`.

src/lib.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ pub use http;
407407
pub use proxy::{ProxyConfig, ProxyEndpoint};
408408
pub use web_context::WebContext;
409409

410+
#[cfg(target_os = "ios")]
411+
pub type InputAccessoryViewBuilder =
412+
dyn Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>>;
413+
410414
/// A rectangular region.
411415
#[derive(Clone, Copy, Debug)]
412416
pub struct Rect {
@@ -1410,11 +1414,12 @@ impl<'a> WebViewBuilder<'a> {
14101414
}
14111415

14121416
#[cfg(any(target_os = "macos", target_os = "ios"))]
1413-
#[derive(Clone)]
14141417
pub(crate) struct PlatformSpecificWebViewAttributes {
14151418
data_store_identifier: Option<[u8; 16]>,
14161419
traffic_light_inset: Option<dpi::Position>,
14171420
allow_link_preview: bool,
1421+
#[cfg(target_os = "ios")]
1422+
input_accessory_view_builder: Option<Box<InputAccessoryViewBuilder>>,
14181423
}
14191424

14201425
#[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -1425,6 +1430,8 @@ impl Default for PlatformSpecificWebViewAttributes {
14251430
traffic_light_inset: None,
14261431
// platform default for this is true
14271432
allow_link_preview: true,
1433+
#[cfg(target_os = "ios")]
1434+
input_accessory_view_builder: None,
14281435
}
14291436
}
14301437
}
@@ -1476,6 +1483,40 @@ impl WebViewBuilderExtDarwin for WebViewBuilder<'_> {
14761483
}
14771484
}
14781485

1486+
#[cfg(target_os = "ios")]
1487+
pub trait WebViewBuilderExtIos {
1488+
/// Allows overriding the the keyboard accessory view on iOS.
1489+
/// Returning `None` effectively removes the view.
1490+
///
1491+
/// The closure parameter is the webview instance.
1492+
///
1493+
/// The accessory view is the view that appears above the keyboard when a text input element is focused.
1494+
/// It usually displays a view with "Done", "Next" buttons.
1495+
fn with_input_accessory_view_builder<
1496+
F: Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>> + 'static,
1497+
>(
1498+
self,
1499+
builder: F,
1500+
) -> Self;
1501+
}
1502+
1503+
#[cfg(target_os = "ios")]
1504+
impl WebViewBuilderExtIos for WebViewBuilder<'_> {
1505+
fn with_input_accessory_view_builder<
1506+
F: Fn(&objc2_ui_kit::UIView) -> Option<Retained<objc2_ui_kit::UIView>> + 'static,
1507+
>(
1508+
self,
1509+
builder: F,
1510+
) -> Self {
1511+
self.and_then(|mut b| {
1512+
b.platform_specific
1513+
.input_accessory_view_builder
1514+
.replace(Box::new(builder));
1515+
Ok(b)
1516+
})
1517+
}
1518+
}
1519+
14791520
#[cfg(windows)]
14801521
#[derive(Clone)]
14811522
pub(crate) struct PlatformSpecificWebViewAttributes {

src/wkwebview/class/wry_web_view.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub struct WryWebViewIvars {
2929
pub(crate) drag_drop_handler: Box<dyn Fn(DragDropEvent) -> bool>,
3030
#[cfg(target_os = "macos")]
3131
pub(crate) accept_first_mouse: objc2::runtime::Bool,
32+
#[cfg(target_os = "ios")]
33+
pub(crate) input_accessory_view_builder: Option<Box<crate::InputAccessoryViewBuilder>>,
3234
pub(crate) custom_protocol_task_ids: Mutex<HashMap<usize, Retained<NSUUID>>>,
3335
}
3436

@@ -59,6 +61,16 @@ define_class!(
5961
fn accept_first_mouse(&self, _event: &NSEvent) -> Bool {
6062
self.ivars().accept_first_mouse
6163
}
64+
65+
#[cfg(target_os = "ios")]
66+
#[unsafe(method_id(inputAccessoryView))]
67+
fn input_accessory_view(&self) -> Option<Retained<objc2_ui_kit::UIView>> {
68+
if let Some(builder) = &self.ivars().input_accessory_view_builder {
69+
builder(self)
70+
} else {
71+
unsafe { objc2::msg_send![super(self), inputAccessoryView] }
72+
}
73+
}
6274
}
6375
unsafe impl NSObjectProtocol for WryWebView {}
6476

src/wkwebview/class/wry_web_view_parent.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5-
use std::cell::Cell;
6-
7-
use objc2::{define_class, msg_send, rc::Retained, DefinedClass, MainThreadOnly};
5+
#[cfg(target_os = "macos")]
6+
use objc2::DefinedClass;
7+
use objc2::{define_class, msg_send, rc::Retained, MainThreadOnly};
88
#[cfg(target_os = "macos")]
99
use objc2_app_kit::{NSApplication, NSEvent, NSView, NSWindow, NSWindowButton};
1010
use objc2_foundation::MainThreadMarker;
@@ -15,7 +15,7 @@ use objc2_ui_kit::UIView as NSView;
1515

1616
pub struct WryWebViewParentIvars {
1717
#[cfg(target_os = "macos")]
18-
traffic_light_inset: Cell<Option<(f64, f64)>>,
18+
traffic_light_inset: std::cell::Cell<Option<(f64, f64)>>,
1919
}
2020

2121
define_class!(

src/wkwebview/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use std::{
7777
net::Ipv4Addr,
7878
os::raw::c_char,
7979
panic::AssertUnwindSafe,
80-
ptr::{null_mut, NonNull},
80+
ptr::NonNull,
8181
rc::Rc,
8282
str::{self, FromStr},
8383
sync::{Arc, Mutex, RwLock},
@@ -272,6 +272,8 @@ impl InnerWebView {
272272
},
273273
#[cfg(target_os = "macos")]
274274
accept_first_mouse: Bool::new(attributes.accept_first_mouse),
275+
#[cfg(target_os = "ios")]
276+
input_accessory_view_builder: pl_attrs.input_accessory_view_builder,
275277
custom_protocol_task_ids: Default::default(),
276278
});
277279

@@ -284,7 +286,7 @@ impl InnerWebView {
284286
let proxy_config = match proxy_config {
285287
ProxyConfig::Http(endpoint) => {
286288
let nw_endpoint = nw_endpoint_t::try_from(endpoint).unwrap();
287-
nw_proxy_config_create_http_connect(nw_endpoint, null_mut())
289+
nw_proxy_config_create_http_connect(nw_endpoint, std::ptr::null_mut())
288290
}
289291
ProxyConfig::Socks5(endpoint) => {
290292
let nw_endpoint = nw_endpoint_t::try_from(endpoint).unwrap();
@@ -508,6 +510,7 @@ impl InnerWebView {
508510
}
509511
}
510512

513+
#[cfg_attr(target_os = "ios", allow(unused_mut))]
511514
let mut w = Self {
512515
id: webview_id,
513516
mtm,
@@ -778,7 +781,7 @@ r#"Object.defineProperty(window, 'ipc', {
778781
&window,
779782
None,
780783
None,
781-
null_mut(),
784+
std::ptr::null_mut(),
782785
)
783786
}
784787
}

0 commit comments

Comments
 (0)