Using UIEditMenuInteraction with WebKit

I use UIMenuController when presenting my custom menu for the selected text on my WKWebview. But it is now deprecated on iOS 16, and get the following error

[Text] Using UIMenuController to add items into text menus is deprecated. Please implement the UITextInput API editMenuForTextRange:suggestedActions: instead.

[EditMenuInteraction] The edit menu ... did not have performable commands and/or actions; ignoring present.

And now I cant find any documentation on how to customize the menu on wkwebview.

This is what I am trying to present on the menu.

enter image description here

How can you customize the menu on the selected text on wkwebview?

I tried adding UITextInput, but it requires to conform to a bunch of protocols.

Upvotes: 3

Views: 2551

Answers (3)

Ely
Ely

Reputation: 9131

In the view controller that contains the WKWebView control, override the buildMenu method to add a custom context menu item, like this:

override func buildMenu(with builder: any UIMenuBuilder) {
     
    let customMenuItem = UIAction(title: "Custom Title", image: UIImage(systemName: "star")) { action in
        // Handle menu item action here
    }
    
    let menu = UIMenu(title: String(), image: nil, identifier: nil, options: .displayInline, children: [customMenuItem])
    builder.insertSibling(menu, afterMenu: .standardEdit) // Or any other system menu
    
    super.buildMenu(with: builder)
}

Works with iOS 16 or newer

Upvotes: 3

Alex Staravoitau
Alex Staravoitau

Reputation: 2268

This isn't possible just yet, but I think Apple is planning to add APIs for UIEditMenuInteraction soon. This is what I found in the WebKit source (mind the WK_IOS_TBA availability specifier):

/**
 * @abstract Called when the web view is about to present its edit menu.
 *
 * @param webView The web view displaying the menu.
 * @param animator Appearance animator. Add animations to this object to run them alongside the appearance transition.
 */
- (void)webView:(WKWebView *)webView willPresentEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator WK_API_AVAILABLE(ios(WK_IOS_TBA));

/**
 * @abstract Called when the web view is about to dismiss its edit menu.
 *
 * @param webView The web view displaying the menu.
 * @param animator Dismissal animator. Add animations to this object to run them alongside the dismissal transition.
 */
- (void)webView:(WKWebView *)webView willDismissEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator WK_API_AVAILABLE(ios(WK_IOS_TBA));

UPDATE: These methods are showing up in the WKUIDelegate docs too now:

Upvotes: 2

Fahad Nazir
Fahad Nazir

Reputation: 73

I faced the same issue while presenting my custom menu in webview in iOS 16. I implemented the following method and removed all non-required menu items as following and it was good to go:

    open override func buildMenu(with builder: UIMenuBuilder) {
    if #available(iOS 16.0, *) {
        builder.remove(menu: .lookup)
        builder.remove(menu: .file)
        builder.remove(menu: .edit)
        builder.remove(menu: .view)
        builder.remove(menu: .window)
        builder.remove(menu: .help)
        builder.remove(menu: .about)
        builder.remove(menu: .preferences)
        builder.remove(menu: .services)
        builder.remove(menu: .hide)
        builder.remove(menu: .quit)
        builder.remove(menu: .newScene)
        builder.remove(menu: .openRecent)
        builder.remove(menu: .close)
        builder.remove(menu: .print)
        builder.remove(menu: .document)
        builder.remove(menu: .undoRedo)
        builder.remove(menu: .standardEdit)
        builder.remove(menu: .find)
        builder.remove(menu: .replace)
        builder.remove(menu: .share)
        builder.remove(menu: .textStyle)
        builder.remove(menu: .spelling)
        builder.remove(menu: .spellingPanel)
        builder.remove(menu: .spellingOptions)
        builder.remove(menu: .substitutions)
        builder.remove(menu: .substitutionsPanel)
        builder.remove(menu: .substitutionOptions)
        builder.remove(menu: .transformations)
        builder.remove(menu: .speech)
        builder.remove(menu: .learn)
        builder.remove(menu: .format)
        builder.remove(menu: .font)
        builder.remove(menu: .textSize)
        builder.remove(menu: .textColor)
        builder.remove(menu: .textStylePasteboard)
        builder.remove(menu: .text)
        builder.remove(menu: .writingDirection)
        builder.remove(menu: .alignment)
        builder.remove(menu: .toolbar)
        builder.remove(menu: .sidebar)
        builder.remove(menu: .fullscreen)
        builder.remove(menu: .minimizeAndZoom)
        builder.remove(menu: .bringAllToFront)

    }
    super.buildMenu(with: builder)
}

Hope this helps, Cheers

Upvotes: 5

Related Questions