CloudKit - "Invalid bundle ID for container" - swift

I've just create a project in Xcode 9 beta 6 and add this code:
let privateDB = CKContainer.default().privateCloudDatabase
let greatID = CKRecordID(recordName: "GreatPlace")
let place = CKRecord(recordType: "Place", recordID: greatID)
privateDB.save(place) { (record, error) in
if error != nil {
let er = (error as! CKError).errorUserInfo
print("Error: \n")
print("CKErrorDescription: \(er["CKErrorDescription"]!)\n")
print("ContainerID: \(er["ContainerID"]!)\n")
print("NSDebugDescription: \(er["NSDebugDescription"]!)\n")
print("NSUnderlyingError: \(er["NSUnderlyingError"]!)\n")
print("NSLocalizedDescription: \(er["NSLocalizedDescription"]!)\n")
print("ServerErrorDescription: \(er["ServerErrorDescription"]!)\n")
}
if record != nil {
print("record: \(record!)")
}
}
and add this capabilities:
and when I run the code I receive this error message:
What I am doing wrong ?

There was a bug causing some associations to be missed. That bug has been fixed and we automatically fixed the container/app associations that were broken during that time.
If for some reason you still need to redo an association you can either use the Capabilities pane in Xcode or use developer.apple.com -> Certificates, Identifiers & Profiles -> App IDs -> pick the ID -> Edit -> Edit under iCloud -> check the box for the container to disassociate, save, then re-associate.
If you're still stuck please email cloudkit[at]apple.com

My friend and I are having the same issue. We made 2 different projects and both of them had the same error message "Invalid bundle ID for container" which is CKError case 10 .
We are calling our fetch function to get the default "Users" record in the viewDidLoad.
func fetchWorkoutCompleted(completion: #escaping (Error?) -> Void = { _ in }) {
cloudKitManager.fetchRecord(ofType: "Users", sortDescriptors: nil) { (records, error) in
if let error = error {
print(error.localizedDescription)
completion(error)
return
}
guard let records = records else { completion(nil); return }
completion(nil)
}
}

Using Xamarin.IOS, I had to select manual provisioning rather than automatic provisioning in the info.plist file.

Had the same issue. what worked for me was changing the iCloud group name.
Before it was something like this: iCloud.com.companyName.appName.randomString
After changing to: iCloud.com.companyName.randomString it started working and synchronising.
If after adding the new container it's red press the refresh button(from under the groups) and try a clean install on your phone and it should work

Thanks to Dave Browning, this is based on his answer.
Following worked for me:
Check the container id
Check the container id used for initialisation of CKContainer
Note: If you are using NSPersistentCloudKitContainer we wouldn't be using the container id directly would be picked automatically from the entitlements file.
Try to disable and enable iCloud on the App ID
Disable and Enable iCloud on App ID
Go to https://developer.apple.com and sign in
Select Certificates, Identifiers & Profiles
Select Identifiers (App IDs)
Edit App ID for the app
Uncheck iCloud
Save
Check iCloud
Quit Xcode and Clear DerivedData
Run app

Related

requestApplicationPermission userDiscoverability failed in Mac Catalyst

I have ios app using requestApplicationPermission userDiscoverability. Today, I add Mac Catalyst support, but failed: "requestApplicationPermission(.userDiscoverability) failed, error: CloudKit access was denied by user settings".
container.requestApplicationPermission(.userDiscoverability) { [weak self] (status, error) in
guard let self = self else { return }
DispatchQueue.main.async {
if let error = error {
foolPrint("requestApplicationPermission(.userDiscoverability) failed, error: \(error.localizedDescription)")
}
}
}
And I cannot find settings about userDiscoverability in mac settings, where is it?
This iCloud user guide shows how to change these settings:
On iCloud.com, go to Account Settings, then click Manage Apps That Can Look You Up in the Advanced section.
To prevent an app from showing your name and email address to other users, deselect the app’s checkbox in the list.

Swift Realm issue in iOS 14+

