iCloud GUID Across Devices - ios

I'm trying to figure out a way to generate a unique iCloud ID that will be the same across devices. My app stores data in an online database that I would like to tie back to an iCloud id. This gives the nice user experience of not having to deal with logins (since all data is tied to their iCloud account), without being stuck using iCloud's lousy sync. The problem is that as far as I know, there's no API that will give me this kind of ID.
Things I've tried/thought about:
1) NSUbiquitousKeyValueStore
Doesn't work, because the value will get updated "sometime later" i.e. - whenever Apple feels like it.
2) iCloud Document Storage
Same problem as #1, with the added bonus of storing a random file in the device that the user can remove by hand
3) Using [[NSFileManager defaultManager] ubiquityIdentityToken]
Because the Ubiquity Token's bytes are the same for any given login session, I imagined it may be that this may be the case across devices. Not the case
4) Using the Address Book Contact
Seems like it would be unreliable (what happens if they change their main email/phone number/name), plus has the side effect of annoying/freaking out the user at first launch (how do they know I'm not stealing all their contacts?)
5) Rolling my own login system tied to a remote server
This seems to be the only option available, although I'd prefer a better one.
Thanks in advance

Perhaps this is too late to be useful, but iOS 8 has provided a solution here. From the WWDC 2014 “Intro to CloudKit” session:
So, instead what we do is on a container by container basis we come up with a random ID. This is an identifier that is stable so that is your application no matter what client it's running on talking to this container will get the same identifier, but it's not identifying the user via any personal information. … We've given you enough support that if you wanted to you could implement a login via iCloud flow in your application using the CloudKit framework.
[ Transcription courtesy of http://asciiwwdc.com/2014/sessions/208 ]
To flesh that out a bit more, if your app is provisioned for CloudKit storage then its default container comes with an auto-generated user record representing the currently signed-in iCloud user (if any). The UUID (actually called recordName) associated with this user record is consistent for your app across installs and across devices.
E.g.:
[[CKContainer defaultContainer] fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
…
myiCloudUserID = recordID.recordName;
}];

There is no persistent unique identifier for iCloud.
Option 5 is your best bet unless you want to do conflict resolution on a sync'd file that uses document storage.

Related

When using NSPersistentCloudKitContainer: what to do if the user logs out of iCloud?

From several Apple WWDC talks on CloudKit, when using CloudKit to sync private user data across devices, when the user logs out of iCloud, the App is supposed to empty the on-device cache / local replica (I use Core Data for on-device permanence). Then when this user (or any user really) logs back into his respective iCloud account on that same device, the device is then supposed to sync back down the data from the corresponding iCloud account. Makes sense!
I was wondering how I can achieve this when I use NSPersistentCloudKitContainer (instead of writing all that CloudKit code myself). I looked at the sample code related to Apple WWDC 2019 session 202 ("Using Core Data with CloudKit"), and this code does not what I want (the sample just does not focus on the iCloud account part, that is why they do not bother to empty the cache, I think): Indeed the NSPersistentCloudKitContainer stops synching if I log out the user, but it picks up again synching when I log back in. That is actually more like the desired (and indeed also actual, which is good) behaviour by the sample App when my web connection goes offline for a while.
But if the user logs out of iCloud (I use CloudKit framework to be informed about user account logout and login status), what I would need to do is somehow:
"disconnect" the sqlite store from the NSPersistentCloudKitContainer, then
empty (or even delete) the database, and then,
when the old (or another) user logs in, initialise a new NSPersistentCloudKitContainer (that will recreate an empty database as if the App would be used for the first time ever), so communication with the respective Cloud database can proceed.
I can not just empty the database WHILE being "connected" to the NSPersistentCloudKitContainer, as it records all the deletes and as soon as the (same) user logs in again, these deletes are synched to the Cloud, which I of course do NOT want.
Is this how one does it, aka essentially follow these three steps?
And if yes, how do I do step 2? Since I must use some kind of NSPersistentContainer to talk to the database, Apple warns not to directly do file system operations but only via Core Data. So do I need to init a "standard" NSPersistentContainer (without a communication pipe to the Cloud), and then destroy the database (e.g. using e.g. the coordinator instance method destroyPersistentStore())?
Or is there another approach for achieving the same thing?
Thank you very much for any help!!

Xamarin IOS identifying device

I'm writing an application which will be used in an enterprise, no outsiders.
This application should fetch data from API response and display it.
Each user has his own device, Ipad and should see only the data he is the owner of.
Problem i'm facing is identifying the device/user, so that API responds with only the information the user is supposed to see.
brief example of how it should work:
App is opened -> get unique id -> attach ID to API call -> receive appropiate response -> display data
As i imagine this ID should be static and not made upon installation of the app or generated.
I've tried getting UDID, Serial, MAC,- no luck, they're deprecated. Only managed to get .IdentifierForVendor, which is unique not in the way that i need.
So here is my question, are there any other options left?
Like fetching appleID name,email or should i make unique deployments for everyone separately?
Or a Log-in screen?
You could create a GUID for every App instance. However, apart from that you will have a hard time doing what you want.
These ways of identifying a device have been deprecated to ensure Advertisers and other malicious Apps cannot fingerprint a device easily.
If you don't want too much hassle authenticating everyone, you could apply a simpler scheme such as using a pin code, QR code, NFC tag or whatever you prefer.
However, if someone were to steal one of these enterprise devices and it would contain any secret information I would rather rely on something more secure as username and password, or even better something multi-factor.
Unique id's will have to be set by deploying the app from MDM. For example:
https://docs.jamf.com/9.9/casper-suite/administrator-guide/In-House_Apps.html
How should the application accept those variables, i dont know. Maybe it modifies .plist when deploying.
Solution i did was enforcing device name from MDM, so that users are unable to change it - and using that as the unique identifier.

