如何覆盖 wkwebview 超链接操作 sheet
How to override wkwebview hyperlink action sheet
当您长按 WkWebview 中的超链接时,您会收到一个操作 sheet。我想在长按时用我自己的一组选项覆盖该操作 sheet,但否则表现正常。我可以获得长按事件,但我不知道如何:
- 阻止显示sheet的默认操作
- 防止 webview 在长按结束时导航到 URL。
- 获取 Web 视图直接指向的基础 href URL 或 html 标签本身和相关属性,例如 ID。
这是覆盖菜单的有效解决方案。我仍然想获得一些 html 属性,但还不知道该怎么做。
override func loadView() {
super.loadView()
let contentController = WKUserContentController();
let userScript = WKUserScript(
source: "redHeader()",
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
forMainFrameOnly: true
)
contentController.addUserScript(userScript)
contentController.addScriptMessageHandler(
self,
name: "callbackHandler"
)
let config = WKWebViewConfiguration()
config.userContentController = contentController
self.webView = WKWebView(frame: self.view.frame, configuration: config)
self.webView.navigationDelegate = self
self.view = self.webView
let lpress = UILongPressGestureRecognizer(target: self, action: "webViewLongPressed:")
lpress.delegate = self
self.webView.scrollView.addGestureRecognizer(lpress)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func webViewLongPressed(sender:UILongPressGestureRecognizer!) {
longpress = true
if (sender.state == UIGestureRecognizerState.Ended) {
print("Long press Ended")
//This is where everything starts to happen
} else if (sender.state == UIGestureRecognizerState.Began) {
print("Long press detected.")
}
}
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) {
if let myUrlStr : String = navigationAction.request.URL!.absoluteString {
if myUrlStr.lowercaseString.rangeOfString("/book/") != nil {
/* Do not allow links to be tapped */
var parts = myUrlStr.componentsSeparatedByString("/")
let id = Int(parts[4])
if navigationAction.navigationType == .LinkActivated && longpress == true {
decisionHandler(.Cancel)
let ac = actionMenu(self, id: id!, user_id: 1)
self.presentViewController(ac, animated: true) {
}
longpress = false
return
}
}
}
decisionHandler(.Allow)
}
//Build action sheet
func actionMenu(sender: UIViewController, id: Int, user_id: Int) -> UIAlertController {
let alertController = UIAlertController(title: "Title", message: "Some message.", preferredStyle: .ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
}
alertController.addAction(cancelAction)
let someAction = UIAlertAction(title: "Some action", style: .Default) { (action) in
//do something, call a function etc, when this action is selected
}
alertController.addAction(someAction)
return alertController
}
取消操作的一种简单(但激进)方法 sheet 是覆盖
presentViewController:animated:completion:
在您应用的根视图控制器中。
Swift 3 个样本
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
guard let alertController = viewControllerToPresent as? UIAlertController,
alertController.preferredStyle == .actionSheet else {
// Not an alert controller, present normally
super.present(viewControllerToPresent, animated: flag, completion: completion)
return
}
// Create and open your own custom alert sheet
let customAlertController = UIAlertController(...)
super.present(customAlertController, animated: flag, completion: completion)
}
您可以从alertController.title
中获取link的URL,如果您需要获取其他属性,建议您查看this commit到Firefox iOS,它使用 JS 脚本处理程序来查找单击的元素并将其属性发送回应用程序。
此外,您还需要编写一些逻辑来防止取消除 WKWebView 之外的任何其他警报 sheet,您的应用可能会使用这些警报。
当您长按 WkWebview 中的超链接时,您会收到一个操作 sheet。我想在长按时用我自己的一组选项覆盖该操作 sheet,但否则表现正常。我可以获得长按事件,但我不知道如何:
- 阻止显示sheet的默认操作
- 防止 webview 在长按结束时导航到 URL。
- 获取 Web 视图直接指向的基础 href URL 或 html 标签本身和相关属性,例如 ID。
这是覆盖菜单的有效解决方案。我仍然想获得一些 html 属性,但还不知道该怎么做。
override func loadView() {
super.loadView()
let contentController = WKUserContentController();
let userScript = WKUserScript(
source: "redHeader()",
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
forMainFrameOnly: true
)
contentController.addUserScript(userScript)
contentController.addScriptMessageHandler(
self,
name: "callbackHandler"
)
let config = WKWebViewConfiguration()
config.userContentController = contentController
self.webView = WKWebView(frame: self.view.frame, configuration: config)
self.webView.navigationDelegate = self
self.view = self.webView
let lpress = UILongPressGestureRecognizer(target: self, action: "webViewLongPressed:")
lpress.delegate = self
self.webView.scrollView.addGestureRecognizer(lpress)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func webViewLongPressed(sender:UILongPressGestureRecognizer!) {
longpress = true
if (sender.state == UIGestureRecognizerState.Ended) {
print("Long press Ended")
//This is where everything starts to happen
} else if (sender.state == UIGestureRecognizerState.Began) {
print("Long press detected.")
}
}
func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: ((WKNavigationActionPolicy) -> Void)) {
if let myUrlStr : String = navigationAction.request.URL!.absoluteString {
if myUrlStr.lowercaseString.rangeOfString("/book/") != nil {
/* Do not allow links to be tapped */
var parts = myUrlStr.componentsSeparatedByString("/")
let id = Int(parts[4])
if navigationAction.navigationType == .LinkActivated && longpress == true {
decisionHandler(.Cancel)
let ac = actionMenu(self, id: id!, user_id: 1)
self.presentViewController(ac, animated: true) {
}
longpress = false
return
}
}
}
decisionHandler(.Allow)
}
//Build action sheet
func actionMenu(sender: UIViewController, id: Int, user_id: Int) -> UIAlertController {
let alertController = UIAlertController(title: "Title", message: "Some message.", preferredStyle: .ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
}
alertController.addAction(cancelAction)
let someAction = UIAlertAction(title: "Some action", style: .Default) { (action) in
//do something, call a function etc, when this action is selected
}
alertController.addAction(someAction)
return alertController
}
取消操作的一种简单(但激进)方法 sheet 是覆盖
presentViewController:animated:completion:
在您应用的根视图控制器中。
Swift 3 个样本
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
guard let alertController = viewControllerToPresent as? UIAlertController,
alertController.preferredStyle == .actionSheet else {
// Not an alert controller, present normally
super.present(viewControllerToPresent, animated: flag, completion: completion)
return
}
// Create and open your own custom alert sheet
let customAlertController = UIAlertController(...)
super.present(customAlertController, animated: flag, completion: completion)
}
您可以从alertController.title
中获取link的URL,如果您需要获取其他属性,建议您查看this commit到Firefox iOS,它使用 JS 脚本处理程序来查找单击的元素并将其属性发送回应用程序。
此外,您还需要编写一些逻辑来防止取消除 WKWebView 之外的任何其他警报 sheet,您的应用可能会使用这些警报。