MagicCloud
Magic Cloud 是一个 Swift (iOS) 框架,它使使用 CloudKit 变得简单且容易。
对于任何需要以数据库记录形式保存的数据类型,只需将其符合到 MCRecordable
协议。然后通用的 MCMirror
类可以维护该类型的本地数组,并在后台将其镜像到 CloudKit 的数据库中。
默认设置涵盖了 错误处理、订阅、账户更改等。可根据需要配置/自定义以优化性能(有关详细信息,请参阅即将推出的 Magic Cloud 博客),或直接使用。
查看 快速入门指南,看看如何以不到 20 行代码将云功能添加到应用程序中!
需求
满足 CloudKit 的要求,其中包括一个 付费开发者账号。
一个 iOS 项目(最低版本 10.3),需要关系型数据库。(为何不使用 Swift 呢?)
不直接支持共享数据库(即将推出版本)。
入门
为了使用 Magic Cloud,项目需要配置 CloudKit,并且需要将 MagicCloud 框架链接到其工作区。
为应用准备 CloudKit
魔法云旨在在 Apple 的 CloudKit 技术之上工作,而不是取代它。开发者不维护任何实际数据库,也不对数据完整性和安全性或丢失负责。
在安装 魔法云 之前,请确保在您的项目功能中启用了 CloudKit 和 推送通知。在此处启用 CloudKit 和配置 CloudKit。
安装
如果您熟悉使用 CocoaPods 来 管理依赖项(推荐),请在 podfile 中添加以下内容。
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.3' # <- 10.3 minimum requirement, can be more recent...
use_frameworks! # <- MagicCloud is a swift framework, ensure this is present.
target '<Your Target Name>' do
pod 'MagicCloud', '~> 3.0.1' # <- Be sure to use the current version.
end
然后,从您的项目目录...
pod install
或者,从 github 克隆,然后将框架手动添加到您的项目中(不推荐)。
快速入门指南
查看 快速入门指南,一个在 Escape Chaos 上的操作视频,了解一个测试应用如何在少于 20 行代码的情况下完全配置。
示例
对于基本项目,以下示例应该是必要的。
MCNotificationConverter
一旦启用了 CloudKit 并安装了 cocoapod,还需要在应用程序代理中进行最后的配置。
首先,让你的 app 委托(app delegate)遵守 MCNotificationConverter 协议。
class AppDelegate: UIResponder, UIApplicationDelegate, MCNotificationConverter { // <-- Add it here...
接下来,将以下两行代码插入到已存在于 app 委托中的 didFinishLaunchingWithOptions
方法中。
MCUserRecord.verifyAccountAuthentication() // <-- More information about this below @ MCUserRecord
application.registerForRemoteNotifications()
最后,向下滚动并插入 上面两个方法中的任意一个 到相同类中。
// This is the current way ...
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
convertToLocal(from: userInfo)
}
// This version is deprecated, but works for pre-iOS 10 apps...
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
convertToLocal(from: userInfo)
}
// This version DOES NOT work for silent push notifications, so it will miss any pushes from Magic Cloud...
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
convertToLocal(from: userInfo) // <-- DOES NOT WORK !!
}
设置完成后,任何来自 CloudKit 数据库的提醒都将被转换为本地提醒,并由任何已设置的 MCMirror
处理。
如果你需要在订阅失败期间禁用某些功能(例如,飞行模式、网络连接不稳定等),请将此方法添加到 app 委托中,并进行相应的处理(或者更有可能,在这里发布一个通知)。
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// This is only one of the ways you can 'gracefully disable' features that require cloud.
}
完成所有设置/配置后,现在你就可以开始了...
MCRecordable
任何需要将其模型存储为记录(并且其属性以这些记录的字段保存)的数据类型都需要遵守 MCRecordable
协议。目前,Magic Cloud 不会直接处理 CKRecords
。
extension MockType: MCRecordable {
public var recordType: String { return "MockType" } // <-- This string will serve as a CKRecordType.Name
public var recordFields: Dictionary<String, CKRecordValue> { // <-- This is where the properties that should be CKRecord
get { // fields are updated / recovered.
return [Mock.key: created as CKRecordValue]
}
set {
if let date = newValue[Mock.key] as? Date { created = date }
}
}
public var recordID: CKRecordID { // <-- This ID needs to be unique for each instance.
get { return _recordID ?? CKRecordID(recordName: "EmptyRecord") }
set { _recordID = newValue } // <-- This value needs to be saved when instances are
} // created from downloaded database records.
// MARK: - Functions: Recordable
public required init() { } // <-- This empty init is used to generate empty instances
} // that can then be overwritten from database records.
MCMirror
一旦有了可记录的(recordables),就用 MCMirror
(s) 在 CloudKit
数据库中保存和恢复这些类型。
let mocksInPublicDatabase = MCMirror<MockType>(db: .publicDB)
let mocksInPrivateDatabase = MCMirror<MockType>(db: .privateDB)
在初始化后不久,接收器应完成现有记录的下载和转换。这些可以通过 dataModel
数组访问。
let publicMocks = mocksInPublicDatabase.dataModel
瞧!对云数据库中记录的任何更改(添加/编辑/删除)都将自动反映在接收者的记录数组的接收者中,直到其进行卸载(deinit)。当从 cloudRecordables
数组中添加、修改或删除元素时,MCMirror
将确保这些更改在后台鞍接到相应的数据库。
let new = MockType(created: Date())
mocksInPublicDatabase.cloudRecordables.append(new) // <-- This will add a new record to the database.
mocksInPublicDatabase.cloudRecordables[0].created = Date.distantFuture // <-- This will modify an existing database record.
mocksInPublicDatabase.cloudRecordables.removeLast // <-- This will remove a record from the database.
注意:即使在同一个应用中,对于同一数据类型的多个镜像会降低稳定性,但我们支持它。任何更改都应反映在所有镜像中,无论是在本地应用还是其他用户的手机应用中。
MCUserRecord
如果你正在处理私有数据库或需要为每个云账户获取唯一的令牌,请使用 MCUserRecord
来获取用户的唯一 iCloud 标识符。
if let userRecord = MCUserRecord().singleton { // <-- Returns nil if not logged in OR if not connected to network.
print("User Record: \(userRecord.recordName)")
}
为了测试用户是否已登录他们的 iCloud 账户,并且在没有登录的情况下向他们显示带有链接到 设置 应用程序的警告,可以简单地调用以下静态方法。
MCUserRecord.verifyAccountAuthentication()
如有需要,你可能在 app 委托中完成(推荐使用 didFinishLaunchingWithOptions
方法)。
注意事项
虽然上述代码对于大多数项目来说是必需的,但仍有一些设计考虑因素和常见问题需要注意。
并发,大中枢调度 (& The Main Thread)
如果你这是第一次尝试处理异步操作,苹果提供了许多资源可以帮助你节省时间和精力...
苹果 和 魔法云 已经做了大量艰苦的工作,但你仍需要理解进程的执行顺序,以及云交互所需的各种时间。在这种情况下,分发组(以及用于单元测试的 XCTExpectations)非常有帮助。
不要使用云活动锁定主线程;每个应用程序都需要单独的线程来更新视图和等待数据。如果你不确定这意味着什么,那么你可能需要回顾上述文档。
错误通知
错误处理 是云开发的一个重要部分,但大多数情况下 魔法云 可以足够处理这些问题。对于需要执行额外处理的开发者,每当遇到问题都会发布一个包含原始 CKError 的 Notification。
要监听这些通知,请使用 MCErrorNotification
。
let name = Notification.Name(MCErrorNotification)
NotificationCenter.default.addObserver(forName: name, object: nil, queue: nil) { notification in
// Error notifications from MagicCloud should always include the actual CKError as Notification.object.
if let error = notification.object as? CKError { print("CKError: \(error.localizedDescription)") }
}
注意:在存在批量问题的情况下,单个错误可能生成多个通知。
CloudKit 仪表板
每个 CloudKit 容器可以直接在CloudKit 控板中进行访问,开发者可以在那里修改数据库模式、查询/修改记录、管理订阅等...
不要忘记 对所有记录名称进行查询。 MCMirror
使用这些名称来查找和检索记录。
bug 报告
如果您遇到了任何问题,请首先仔细审查现有文档。确定您正在处理一个可复现的bug后,最佳提交问题的方法是通过GitHub。
@ github.com/jalingo/MagicCloud > "Issues" tab > "New Issue" button
您还可以发送电子邮件至[email protected]
,或者为了更快地得到回应,请尝试Stack Overflow
。