使用WKWebView接收NSDraggingDestination消息

时间:2014-08-02 16:04:17

标签: objective-c cocoa webview drag-and-drop

我正在移植一个OS X应用程序,它使用WebView来使用WKWebView,这是OS X Yosemite中引入的新“现代WebKit API”。我之前的WebView子类支持通过先调用[self registerForDraggedTypes:@[NSFilenamesPboardType]]然后简单地实现- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender将文件放到其上。

这不适用于新的WKWebView,因为performDragOperation永远不会被调用,也没有我尝试的任何NSDraggingDestination协议方法。

我也试过让父NSView实现协议,我仍然没有收到消息。从层次结构中删除WKWebView会使父NSView接收这些消息。

我也试过实现WKNavigationDelegate协议来防止WKWebView的默认丢弃行为发生,这也没有改变。

编辑:经过进一步检查(由Scott Kyle / @appden在Twitter上建议),私有类WKView implements the NSDraggingDestination protocol是WKWebView的子视图。我的代码可能会尝试在WKView看到它们之前获取拖动通知并对其进行操作。

2 个答案:

答案 0 :(得分:2)

由于Scott Kyle,我找到的唯一解决方案是使用performDragOperation:object_getClass和{{1}将我在WKView上定义的class_getInstanceMethod方法替换为我自己的实现来自Objective-C运行时。希望将来,WKUIDelegate协议将扩展为支持自定义挂钩到WKWebView私有实现的拖放协议。

这是一个示例,展示了我们如何使用我们自己的WKWebView子类交换嵌套视图method_exchangeImplementations的实现:

performDragOperation:

然后是我们委托给 // Override the performDragOperation: method implemented on WKView so that we may get drop notification. var originalMethod = class_getInstanceMethod(object_getClass(subviews[0]), "performDragOperation:") var overridingMethod = class_getInstanceMethod(object_getClass(self), "performDragOperation:") method_exchangeImplementations(originalMethod, overridingMethod) 对象的实现。

dropDelegate

答案 1 :(得分:2)

我需要保留WKWebView对drags的处理,但能够在收到它们之前对内容进行内省和修改。子类化WKView并不是很有用,因为所有WKWebView的类仍然会使用原始类,所以我使用了之前提出的运行时调版+类扩展。

import WebKit
import Foundation
import ObjectiveC
extension WKView {
func shimmedPerformDragOperation(sender: NSDraggingInfo) -> Bool {
    var pboard = sender.draggingPasteboard()
    if let items = pboard.pasteboardItems {
        for item in items {
            if let types = item.types? {
                for type in types {
                    if let value = item.stringForType(type.description) {
                        NSLog("DnD type(\(type)): \(value)")
                    }
                }
            }
        }
    }
    return self.shimmedPerformDragOperation(sender) //return pre-swizzled method
}
}

var webview = WKWebView(frame: CGRectZero, configuration: WkWebViewConfiguration())
var wkview = (webview.subviews.first as WKView) // 1 per frame?
var origDnD = class_getInstanceMethod(WKView.self, "performDragOperation:")
var newDnD = class_getInstanceMethod(WKView.self, "shimmedPerformDragOperation:")
method_exchangeImplementations(origDnD, newDnD)

您需要在桥接标头中添加一个小片段以扩展WKView:

@import WebKit;
@interface WKView : NSView <NSTextInputClient> {
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo;
@end