Manipulate paste content in WKWebView

微笑、不失礼 提交于 2020-04-18 05:47:28

问题


I need to manipulate the text that is pasted into a WKWebView (from any source) running an asynchronous operation that can take some time.

My original idea was to use Javascript and the WKWebView configuration in order to get the onpaste event:

WKUserContentController *wkUController = [[WKUserContentController alloc] init];

NSString *pasteJSSource = @"document.addEventListener('onpaste', function(){ window.webkit.messageHandlers.ComposerListener.postMessage('onpaste happened!'); })";

WKUserScript *pasteScript = [[WKUserScript alloc] initWithSource:pasteJSSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly: NO];

[wkUController addScriptMessageHandler:self name:@"ComposerListener"];

[wkUController addUserScript:pasteScript];

webViewConfiguration.userContentController = wkUController;

Then my class implements WKScriptMessageHandler

#pragma mark - WKScriptMessageHandler

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"message: %@", message.body);
}

(Ignore Obj-c, swift is ok too)

But I have two problems:

  1. userContentController:didReceiveScriptMessage: is never called
  2. I don't know how to intercept the pasted code and replace it with something different

Any idea on how to solve this (even without JS that I don't obviously know :P )? Thanks.


回答1:


FOR POSTERITY:

I'm sure there a way to do this using JS exists and is cleaner but I managed to achieve the result using method swizzling:

//Method Swizzling
UIView *webContentView = self.webView.contentView;
if(webContentView != nil)
{
    //Paste:
    NSError *error;
    [webContentView swizzleMethod:@selector(paste:) withSelector:@selector(my_paste:) error:&error];
    if(error != nil)
    {
        NSLog("Failed to swizzle 'paste:' into WKContentView: %@, error);
        NSAssert(false, error);
    }

    ...
}

Where the contentView is:

- (UIView *)contentView
{
    return [self subviewWithClassName:@"WKContentView"];
}

The method my_paste: need to be part of UIResponder (that is implemented by the private WKContentView)

#pragma mark - Method Swizzling UIResponder

@interface UIResponder (WebComposerSwizzling)

- (void)my_paste:(id)sender;
#define original_paste my_paste

@end

@implementation UIResponder (WebComposerSwizzling)

- (void)my_paste:(id)sender
{
    MailComposerViewController* strongComposer = sCurrentComposer;
    if (strongComposer)
        [strongComposer manipulatePasteboard:nil];
    [self original_paste:sender];
}

@end

Note that sCurrentComposer is a static variable in my ViewController

__weak MailComposerViewController* sCurrentComposer;

The various utilities:

UIView+SubviewSearch

import UIKit

extension UIView {

    /// Find a subview corresponding to the className parameter, recursively.
    @objc public func subviewWithClassName(_ className: String) -> UIView? {
        if NSStringFromClass(type(of: self)) == className {
            return self
        } else {
            for subview in subviews {
                return subview.subviewWithClassName(className)
            }
        }
        return nil
    }
}

NSObject+Swizzling

import Foundation

extension NSObject {

    enum NSObjectSwizzlingError: Error {
        case originalSelectorNotFound
    }

    @objc public func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) throws {
        if let currentMethod = self.instanceMethod(for: currentSelector),
            let newMethod = self.instanceMethod(for:newSelector) {
            method_exchangeImplementations(currentMethod, newMethod)
        } else {
            throw NSObjectSwizzlingError.originalSelectorNotFound
        }
    }

    @objc public func instanceMethod(for selector: Selector) -> Method? {
        let classType: AnyClass! = object_getClass(self)
        return class_getInstanceMethod(classType, selector)
    }
}

(I'm sorry about the Swift <> OBJ-C mix)



来源:https://stackoverflow.com/questions/61124006/manipulate-paste-content-in-wkwebview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!