------LE: We ended up removing the encryption of the database because with realm team suggestions it got worse - all we could do was to remove the database and loose all stored info. Now we encrypt in keychain only the fields we need.------
I have an app released in store and after updating their iOS version to 14+, users started to complain about info not being populated from database. Not all users with iOS 14+ have this issue, it appears randomly on some devices.
The issue goes away for awhile if they reinstall the app or after they update it to another version, but after using it for a few minutes it happens again.
My database uses encryption as documented here.
The store version of my app uses Realm 5.4.8, but I tested their last version (10.0.0) and the issue is still present.
I checked this issue but it's not the case for me, I don't have a shared app group container or a share extension.
Here's how the initialisation of realm looks like:
override init() {
super.init()
do {
guard let config = getMigrationAndEncryptionConfiguration() else {
realmConfigured = try Realm()
return
}
realmConfigured = try Realm(configuration: config)
} catch let error as NSError {
// this is where I got the error:
//"Encrypted interprocess sharing is currently unsupported.DB has been opened by pid: 4848. Current pid is 5806."
}
}
func getMigrationAndEncryptionConfiguration() -> Realm.Configuration? {
let currentSchemaVersion: UInt64 = 19
if Keychain.getData(for: .realmEncryptionKey) == nil {
var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { bytes in
SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
}
Keychain.save(data: key, for: .realmEncryptionKey)
}
guard let key = Keychain.getData(for: .realmEncryptionKey) else {
return nil
}
let fileUrl = Realm.Configuration().fileURL!.deletingLastPathComponent()
.appendingPathComponent("Explorer.realm")
var config = Realm.Configuration(fileURL: fileUrl,
encryptionKey: key,
schemaVersion: currentSchemaVersion, migrationBlock: { (migration, oldVersion) in
if oldVersion != currentSchemaVersion {
print("we need migration!")
}
})
return config
}
I had another question opened for the same issue on SO, but it was closed because I didn't have enough details. After another release of my app with more logs, I could find the error that appears at initialisation of realm:
"Encrypted interprocess sharing is currently unsupported.DB has been opened by pid: 4848. Current pid is 5806. "
This appears after the app goes to background, it gets terminated (crash or closed by the system/user) and when the users opens it again, realm fails to init.
I read all about encrypted realm not being supported in app groups or in a share extension, but I didn't implement any of that in my app, is there any other reason why this error happens?
I also removed Firebase Performance from my app because I read that this module could generate issues on realm database, but it didn't help.
I opened an issue on realm github page, but I got no answer yet.
Does anyone have any idea how to fix this or why is this happening?
Thank you.

CNContactStore execute fails

I am working out how to use the Contacts framework, however some fairly simple code to create a contact is failing with an unexpected result. This is my code:
let Store = CNContactStore()
Store.requestAccess(for: .contacts, completionHandler:{ success, error in
if success {
let Contact = CNMutableContact()
Contact.givenName = "Dave"
Contact.familyName = "Nottage"
let SaveRequest = CNSaveRequest()
SaveRequest.add(Contact, toContainerWithIdentifier: nil)
do {
try Store.execute(SaveRequest)
print("Success")
}
catch let error as NSError {
print(error.localizedDescription)
}
} else {
print("No access")
}
})
..and this is the result:
2019-02-22 10:30:56.050344+1030 ContactsTest[30329:25254955] [default] Unable to load Info.plist exceptions (eGPUOverrides)
2019-02-22 10:30:57.973724+1030 ContactsTest[30329:25254955] Could not get real path for Address Book lock folder: open() for F_GETPATH failed.
2019-02-22 10:30:57.973954+1030 ContactsTest[30329:25254955] Unable to open file lock: <ABProcessSharedLock: 0x600001752ac0: name=(null), lockFilePath=(null), localLock=<NSRecursiveLock: 0x600002914a80>{recursion count = 0, name = nil}, fileDescriptor=-1> Error Domain=NSPOSIXErrorDomain Code=14 "Bad address" UserInfo={ABFileDescriptor=-1}
The operation couldn’t be completed. (Foundation._GenericObjCError error 0.)
Any ideas on what might be causing this?
Edit: Note also that this is being compiled for macOS 10.14 SDK, and is running on macOS 10.14.3
The answer is to check the Contacts checkbox of App Data in the App Sandbox section in Capabilities and turn on the switch for App Sandbox.
Make sure you added key NSContactsUsageDescription in Info.plist.
Please refer to link.
Important
An iOS app linked on or after iOS 10.0 must include in its Info.plist
file the usage description keys for the types of data it needs to
access or it will crash. To access Contacts data specifically, it must
include NSContactsUsageDescription.

Swift OSX CNContact.organizationName crash in High Sierra

