2

我的应用程序能够提供多种 UIActivityItem 类型(文本、数据、富文本、打印页面渲染器等)用于各种用途的共享,包括打印、复制/粘贴和另存为文件。出于复制/粘贴的目的,它需要包含纯文本、属性字符串、数据(JSON 数据)和 JSON 字符串)。

但是,由于提供了多种数据类型,UIActivityViewController 的“保存到文件”选项会导致保存多个文件 - 一个用于可以保存为文件的每种项目类型。

如果我将它减少到只有一个 UIActivityItem,那么复制/粘贴功能会严重减少,因此它不能与它应该使用的所有各种不同的粘贴板类型一起工作(例如,我的应用程序的自定义 JSON 数据格式以及纯文本和属性字符串) .

所以我试图使用 UIActivityItemProvider 子类来解决这个问题,但我仍然无法弄清楚如何只保存一个文件,而不是多个文件(每个项目类型一个)。这甚至可能吗?

我的 UIActivityItemProvider 子类的相关部分如下。

(请注意,我为此使用了单个子类的多个实例,但使用不同的子类也会出现同样的问题。)

class RatsActivityItemProvider: UIActivityItemProvider {

    var rats: [Rat]

    init(placeholderItem: Any, rats: [Rat]) {
        RatsActivityItemProvider.selectedOption = nil
        self.rats = rats
        super.init(placeholderItem: placeholderItem)
    }

    class func allProviders(forRats rats: [Rat]) -> [RatsActivityItemProvider] {
        var providers: [RatsActivityItemProvider] = []
        providers.append(RatsActivityItemProvider(placeholderItem: NSAttributedString(), rats: rats))
        providers.append(RatsActivityItemProvider(placeholderItem: RatPrintPageRenderer(), rats: rats))
        providers.append(RatsActivityItemProvider(placeholderItem: [:] as [String:Any], rats: rats))
        providers.append(RatsActivityItemProvider(placeholderItem: Data(), rats: rats))
        return providers
    }

    override var item: Any {
        print("\(activityType!.rawValue as Any) - \(type(of: placeholderItem!))")
        switch activityType {
        case UIActivity.ActivityType.print:
            return RatPrintPageRenderer(rats)
        case UIActivity.ActivityType.copyToPasteboard:
            var pasteboardDict: [String:Any] = attrString.pasteables()
            //  (Add custom types to dictionary here)
            return pasteboardDict
        default:
            //  "Save To Files" activity is not available in UIActivity.ActivityType so check the raw value instead
            if activityType?.rawValue.contains("com.apple.CloudDocsUI.AddToiCloudDrive") ?? false {
                //
                //  HOW TO HAVE ONLY ONE OF THE PROVIDERS RETURN A VALUE HERE???
                //
            }
        }
    }

}

当我运行它并选择“保存到文件”时,我得到以下输出(来自每个提供者的一行):

com.apple.CloudDocsUI.AddToiCloudDrive - NSConcreteAttributedString
com.apple.CloudDocsUI.AddToiCloudDrive - RecipePrintPageRenderer
com.apple.CloudDocsUI.AddToiCloudDrive - __EmptyDictionarySingleton
com.apple.CloudDocsUI.AddToiCloudDrive - _NSZeroData

...如果我简单地传回该数据类型的项目,则会为其中的每一个创建一个文件。

4

1 回答 1

1

好吧,我发现解决方案有两个...

直接回答问题(但不是理想的行为):

在每个switch案例(以及案例ifdefault)中,我都需要activityType检查placeholderItem. 如果它不是合适的匹配项,则按原样返回(空)placeholderItem(除了在“保存到文件”的情况下,即使是空的打印页面渲染器占位符也会导致文件被写入!所以而不是返回占位符在那里,返回一个空数组)。

这有效,并导致将单个文件写入用户选择的位置,从而回答了原始问题。用户甚至有机会为文件提供名称。但是默认名称一点都不好——只是数据类型(例如,“文本”或“数据”,取决于保存到文件中的内容)。

提供更多灵活性的解决方案: 创建一个自定义UIActivity,将文件写入用户使用UIDocumentPickerViewController. 例如,活动的标题可以是“导出到”)。

事实证明这更加灵活,并且让我根据传入的数据使用更有意义的默认文件名(和扩展名!)。它还有可能让我进一步改进行为稍后(例如,我可能能够使用警报让用户在几种不同的文件格式之间进行选择(用于不同目的)。

这不会取代“保存到文件”操作,所以我最终得到了它们,并且仍然需要修复我的“保存到文件”操作的行为,如上所述。

它给我留下了“导出”和“保存”两个动作,它们的工作方式类似,但一个比另一个更灵活和直观,我可以让它们默认使用不同的文件格式。

我的新代码(default外部部分switch)如下......

        default:
            if activityType?.rawValue == "com.stuff.thing.activity.export" {
                if placeholderItem is [Rat] {
                    return rats
                } else {
                   return placeholderItem!
               }
            } else if activityType?.rawValue == "com.apple.CloudDocsUI.AddToiCloudDrive" {
                if placeholderItem is Data {
                    return attrString
                } else {
                    //  Don't return the placeholder item here!  Some (eg print page renderer) can result in a file being written!
                    return [] as [Any]
                }
            }

            return attrString
        }
于 2020-04-22T21:54:41.453 回答