ios - swift : Sending custom data between two devices (not on the same network)

标签 ios swift uiactivityviewcontroller

我是 ios 开发的新手。

我构建了将数据保存在核心数据中的应用程序。我想做的是与我的 Ipad 或我 child 的 Iphone 共享这些数据。

设备不在同一网络或彼此封闭,因此共享过程将通过电子邮件或即时消息。

该应用程序将安装在所有设备上以发送/接收数据。

我想确保唯一的方法是使用 UIActivityViewController。

我还没有开始编码部分(分享部分),我还在做一些研究和一些好的建议。

谢谢你的帮助

//完整代码

经过大量搜索后,这是我的代码,我不知道是否有更好的方法,但我是这样解决的:

1 - 创建一个 Json 字符串

      let savedData = ["Something": 1]
      let jsonObject: [String: Any] = [
        "type_id": 1,
        "model_id": true,
        "Ok": [
            "startDate": "10-04-2015 12:45",
            "endDate": "10-04-2015 16:00"
        ],
        "custom": savedData
    ]

2 - 保存为文件

     let objectsToShare = [jsonObject as AnyObject]
   let data: Data? = try? JSONSerialization.data(withJSONObject: objectsToShare, options: .prettyPrinted)
     let filePath = NSTemporaryDirectory() + "/" + NSUUID().uuidString + ".kis"

    do
   {
    try data?.write(to: URL(fileURLWithPath: filePath))

    }
    catch {

    }
    print (filePath)
    // create activity view controller
    let activityItem:NSURL = NSURL(fileURLWithPath:filePath)
    let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)
    self.present(activityViewController, animated: true, completion: nil)

3 - 更新 info.plist

 <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
        <key>LSItemContentTypes</key>
        <array>
            <string>XXXSharingData.kis</string>
        </array>
        <key>CFBundleTypeRole</key>
        <string>Viewer</string>
        <key>CFBundleTypeName</key>
        <string>kis file</string>
        <key>LSHandlerRank</key>
        <string>Owner</string>
    </dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.data</string>
        </array>
        <key>UTTypeIdentifier</key>
        <string>XXXSharingData.kis</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.mime-type</key>
            <string>application/pry</string>
            <key>public.filename-extension</key>
            <string>kis</string>
        </dict>
    </dict>
</array>

最后,当通过电子邮件发送/接收文件作为附件并在我的应用程序中打开时:打开方法 appdelegate,我能够看到 Json 字符串

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    do
    {
        let dictionary =  try NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue)
        print (dictionary)
    }
    catch {

    }
    return true
}

最佳答案

嗯,总的来说有 2 个原则。您要么不想发送数据差异,要么不想发送整个数据本身。

首先,我会按需发送整个数据包,因为差异意味着目标设备需要首先报告它所处的状态。

因此,要传输整个核心数据,我想应该可以简单地压缩存储数据库的整个文件夹,将 zip 扩展名更改为某个自定义名称,然后简单地发送该文件。然后把另一边的这个文件解压到相应的位置。

但这并不是很好,因为它不能移植到任何其他系统(Android、远程存储...)并且会出现版本控制问题:如果您更新数据模型,那么您的新应用程序将在导入旧数据库时崩溃。

所以我想说发送任何标准数据 block 都是最好的:只需将所有核心数据实体转换为字典,然后将此数据序列化为 JSON。因此,像这样:

var JSONDictionary: [String: Any] = [String: Any]()
JSONDictionary["users"] = User.fetchAll().map { $0.toDictionary() }
JSONDictionary["tags"] = Tag.fetchAll().map { $0.toDictionary() }
JSONDictionary["notifications"] = Notification.fetchAll().map { $0.toDictionary() }
let data: Data? = try? JSONSerialization.data(withJSONObject: JSONDictionary, options: .prettyPrinted)
let filePath = NSTemporaryDirectory() + "/" + NSUUID().uuidString + ".myApplicationFileExtension"
Data().write(to: URL(fileURLWithPath: filePath))

所以此时您的文件很容易共享,并且可以在另一侧反转。然后您可以选择合并数据,覆盖它...

