How can CloudKit environment be determined at runtime?

729 views Asked by At

Is there a programmatic way to discover whether my app is talking to the CloudKit Development or Production environment?

(I know I can look at the com.apple.developer.icloud-container-environment key in Entitlements.plist to make an intelligent guess, but that doesn't really -prove- which environment I'm using.)

3

There are 3 answers

1
Edwin Vermeer On

I can think of 2 ways to do that:

  1. You could create a settings recordType and add an environment variable. Then make sure there is only 1 record in it, both on production and development. On development set the environment variable to development and on production set that variable to production. Then in your app just read that record to see what environment you are in.

  2. There is a way that does not rely on data manipulation and that is this: Try to create a new random field name in a dummy recordType. On development that will just work. On production you will get an error.

0
Klaas On

As of now you can use an extension on CKContainer. This can be very helpful for debugging and development purposes.

extension CKContainer {
    public var isProductionEnvironment:Bool {
        let containerID = self.value(forKey: "containerID") as! NSObject // CKContainerID
        return containerID.value(forKey: "environment")! as! CLongLong == 1
    }
}

Explanation:

Expanding on @garafajon's answer. If you have a look at the iOS Runtime Headers (e.g. https://github.com/JaviSoto/iOS10-Runtime-Headers), you'll see that there is the class CKContainerID that is not publicly available.

You can access the environment property using key value coding like this:

let container = CKContainer.default()
let containerID = container.value(forKey: "containerID") as! NSObject // CKContainerID
let environment = containerID.value(forKey: "environment")!
print("\(container)")
print("\(containerID)")
print("\(environment)")

Output with com.apple.developer.icloud-container-environment=Production:

<CKContainer: 0x60800017a040; containerID=<CKContainerID: 0x608000232ea0; containerIdentifier=iCloud.com.yourdomain.yourapp, containerEnvironment="Production">>
<CKContainerID: 0x608000232ea0; containerIdentifier=iCloud.com.yourdomain.yourapp, containerEnvironment="Production">
1

Output with com.apple.developer.icloud-container-environment=Development:

<CKContainer: 0x60800017a1c0; containerID=<CKContainerID: 0x618000035360; containerIdentifier=iCloud.com.yourdomain.yourapp, containerEnvironment="Sandbox">>
<CKContainerID: 0x618000035360; containerIdentifier=iCloud.com.yourdomain.yourapp, containerEnvironment="Sandbox">
2
0
garafajon On

In the CloudKit JS docs there is a variable on container called "environment" so I expect we'll get that in future releases. For now though, it is in there and you can peek at it by getting it's description string. So this is working for now:

    let container = CKContainer(identifier: kContainerName)
    let containerDescription = String(describing: container)
    if containerDescription.contains("containerEnvironment=\"Sandbox\"") {
        showTestMode()  // or whatever you want to do differently
    }