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

Feat: Support keyboardDisplayRequiresUserAction to focus automaticlly in iOS #1445

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void loadDataWithBaseURL(String baseUrl, String data,
boolean zoomIn();
boolean zoomOut();
void clearFocus();
void requestFocusView(); // For requestFocus
Map<String, Object> requestFocusNodeHref();
Map<String, Object> requestImageRef();
int getScrollX();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ public void onReceiveValue(String value) {
}
result.success(true);
break;
case requestFocus:
if (webView != null) {
webView.requestFocusView();
}
result.success(true);
break;
case requestFocusNodeHref:
if (webView != null) {
result.success(webView.requestFocusNodeHref());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public enum WebViewChannelDelegateMethods {
zoomOut,
clearFocus,
setContextMenu,
requestFocus,
requestFocusNodeHref,
requestImageRef,
getScrollX,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,15 @@ public void onReceiveValue(String value) {
});
}

public void requestFocusView() {
requestFocus();
InputMethodManager inputManager =
(InputMethodManager) this.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputManager != null) {
inputManager.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_NOT_ALWAYS);
}
}

public Map<String, Object> requestFocusNodeHref() {
Message msg = InAppWebView.mHandler.obtainMessage();
requestFocusNodeHref(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ public boolean checkInputConnectionProxy(final View view) {
public void clearFocus() {
super.clearFocus();

InputMethodManager inputManager = (InputMethodManager) this.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputManager != null) {
inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0);
}

if (useHybridComposition) {
return;
}
Expand Down
70 changes: 70 additions & 0 deletions ios/Classes/InAppWebView/InAppWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,75 @@ import Flutter
import Foundation
import WebKit

// Support `keyboardDisplayRequiresUserAction` to focus automaticlly
typealias OldClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void
extension WKWebView{
var keyboardDisplayRequiresUserAction: Bool? {
get {
return self.keyboardDisplayRequiresUserAction
}
set {
self.setKeyboardRequiresUserInteraction(newValue ?? true)
}
}

func setKeyboardRequiresUserInteraction( _ value: Bool) {
guard let WKContentView: AnyClass = NSClassFromString("WKContentView") else {
print("keyboardDisplayRequiresUserAction extension: Cannot find the WKContentView class")
return
}
// For iOS 10, *
let sel_10: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:")
// For iOS 11.3, *
let sel_11_3: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
// For iOS 12.2, *
let sel_12_2: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
// For iOS 13.0, *
let sel_13_0: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:")

if let method = class_getInstanceMethod(WKContentView, sel_10) {
let originalImp: IMP = method_getImplementation(method)
let original: OldClosureType = unsafeBitCast(originalImp, to: OldClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3) in
original(me, sel_10, arg0, !value, arg2, arg3)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}

if let method = class_getInstanceMethod(WKContentView, sel_11_3) {
let originalImp: IMP = method_getImplementation(method)
let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
original(me, sel_11_3, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}

if let method = class_getInstanceMethod(WKContentView, sel_12_2) {
let originalImp: IMP = method_getImplementation(method)
let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
original(me, sel_12_2, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}

if let method = class_getInstanceMethod(WKContentView, sel_13_0) {
let originalImp: IMP = method_getImplementation(method)
let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
original(me, sel_13_0, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
}
}

public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
WKNavigationDelegate, WKScriptMessageHandler, UIGestureRecognizerDelegate,
WKDownloadDelegate,
Expand Down Expand Up @@ -78,6 +147,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
}
self.contextMenu = contextMenu
self.initialUserScripts = userScripts
self.keyboardDisplayRequiresUserAction = false
uiDelegate = self
navigationDelegate = self
scrollView.delegate = self
Expand Down
2 changes: 2 additions & 0 deletions ios/flutter_inappwebview.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ A new Flutter plugin.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0'

s.platforms = { :ios => '11.0' }

s.dependency 'OrderedSet', '~>5.0'

s.default_subspec = 'Core'
Expand Down
1 change: 1 addition & 0 deletions lib/src/in_app_webview/apple/in_app_webview_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class IOSInAppWebViewOptions
///- [InAppWebViewController.pauseTimers]
///- [InAppWebViewController.getSelectedText]
///- [InAppWebViewController.getHitTestResult]
///- [InAppWebViewController.requestFocus]
///- [InAppWebViewController.requestFocusNodeHref]
///- [InAppWebViewController.requestImageRef]
///- [InAppWebViewController.postWebMessage]
Expand Down
8 changes: 8 additions & 0 deletions lib/src/in_app_webview/in_app_webview_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,14 @@ class InAppWebViewController {
_inAppBrowser?.contextMenu = contextMenu;
}

/// Only support android.
///
///- Android issue: https://www.pudn.com/news/6228d8129ddf223e1ad224f8.html
Future<void> requestFocus() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('requestFocus', args);
}

///Requests the anchor or image element URL at the last tapped point.
///
///**NOTE**: On iOS, it is implemented using JavaScript.
Expand Down
1 change: 1 addition & 0 deletions lib/src/in_app_webview/in_app_webview_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,7 @@ class InAppWebViewSettings_ {
///- [InAppWebViewController.pauseTimers]
///- [InAppWebViewController.getSelectedText]
///- [InAppWebViewController.getHitTestResult]
///- [InAppWebViewController.requestFocus]
///- [InAppWebViewController.requestFocusNodeHref]
///- [InAppWebViewController.requestImageRef]
///- [InAppWebViewController.postWebMessage]
Expand Down
1 change: 1 addition & 0 deletions lib/src/in_app_webview/in_app_webview_settings.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.