如何在整个应用中禁用 iOS 11 拖动?

How to disable iOS 11 dragging within the whole app?

出于安全原因,我想在我的整个应用程序中禁用新的 iOS 11 拖放功能。更具体地说是拖动部分。

在 iOS 11 中,所有可以选择文本的地方(弹出窗口、文本视图、网络视图等)默认情况下都会发生这种情况。

我不知道有什么方法可以完全禁用拖动功能,但有一种方法可以将拖动会话仅限于您自己的应用程序。这在安全方面应该已经是一个很大的改进了。

看看sessionIsRestrictedToDraggingApplication

dragInteraction(_:sessionIsRestrictedToDraggingApplication:)

Called to ask your app whether the drag session should be confined to the app in which it begins.

默认情况下不启用拖放。您需要通过向视图提供拖动交互委托来启用它。因此,如果您尚未实现拖放功能,则可能不需要禁用它。

注:
Text views and text fields automatically support drag and drop. 但它的默认行为是允许使用 UIMenuController 将内容从一个来源复制到另一个来源。拖放可以轻松复制粘贴文本输入视图的文本内容。与使用 UIMenuController 的当前稳定的 OS 数据共享功能相比,拖放对数据安全问题没有影响。


这是 Apple 的声明。

Making a View into a Drag Source By implementing a drag interaction delegate (UIDragInteractionDelegate) for a view, you enable that view to function as a drag source in your app.


启用视图作为拖动源
UIView 的任何实例或子class 都可以充当拖动源。实现这一目标的第一步是:

  1. 创建拖动交互(UIDragInteraction 实例)。
  2. 指定拖动交互的委托(符合 UIDragInteractionDelegate 协议的对象)。
  3. 将交互添加到视图的交互中 属性。

以下是使用自定义辅助方法执行此操作的方法,您通常会在视图控制器的 viewDidLoad() 方法中调用该方法:

func customEnableDragging(on view: UIView, dragInteractionDelegate: UIDragInteractionDelegate) {
    let dragInteraction = UIDragInteraction(delegate: dragInteractionDelegate)
    view.addInteraction(dragInteraction)
}



创建拖动项
拖动项封装了源应用程序为一个模型对象提供多种数据表示的承诺。
要创建拖动项,请实施 dragInteraction(_:itemsForBeginning:) 拖动交互委托中的方法,如此处以最小形式显示:

func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
    // Cast to NSString is required for NSItemProviderWriting support.
    let stringItemProvider = NSItemProvider(object: "Hello World" as NSString)
    return [
        UIDragItem(itemProvider: stringItemProvider)
    ]
}

此实现使用 init(object:) 便利初始化器。当您实例化一个拖动项时,以您的应用程序的本机表示形式或您支持的最高保真表示形式传递一个对象。通常,确保项目提供者的 registeredTypeIdentifiers 数组中的第一个元素代表您的拖动交互委托可以提供的最高保真度数据。

要向拖动项添加更多数据表示,就像您通常在应用中所做的那样,请按保真度顺序从高到低添加它们。添加表示时,您有以下选择:

  • 在许多情况下,向拖动项添加多个数据表示的最佳选择是在模型中采用 NSItemProviderWriting 协议 class。使用此协议,您可以在模型 class.
  • 中放置用于提供多种数据表示的代码
  • 您可以使用 NSItemProvider class 中的 registerObject(_:visibility:) 方法或相关方法来显式注册数据表示。

找到解决办法。在您的应用程序可能需要的情况下,将 UIDragInteraction 的 isEnabled 方法方法调整为 return NO。请注意,通常使用 method swizzle 并不是一个好主意。

@implementation UIDragInteraction (TextLimitations)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        Class class = [self class];

        SEL originalSelector = @selector(isEnabled);
        SEL swizzledSelector = @selector(restrictIsEnabled);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

-(BOOL)restrictIsEnabled
{
    if (restrictedCondition)
    {
        return NO;
    }
    return [self restrictIsEnabled];
}