- The "Custom Fields" must with prefix "CD_", like: CD_name, CD_preview
- Must have "CD_id"(String), "CD_timestamp"(Date/Time) fields
- Custom Fields must have "Queryable,Sortable or Searchable" indexs
- Create "Queryable,Sortable" indexes to "modifiedAt" field
- Create "Sortable" index to "createAt" field
- Create "Queryable" index to "recordName" field
- Have the same fields like the Type on CloudKit Dashboard, but remove prefix "CD_", like: name, preview
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
var records: [ABCloudKitPublicDatabaseAutoSyncRecord] = []
init() {
// if #available(iOS 14.0, *) {
// self.container = NSPersistentCloudKitContainer(name: "Metronome")
// } else {
// self.container = NSPersistentContainer(name: "Metronome")
// }
self.container = NSPersistentContainer(name: "Metronome")
guard let persistentStoreDescriptions = self.container.persistentStoreDescriptions.first else {
fatalError("\(#function): Failed to retrieve a persistent store description.")
}
persistentStoreDescriptions.setOption(true as NSNumber,
forKey: NSPersistentHistoryTrackingKey)
persistentStoreDescriptions.setOption(true as NSNumber,
forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
// if #available(iOS 14.0, *) {
// persistentStoreDescriptions.cloudKitContainerOptions!.databaseScope = .public
// } else {
// self.container.managedObjectModel.entities.forEach { entity in
// let record = ABCloudKitPublicDatabaseAutoSyncRecord(with: self.container.viewContext, entity: entity)
// self.records.append(record)
// }
// }
self.container.managedObjectModel.entities.forEach { entity in
let record = ABCloudKitPublicDatabaseAutoSyncRecord(with: self.container.viewContext, entity: entity)
self.records.append(record)
}
self.container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
self.container.viewContext.automaticallyMergesChangesFromParent = true
self.container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
func saveContext () {
let context = self.container.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var cloudNotification: CloudNotification = CloudNotification()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// public database
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
PersistenceController.shared.records.forEach({ record in
record.processSubscriptionNotification(with: userInfo)
})
completionHandler(.newData)
}
}
- Create fields: content(String), info(String), title(String with "Queryable,Sortable or Searchable" indexes.
!!This step is Not necessary!!
- Create "Queryable" index to "recordName" field
2. If need i18n support, create the same type named "CloudNotification_KEY" like: CloudNotification_zh, CloudNotification_jp
- Add key to "Localizable.strings" file, like: "current_lang" = "zh";
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var cloudNotification: CloudNotification = CloudNotification()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// public database
application.registerForRemoteNotifications()
application.applicationIconBadgeNumber = 0
// Ask Permission for Notifications
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { authorized, error in })
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
center.removeAllDeliveredNotifications()
}
}
...
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
UIApplication.shared.applicationIconBadgeNumber = 0
(UIApplication.shared.delegate as! AppDelegate).cloudNotification.resetBadgeCounter()
}
...