I'm building two apps. They both share a CloudKit container. One application is designed to edit the contents of the public database regardless of who a record's creator is. The other should only be allowed to read from the public database.
Since CloudKit is largely a client-side framework it's easy enough to enforce this client side.
Are there any additional guarantees that iCloud provides to enforce what the clients are signed to do? Or is there a risk of having some actor tamper with the public database that isn't using the editing application?
CloudKit
RSS for tagStore structured app and user data in iCloud containers that can be shared by all users of your app using CloudKit.
Posts under CloudKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello,
I have an iOS app that is still in development, and I am also making a website for it with asp.net core. I am trying to use a server to server key, but it isn't working. The response is:
{
"uuid" : "some_uuid",
"serverErrorCode" : "AUTHENTICATION_FAILED",
"reason" : "Authentication failed"
}
I am using a library called EllipticCurve. You can find it here. My code is:
var requestData = new {
zoneID = new {},
query = new {
recordType = "CD_Person",
filterBy = new [] {
new {
comparator = "EQUALS",
fieldName = "CD_email",
fieldValue = new {
value = email,
type = "String"
}
}
},
sortBy = new [] {
new {
fieldName = "CD_email"
}
}
},
zoneWide = "true",
numbersAsStrings = "true"
};
string request = JsonSerializer.Serialize(requestData);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-KeyID", "my_key_id");
DateTime date = DateTime.Now;
string iso8601Date = date.ToUniversalTime().ToString("u").Replace(" ", "T");
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-ISO8601Date", iso8601Date);
byte[] bytes = Encoding.UTF8.GetBytes(request);
SHA256 hashstring = SHA256.Create();
byte[] hash = hashstring.ComputeHash(bytes);
string base64Request = Convert.ToBase64String(hash);
string paramsToSign = $"{iso8601Date}:{base64Request}:my url";
PrivateKey privateKey = PrivateKey.fromPem("-----BEGIN EC PRIVATE KEY-----\nprivate_key\n-----END EC PRIVATE KEY-----");
Signature signature = Ecdsa.sign(paramsToSign, privateKey);
client.DefaultRequestHeaders.Add("X-Apple-CloudKit-Request-SignatureV1", signature.toBase64());
var content = new StringContent(request, Encoding.UTF8, "application/json");
var response = client.PostAsync("https://api.apple-cloudkit.com/database/1/my_container/development/public/records/query", content);
string responseString = response.Result.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseString);
return View();
Any help would be appreciated.
Afternoon all,
I am starting out and want to store data in the App, some will be user specific and some general. So I have a new developer account which should have CloudKit permissions.
I am just trying to make any of the most basic example applications work, but keep hitting issues.
I create an App, select CloudKit and SwiftData. When I go into the signing and capabilities I select the Team which has the developer account. Then the CloudKit is selected as I clicked it when creating the project, but no Container is selected. I create a Container using the +, it names it iCloud.com.mydomain.AppName. However it is coloured in Red text.
I press the refresh and then it turns into black text, the Push Notifications appear all populated for 1 second then all disappear. I have nothing under Push now, only a Trashcan button.
The Container is now selected however.
Is this an issue that the Push notifications items appeared then vanished?
When I then try to run the app, using any of the many attempts I have had with simple code samples, it always fails to create the Container, usually with an error like this:
error: Store failed to load. <NSPersistentStoreDescription: 0x600000c79ce0> (type: SQLite, url: file:///Users/cal/Library/Developer/CoreSimulator/Devices/6D2BA1B3-C7CA-499D-A280-AFF4C5E98180/data/Containers/Data/Application/B9CD5E35-08BD-44CC-A72D-EB170E3691C6/Library/Application%20Support/default.store) with error = Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=CloudKit integration requires that all attributes be optional, or have a default value set. The following attributes are marked non-optional but do not have a default value:
Item: name} with userInfo {
NSLocalizedFailureReason = "CloudKit integration requires that all attributes be optional, or have a default value set. The following attributes are marked non-optional but do not have a default value:\nItem: name";
If I go into the CloudKit database view on Apple, I see the Container listed, albeit it is marked as not deployed to production.
To try to remove my newbie issues I have used many web examples, the most recent of which was the "A Beginner’s Guide to SwiftData with a to-do app" from medium.com, which should just work really, snipped from Item.swift below but I have tried several other simple examples which all give the same issue:
import Foundation
import SwiftData
@Model
class Item: Identifiable {
var name: String
init(name: String){
self.name = name
}
}
Any ideas really appreciated.
Thank you
The hardest part of SwiftUI programming is to correctly define the layers of references that you need as your app grows features. When you add Swift data to the mix, it hard to get much of anything correct.
I have an application that interacts with the outside world via BLE and LocationManager. I need to preserve used BLE devices and then store their current state in a static Monitor type class structure. This monitor though, needs to have access to some SwiftData elements, and it is not clear from the documentation whether it's preferred to create multiple ModelContainer instances, when they might share a particular types management. This doesn't feel very safe, so it would then make more sense to have a ModelContainer stuck inside of some other static Monitor object that everyone would use to get the single ModelContainer that should be used.
All of the context specific stacking of references in SwiftUI creates huge dependency chains, and it make the build of my application, currently to take 10s of minutes sometimes, when I have changes in flux and the compiler cannot make heads or tails out of broken references.
We really need to find a way to get the compiler fixed so that as a Recursive Decent parser, it has an easier time finding a terminal state instead of crawling up and down the stack of references looking for a place that it can reach a terminal state.
Not using ';' on every statement is a big part of the problem I feel...
I'm trying to delete many records with one CKModifyRecordsOperation and getting this error:
<CKError 0x600000dbe4f0: "Limit Exceeded" (27/1020); "Your request contains 552 items which is more than the maximum number of items in a single request (400)">
This obviously means, that Modify Operation has record limit of 400 which is equal to CKQueryOperation.maximumResults. The good solution here would be to chunk the array of records into subarrays with length less than 400 and add multiple delete operations to the database.
The only problem is that the limit for CKModifyRecordsOperation is neither documented nor provided with a constant, so it's basically a magic number.
In hope that my prayers would be heard I want to ask to add maximumResults constant to CKModifyRecordsOperation.
If one offline device increments a counter (starting at 0) value by 5 and a second offline device decrements the counter by 2, what can I do so that the final counter value is 3 (once the devices come back online)?
I have read about operational transformations for conflict resolution. Is there any example code I can look at that implements it?
I get the "Permission Failure" error ("Invalid bundle ID for container") below only when running my app from my iOS Target, and not my watchkit target. The watch app is able to sync/create/delete items, but my iOS target is unable to even read the data from the cloud. The cloudkit Container ID matches my iOS Target Bundle ID, which is the apps Bundle ID.
Looking at the output of CKContainer, the container matches the iOS Bundle ID.
I have tried reseting multiple times, creating different cloud containers, reseting the Signing and Capabilites online. It always results in the same issue... What am I missing here?
<CKError 0x281b69590: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE; container ID = "iCloud.companyName.AppName"; partial errors: {
com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x281b771e0: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = 8CCAD43B495AADC0; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE>
}>
I have a flutter app I developed and some of the users cannot use our backup system which uses iCloud Key-Value storage. These users all have one thing in common. Full iCloud. If they turn off the app from iCloud from backup details page in iCloud settings then it works. But if their iCloud is 100% full and they can't even access the page then it does not work.
Can someone tell me why this is happening? My app is made in flutter. It uses this package: https://pub.dev/packages/cloud_kit.
Thanks.
When I logged into my cloudkit console to inspect the database for some debugging work I couldn't access the private database. It keeps saying "failed to access iCloud data, please signi n again". No matter how many times I sign in again, whether with password or passwordless key it keeps saying the same thing. It says that message when I click on Public database, and private and shared databases are below it. I only noticed this a couple of days ago. It's done this in the past, but I eventually got back into the database but I don't know what changed to make it work.
I am trying to use ArchiveStream.process on MacOS as outlined in the documentation here:
https://developer.apple.com/documentation/accelerate/decompressing_and_extracting_an_archived_directory
I have been able to successfully do the following:
Take objects and create Data objects
Create a UIDocument that is FileWrapper based
Compress the UIDocument as an .aar archive
Upload it to iCloud as a CKRecord
Download it as an .aar and decode it back to a directory
Decode the directory as individual data items and back to objects
The problem is that I sometimes can only download from iCloud once and have the decompression function - other times it may work two or three times but ultimately fails when trying to call ArchiveStream.process
The error reported by ArchiveStream.process is simply 'ioError' but on the console I see the following:
[0xa5063c00] Truncated block header (8/16 bytes read)
[0xa503d000] NOP received
[0xa5080400] processStream
[0xa7019000] decoder failed
[0xbd008c00] istream read error
[0xbd031c00] refill buffer
[0x90008000] archive stream read error (header)
[0xc8173800] stream cancelled
The test data I am using does not change so it does not appear to be related to what I am compressing.
But I am at a loss how to prevent the error.
This is IOS 17 running on MacOS (as iPad) and on IOS 17 devices.
My app uses a significant amount of space in a private CloudKit database, and I need to be able to show users how much free space they have. Is there any way to get this value programmatically?
I have v3 models in coredata (model: Event, Lecture), and make new model in v4 with swiftdata but model name, property is different (model: EventModel, LectureModel).
For migration, I add V3Schema, V4Schema and MigrationPlan.
enum V4Schema: VersionedSchema {
static var models: [any PersistentModel.Type] = [LectureModel.self, EventModel.self ]
static var versionIdentifier = Schema.Version(4, 0, 0)
}
enum V3Schema: VersionedSchema {
static var models: [any PersistentModel.Type] = [Event.self, Lecture.self]
static var versionIdentifier = Schema.Version(3, 5, 2)
}
enum ModelMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] = [V3Schema.self, V4Schema.self]
static var stages: [MigrationStage] = [migrateV3ToV4]
}
extension ModelMigrationPlan {
static let migrateV3ToV4 = MigrationStage.custom(fromVersion: V3Schema.self,
toVersion: V4Schema.self,
willMigrate: willMigrate,
didMigrate: { _ in Log.debug(message: "Migration Complete") })
}
private func willMigrate(context: ModelContext) throws {
try migrateLectures(context: context)
try migrateEvents(context: context)
try context.save()
}
private func migrateEventTypes(context: ModelContext) throws {
// create new v4 event model using v3 event model.
}
private func migrateLectures(context: ModelContext) throws {
// create new v4 lecture model using v3 lecture model.
}
static let release: ModelContainer = {
let v4Schema = Schema(V4Schema.models)
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "app group id")
let databaseURL = containerURL?.appending(path: "**.sqlite")
let configuration = ModelConfiguration("**",
schema: v4Schema,
url: databaseURL!,
cloudKitDatabase: .private("**"))
#if DEBUG
do {
try autoreleasepool {
let desc = NSPersistentStoreDescription(url: configuration.url)
let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: configuration.cloudKitContainerIdentifier!)
desc.cloudKitContainerOptions = opts
desc.shouldAddStoreAsynchronously = false
if let model = NSManagedObjectModel.makeManagedObjectModel(for: V4Schema.models) {
let container = NSPersistentCloudKitContainer(name: "**", managedObjectModel: model)
container.persistentStoreDescriptions = [desc]
container.loadPersistentStores(completionHandler: { _, err in
if let err {
Log.error(message: "Store open failed: \(err.localizedDescription)")
}
})
try container.initializeCloudKitSchema()
Log.debug(message: "Initialize Cloudkit Schema")
if let store = container.persistentStoreCoordinator.persistentStores.first {
try container.persistentStoreCoordinator.remove(store)
}
}
}
} catch {
Log.error(message: "Failed: \(error.localizedDescription)")
}
#endif
return try! ModelContainer(for: v4Schema, migrationPlan: ModelMigrationPlan.self, configurations: configuration)
}()
But when I run, I got error message.
CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _scheduleAutomatedExportWithLabel:activity:completionHandler:]_block_invoke(3508): <NSCloudKitMirroringDelegate: 0x1036b1540> - Finished automatic export - ExportActivity - with result: <NSCloudKitMirroringResult: 0x1035da810> storeIdentifier: ***** success: 0 madeChanges: 0 error: Error Domain=NSCocoaErrorDomain Code=134407 "Request '*****' was cancelled because the store was removed from the coordinator." UserInfo={NSLocalizedFailureReason=Request '****' was cancelled because the store was removed from the coordinator.}
I don't know why store was removed from the coordinator.
Any have solutions?
I've created a container, enabled CloudKit in xCode and added code to reference the container and save. Every time I run the app I get this error when I close the game:
Snapshot request 0x2814167c0 complete with error: <NSError: 0x28144df80; domain: BSActionErrorDomain; code: 1 ("response-not-possible")>
The app is not saved and i cannot see any action with the container. My app is built in Unity with C# code and builds with no errors.
I would appreciate and assistance!
SwiftData supports the unique attribute. Unfortunately that one is not available when using CloudKit for SwiftData.
I'm looking for some help (maybe an example) or best practices how to implement the same behavior.
Starting today around 2PM MST I started receiving emails from users reporting their CloudKit synced data was 'completely gone'...
They are reporting no error messages... so that means the CKQuery on the private database is completing without error, but simply not returning any previously saved records...
This appears to be only occurring to a percentage of my users and I cannot replicate it on my device (I'm using iOS 17.1.2.
Are any other developers experiencing this?!
Very simple one. how do I add “create“ permissions for my CloudKit security roles. For some reason “create“ is greyed out when I try to check the box for _creator
Hi,
My app has been receiving a huge increase in the number of CKHTTPStatus=503 errors over the past couple of months. I created a thread before, and also a Feedback (FB13300807) over a month ago, but I haven't gotten any assistance on this, and am wondering if there is any better way to get the attention of a CloudKit engineer who might be able to help.
From my users, I was able to print out the error code and error userInfo in the console:
error.code == 15 (the same as CKErrorServerRejectedRequest),
UserInfo={ContainerID=, CKHTTPStatus=503, RequestUUID=17C6B9B9-35DD-411B-8AED-7A497075D228, OperationID=5285362CCD2DDB32}}, CKHTTPStatus=503}
How can I get this issue addressed? A lot of users are reporting this issue and it's creating a big support burden.
Friends,
I have created an App in SwiftData that uses CloudKit to sync between devices. I am using Xcode 15.0.1, and iOS 17.1.1. For further context, I am calling modelContext.save() with every change that I want to synchronise, and this seems to call a CloudKit save, as expected, within the development environment.
The synchronisation works great in the development environment with no issues, it updates fairly quickly and I use @Query to manage SwiftUI updates in the most direct way possible. It is a complex model with many relationships, and I call @Query and filter instances to get to the instance required, rather than using traditional Bindings, as many tutorials and WWDC have suggested.
When I switch to the production environment the app synchronises between devices great using the production CloudKit container. I have set up push notification certificates, and these seem to work. The issues is that, after a few minutes, the synchronisation stops happening between devices.
When synchronisation is working, Device 1 initially saves to CloudKit, and you can see the items update in the CloudKit console. When synching stops working, Device 1 stops saving, and the CloudKit console stops updating.
If I then delete and install the app on Device 1 from TestFlight, you can see that it starts saving again, with updates to the CloudKit console as expected.
But, Device 2 does not begin updating again unless you delete the app on that device, and install again.
This behaviour seems to suggest that both devices become logged out or deregistered from CloudKit after a short period of time as a consequence of some unknown process within CloudKit or SwiftData. When logged out, each device cannot write to, or read from, CloudKit.
Now, the problem with trying to fix the issue is that the registration with CloudKit, silent push notifications, and fetches, are all managed "under the hood" by SwiftData.
In the production environment, you cannot configure any registration state or refresh registration within your code, because you don't have access to the parts of SwiftData that manage this.
I wanted to find out if this is an issue that has been encountered by other users, and if anyone can help with a solution, or perhaps a debugging strategy that I can use to find out what is happening.
Thank you all in advance.
TLDR: How can I listen to changes in SwiftData and share the data via WatchConnectivity?
I am developing an app for the Apple Watch where the iPhone can act as a remote for the Watch.
The App on the Watch should work independently from iPhone. The user can create elements on the Watch and start the action associated with the element. The iPhone user can see the elements created on the Watch and start the action on the Watch from the iPhone (if possible I want to add the functionality to let the user update the elements on both devices, but that's not a priority atm).
I tried to get it to work with CloudKit and SwiftData, but somehow I couldn't get CloudKit to initialize correctly. After further research, I reconned that using WatchConnectivity and ApplicationContext should be a suitable approach.
To communicate with the iPhone App, I created a singleton class that manages the communication. Now I want this class to listen to the changes in SwiftData to send the elements to the iPhone, but I don't know how I can get access to the ModelContext in the Communicator class. I read that passing the value from the initializer of a view is not good practice and it didn't work for me.
What would be a suitable way to achieve the desired behavior of my app? Any help and feedback is appreciated. TIA
Is there any tool to automatically migrate data & data structure from Google Firebase to CloudKit?