编辑:从评论和更新的问题中添加更多描述

  1. 我不确定你的数据结构是什么,但看起来我希望是这样的:

        class MyObject {
            enum ObjectType {
                case a,b,c
                var id: String {
                    switch self {
                    case .a: return "1"
                    case .b: return "2"
                    case .c: return "3"
                    }
                }
                static let supportedValues: [ObjectType] = [.a, .b, .c]
            }
    
            var savedData: [String: Any]?
            var type: ObjectType = .a
            var isModel: Bool = false
            var startDate: Date?
            var endDate: Date?
    
            func toDictionary() -> [String: Any] {
                var dictionary: [String: Any] = [String: Any]()
                dictionary["custom"] = savedData
                dictionary["type_id"] = type.id
                dictionary["model_id"] = isModel
                dictionary["startDate"] = startDate?.timeIntervalSince1970
                dictionary["endDate"] = endDate?.timeIntervalSince1970
                return dictionary
            }
    
            func loadWithDescriptor(_ descriptor: Any?) {
                if let dictionary = descriptor as? [String: Any] {
                    savedData = dictionary["custom"] as? [String: Any]
                    type = ObjectType.supportedValues.first(where: { $0.id == dictionary["type_id"] as? String }) ?? .a
                    isModel = dictionary["model_id"] as? Bool ?? false
                    startDate = {
                        guard let interval = dictionary["startDate"] as? TimeInterval else {
                            return nil
                        }
                        return Date(timeIntervalSince1970: interval)
                    }()
                    endDate = {
                        guard let interval = dictionary["endDate"] as? TimeInterval else {
                            return nil
                        }
                        return Date(timeIntervalSince1970: interval)
                    }()
                }
            }
        }
    

因此,这将为您提供从字典(而非 JSON)转换到字典(而非 JSON)的能力。

  1. 事件 Controller 不是问题,保存到文件似乎也不是什么大问题。我不确定一些属性,但它应该看起来像这样:

        func saveToTemporaryFile(myConcreteObjects: [MyObject]) -> String {
            let dictionaryObjects: [[String: Any]] = myConcreteObjects.map { $0.toDictionary() }
    
            let path = NSTemporaryDirectory() + "/" + NSUUID().uuidString + ".kis"
    
            let data: Data? = try? JSONSerialization.data(withJSONObject: dictionaryObjects, options: .prettyPrinted)
            try? data?.write(to: URL(fileURLWithPath: path))
    
            return path
        }
    

如果碰巧你有不同的对象,那么这个方法应该接受 Any 对象,它应该构造为:

var myDataObject: [String: Any] = [String: Any]()
myDataObject["myObjects"] = myConcreteObjects.map { $0.toDictionary() }
...
  1. 要从 URL 加载您的 JSON,您只需构建您的数据。既然你得到了 URL,就不用为字符串烦恼了:

    func loadItemsFrom(url: URL) -> [MyObject]? {
        guard let data = try? Data(contentsOf: url) else {
            // Error, could not load data
            return nil
        }
        guard let array = (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)) as? [Any] else {
            // Error, could not convert to JSON or invalid type
            return nil
        }
    
        return array.map { descriptor in
            let newItem = MyObject()
            newItem.loadWithDescriptor(descriptor)
            return newItem
        }
    }
    

这个从 URL 获取数据的构造函数非常强大。如果您可以访问互联网/网络,它甚至可以与远程服务器一起使用。因此,在这些情况下,请确保您在单独的线程上执行此操作,否则您的 UI 可能会被阻塞,直到收到数据。

我希望这能解决一些问题...

关于ios - swift : Sending custom data between two devices (not on the same network),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49048650/

相关文章:

iOS WatchKit 和静态库类

iphone - 如何在不使用 AudioQueueRef 的情况下设置 AudioQueue 中的音量?

ios - Xcode Main.storyboard 不显示 iOS 模拟器中出现的内容

ios - UIActivityViewController集成中的怪癖

ios - UIActivityViewController 未在我的应用程序中显示自定义文件类型的预期 AirDrop 选项

ios - 通过 UIActivityView 共享时 NSURL 打印两次

iOS:自定义按钮未显示在 Storyboard 上

ios - 如果外围设备出现问题则循环

Swift Vapor 向自定义响应添加附加信息

ios - 如何更改平板电脑上的 labelCount? (当有更多空间可用时)