My OSX app allows the user to select a contact from their contacts list and loads the details into a Customer record. I am using CNContactPicker to retrieve a contact into a CNContact record. One of the fields I need to retrieve is organizationName. This works perfectly in OS's prior to High Sierra, but upon upgrading to High Sierra it will crash. All other CNContact fields can be retrieved with no issue (e.g. names, email, address etc). I do have permissions requested in my info.plist file.
It makes no difference if the Contact does/does not have an Organization Name.
Not much to show in terms of code:
// This fails on 1st line - any reference to organizationName causes failure
if (contact.organizationName != "") {
self.name = contact.organizationName
}
// This works
if (contact.givenName != "") {
self.name = contact.givenName
}
// This works
if (contact.contactType == CNContactType.organization) {
// Do something
}
The actual error is: [General] A property was not requested when contact was fetched.
I would like to know what has changed in the OS to cause this error, and if there is a solution or workaround please.
I submitted a bug report with Apple and received the following response which fixes my issue. Essentially, even though I have retrieved a Contact that the user selected, I need to do a CNContactFetchRequest to fetch this specific contact again (using the identifier) with keys specified (e.g. organisation).
Here is their exact response:
If you want to make sure organizationName is available, execute a CNFetchRequest for a contact with the same identifier (as returned from CNContactPicker delegate method) and provide a set of keys to fetch containing CNContactOrganizationName.
Here is the code:
var validContacts: [CNContact] = []
let contactStore = CNContactStore()
do {
// Specify the key fields that you want to be fetched.
// Note: if you didn't specify your specific field request. your app will crash
let fetchRequest = CNContactFetchRequest(keysToFetch: [CNContactOrganizationNameKey as CNKeyDescriptor])
fetchRequest.predicate = CNContact.predicateForContacts(withIdentifiers: [contact.identifier])
try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, error) -> Void in
validContacts.append(contact)
})
for validContact in validContacts {
// Do something with your contact, there should be only one.
}
} catch let e as NSError {
print(e)
}

Any way to get the name of iPhone user?

Outside of asking the user to input their name, is there any way to get it off the device?
I tried this library, which attempts to extract the name from [UIDevice currentDevice] name], but that doesn't work in a lot of situations:
https://github.com/tiboll/TLLNameFromDevice
Is the user's name present in the phonebook or anywhere else that we have access to in iOS 6?
Well you could go through all the contacts in the AddressBook and see if any of them are marked with the owner flag.
Just be aware that doing this will popup the "this app wants access to the address book" message. Also Apple isn't very keen on these kind of things. In the app review guide it is specified that an app can not use personal information without the user's permission.
You could use Square's solution:
Get the device's name (e.g. "John Smith's iPhone").
Go through the contacts on the phone and look for a contact named "John Smith".
JBDeviceOwner and ABGetMe will both do this for you.
You could use CloudKit. Following a snippet in Swift (ignoring errors):
let container = CKContainer.defaultContainer()
container.fetchUserRecordIDWithCompletionHandler(
{
(recordID, error) in
container.requestApplicationPermission(
.PermissionUserDiscoverability,
{
(status, error2) in
if (status == CKApplicationPermissionStatus.Granted)
{
container.discoverUserInfoWithUserRecordID(
recordID,
completionHandler:
{
(info, error3) in
println("\(info.firstName) \(info.lastName)")
}
)
}
}
)
}
)
The above code was based on the code at http://www.snip2code.com/Snippet/109633/CloudKit-User-Info
to save folks time. in swift4:
let container = CKContainer.default()
container.fetchUserRecordID(
completionHandler: {
(recordID, error) in
guard let recordID = recordID else {
return
}
container.requestApplicationPermission(
.userDiscoverability,
completionHandler: {
(status, error2) in
if (status == CKContainer_Application_PermissionStatus.granted)
{
if #available(iOS 10.0, *) {
container.discoverUserIdentity(withUserRecordID:
recordID,
completionHandler:
{
(info, error3) in
guard let info = info else {
return
}
print("\(info.firstName) \(info.lastName)")
}
)
}
}
}
)
}
)
however: CKUserIdentity no longer exposes either first or last name
So this answer no longer works.
You can use:
NSLog(#"user == %#",[[[NSHost currentHost] names] objectAtIndex:0]);
I did receive compiler warnings that the methods +currentHost and -names were not found. Given the warning, I’m not sure of Apple’s intention to make this available (or not) as a publicly accessible API, however, everything seemed to work as expected without the need to include any additional header files or linking in additional libraries/frameworks.
Edit 1:
You may also take a look at this Link
Edit 2:
If you have integrated your app with Facebook you can easily retrieve the user info, see Facebook Fetch User Data
For SWIFT you can use
NSUserName() returns the logon name of the current user.
func NSUserName() -> String