Share iCloud Key-Value Storage with app from other Developer

The question might seem weird (and stupid) at first, but keep reading...
I used iCloud Key-Value Storage in one of my apps and now I need to Transfer this app to another Developer Account. But it's, for some reason, impossible to transfer apps if they've used iCloud Entitlements (why no warning?!?!).
So...In other words, I need to remove my original app and create a new one in my new Developer Account. But before that happen, I want my existing users to be able to sync their data to a common iCloud Key-Value Storage, but directed at the new app "container".
If, the "new" app is Live, would it be possible to point at that app Cloud Container (from my old one)? (e.g. my old app saves iCloud data to the new container).
When reading my own question I just think "this sounds like a big security breach if possible", so my guess is, no. But there's nothing in the Apple Documentation that says that this is not possible.
I'm not interested in solutions that involves users saving data on an external db (I know this is possible, but not what I'm looking for right now). Is there some way to save the data locally on disk (without being removed when app is removed) and then read it from the other app?

NSUbiquitousKeyValueStore vs NSUserDefaults

From Apple's NSUbiquitousKeyValueStore documentation:
If you write to the key-value store object when the user is not signed into an iCloud account, the data is stored locally until the next synchronization opportunity. When the user signs into an iCloud account, the system automatically reconciles your local, on-disk keys and values with those on the iCloud server.
Therefore if a user never signs into an iCloud account, the key-value store object is stored locally indefinitely, much like NSUserDefaults.
In this case, should we all stop using NSUserDefaults and just use NSUbiquitousKeyValueStore as a 'default' for all apps? What are the disadvantages of this approach?
An advantage I can see is that from a user perspective the app preferences will be synced across all their devices, which is most likely a better user experience!
We should clearly understand that NSUbiquitousKeyValueStore in the iCloud is for the configuration and tracking of the app state across all devices of the certain account.
Some facts bout NSUbiquitousKeyValueStore.
In the documentation we can find that :
Avoid using this class for data that is essential to your app’s
behavior when offline; instead, store such data directly into the
local user defaults database.
Also size of the data that is possible to save is relatively small.
The total amount of space available in your app’s key-value store, for
a given user, is 1 MB. There is a per-key value size limit of 1 MB,
and a maximum of 1024 keys.
I have found if the user goes into their iCloud settings and turns your app switch off - you will no longer be able to save to NSUbiquitousKeyValueStore.
Your app will start with it enabled. Then you may save data there. Once iCloud is turned off, it will always be accessible to read - but if you update the data and restart the app, i believe you will see it revert back to what it was before the user turned off iCloud support in iCloud settings.
This is a problem I am working with at the moment. I am trying to find a way to test if that switch is on/off and change my data store to NSUserDefaults.
Correct me if I am wrong but that is what I have discovered so far.
-mark
edit: this is only if you have registered for iCloud Documents. If you are ONLY using NSUbiquitousKeyValueStore it should be virtually the same - I believe.
edit-edit: now its acting different. The switch is there when ONLY NSUbiquitousKeyValueStore is checked in the iCloud capabilities. So looking - again - for a way to detect if that switch is flipped for an app in iCloud Settings.

How can one app provide data to another without swiching apps?

Scenario:
I "control" two different apps, App A and App B, both which the user has installed
App A is running
App A needs to obtain a string that was set by App B when App B last ran.
After obtaining the string, App A will still be running
User should not receive any feedback this communication is happening. E.g. no "switching animations" between A or B, no pop-ups, etc.
Constraints:
Apps are released under different vendors
Apps are already in the app store; updated versions will have this communication ability.
It is acceptable for the data stored in App B to be accessible to other apps on the device.
It is not acceptable for the data stored in App B to be visible to general third parties (e.g. if an external server is used, there needs to be some sort of secured scheme)
The data read should be able to occur immediately upon App A being opened after install. For instance, I cannot require the user of App A to enter log in credentials for an external communication service.
Must work on non-jailbroken devices.
This is seeming rather difficult to pull off in iOS7. Help is appreciated.
Tricky work around. Not recommended, but it will get the job done if you can't afford servers.
On the first app create a contact in the user's contacts book. Give it a generic name like "000 - NameOfAppB Data - Don't Delete" (I start with "000" so it goes to the bottom of the users contact book so they never see it, I also add "don't delete" so if the user does somehow find it they don't delete it hahaha) (who looks at contact books anyways). In the contact info under notes add your NSData in string format.
Then when app A is opened search for that contact, read the data, then delete the contact.
Apple does allow you to create and delete users contacts without their permission. (At least in 2011 they did, this may have changed).
This might serve your purpose
https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/Reference/reference.html
I am not sure of its limitations though, i have seen implementations where credentials have been shared between apps.

Resources