Swift:在两个设备之间发送自定义数据(不在同一网络上)

问题描述 投票:0回答:2

我是ios developpement的新手。

我已经构建了可以在核心数据中保存数据的应用程序。我想要做的是与我的Ipad或我的孩子Iphone分享这些数据。

设备不在同一网络上或彼此关闭,因此共享过程将通过电子邮件或Imessage进行。

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

我想确保唯一的方法是使用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>

最后当通过电子邮件发送/接收文件作为附件并在我的应用程序中打开时:open method 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
}
ios swift uiactivityviewcontroller
2个回答
2
投票

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

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

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

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

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

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)转换。

  1. 活动控制器不是问题,保存到文件似乎也不是一个问题。我不确定一些属性,但它应该看起来像这样: 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,直到收到数据。

我希望这清除一些事情......


0
投票

根据你的描述,我假设你想做像Apple Handoff这样的事情。基本上,当您更改一台设备上的某些数据以继续使用其他设备的最新副本时。

在我看来,你可以通过在客户端和服务器之间同步数据的某种后端来实现这一点。此外,后端应将推送通知发送到其他设备以更新本地副本。通过使用Silent Push Notifications,可以在没有用户交互的情况下静默更新应用程序。

您可以查看CloudantCouchbase,它基本上提供了在客户端和服务器之间同步数据的解决方案。通过使用此方法,您可以最大限度地减少为应用程序的后端部分以及客户端应用程序中的数据和网络层编写代码的需要。两种解决方案都在Swift中具有适用于iOS的SDK,因此您可以轻松集成它们。

希望能帮助到你!

© www.soinside.com 2019 - 2024. All rights reserved.