Strange Thing Going on with UUID on messages extension - ios

I am creating this messages extension that is a game.
When I receive a conversation on didBecomeActiveWithConversation I grab my UUID and the opponent's UUID, for example:
myUUID = [conversation.localParticipantIdentifier UUIDString];
opponentUUID = [[conversation.remoteParticipantIdentifiers firstObject] UUIDString];
at this point if I print this I get something like
myUUID = 3A00236E-606E-41BE-BD11-97658AF13434
opponentUUID = 794DC7EB-E0AF-46CD-9BF0-5B6D39CC6773
Then I make my move in the game and send to the opponent.
On the simulator I switch from "Kate" to "John Appleseed".
When the method didBecomeActiveWithConversation triggers again, now for the other user, I grab both UUID again. This is the result:
myUUID = 3A00236E-606E-41BE-BD11-97658AF13434
opponentUUID = B4621E05-4407-443E-9526-C8F0C82753D6
What? myUUID is the same as before and my opponentUUID is completely different?? By switching users on message I was expecting to see the entries reverted. How can that be? Bug?

Apple doesn't like issuing numbers that can be used to identify users beyond what is strictly necessary. In this case, the localParticipantIdentifier property is unique to each device (so person A has different identifiers on each device they are talking with) and each app install (so two different apps will see two different identifiers).
In fact, if the user deletes and reinstalls your extension, the identifier will be changed – just like identifierForVendor on UIDevice.
From the docs:
This UUID is scoped to this device. It remains stable as long as the extension is enabled. If the extension is disabled and reenabled, or if the containing app is removed and reinstalled, the UUID for the local participant changes.
This particular case is complicated by the fact that you're using the simulator, which is rigged by Apple to look like two accounts even though it's one device. I suspect that when you run the same code on two real devices you'll find two completely different numbers on both sides.
It's worth adding that there are several open radars for Messages identifiers, not least this one, so you might be right that it's a bug.

Related

NSUbiquityIdentityDidChangeNotification doesn't work?

I'm creating a cloudkit app, and have been trying multiple ways to get the NSUbiquityIdentityDidChangeNotification, but I never am able to get this notification.
I've tried both of these code versions under the delegate didFinish and the viewDidLoad methods. And I tried calling it from another notification - UIApplicationDidBecomeActiveNotification. I also put import Foundation at top of files.
Here's the basic code I've tried:
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "handleIdentityChanged:",
name: NSUbiquityIdentityDidChangeNotification,
object: nil)
// And this one I tried too from another post here on SO:
var localeChangeObserver = NSNotificationCenter.defaultCenter().addObserverForName(NSUbiquityIdentityDidChangeNotification, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
println("The user’s iCloud login changed: should refresh all user data.")
}
Does anyone know how to get this notification to work for only a cloudkit app in swift? I really just want to detect the iCloud status change and then initiate fetching the userID if there's been a change.
Not that I need to access the ubiquityIdentityToken, but I was wondering why not store the token and every-time the app starts compare the current token with the one in local storage to see if it's a different account or nil? Therefore, why is getting the notification necessary?
Also, the code for getting the token only seems to work if I turn on "iCloud Documents", which I don't need. Does anyone know the implications of having that turned on for a social app that doesn't need it? And is there another way to get the token without enabling iCloud Documents?
This is the code I used to get token and placed in the delegate didFinish method, but only works if iCloud documents is turned on:
var token = NSFileManager.defaultManager().ubiquityIdentityToken
println("token is \(token!)")
On iOS, when I sign out of iCloud, my app is killed. So there seems not really to be a need to receive a NSUbiquityIdentityDidChangeNotification. Like you have said, it seems to be sufficient to compare the current token to the saved token.
On the Apple TV though, my app was not killed when I logged out of iCloud. Here I had noticed the notification was not fired, like you described. Since the app is not killed, a notification would be in order. (Did Apple forget to kill apps on Apple TV when iCloud account is changed?)
With Apple TV there is no iCloud documents container available (unless I explicitly share one from an iOS app). I found that on the dev center website, for the app identifier, iCloud was shown as "Configurable" and not "Enabled" if no document container was selected. I wonder if this has an effect on receiving notifications.
Both on the Apple TV and iOS, I can also confirm that the iCloud token is nil when not using documents (here: key-value-store only). Now that makes it difficult for Apple TV apps (because the app is not killed on iCloud account change, like on iOS) to detect account changes.
I have just noticed that my Apple TV app does received several NSUbiquitousKeyValueStoreDidChangeExternallyNotification when I log into another iCloud account, to reflect the changes. I guess this is as good as it gets. These notifications come with the NSUbiquitousKeyValueStoreChangeReasonKey key in userInfo, and a value of NSUbiquitousKeyValueStoreAccountChange indicates the account has changed.
Sorry for not being able to provide a direct solution, maybe it helped to share my experience.
To be notified in iOS when a user logs in or out of iCloud while using your app, use CKAccountChangedNotification instead of NSUbiquityIdentityChanged notification.
(Longer explanation: https://stackoverflow.com/a/38689094/54423.)

MCNearbyServiceBrowserDelegate foundPeer reports different PeerId for a given advertiser device when switch out, then switch back on browsing device

iOS Multipeer Connectivity question...
My app uses MCNearbyServiceBrowser and MCNearbyServiceAdvertiser (but not simultaneously on a given device).
My MCNearbyServiceAdvertiser always uses the same PeerId ... I store it in NSUserDefaults, per the 2014 WWDC session's advice on this.
When another device is browsing for services, the browsing device gets a foundPeer browser delegate callback, as expected.
However, if on the browsing device I switch away from my app (e.g., via a Home button tap) and then switch back to my app, I get another call to foundPeer for the advertising device, but this time the PeerId is different!
This seems odd, because my advertiser always uses the same PeerId.
Any ideas why this might be happening? Unexpected?
(I was planning to see if a newly-found advertising device with a given PeerId is already in my table view of advertisers, but the above issue kind of messes up that plan.)
Thank you.
-Allan
From the apple docs: “ The Multipeer Connectivity framework is responsible for creating peer objects that represent other devices.”
After pressing the home button and switching back to the app the framework has created a new PeerID object to represent the advertising device. This is another object than the previous one, even though it represents the same advertising device. So you can not rely on PeerID object equality.
To identify peer correctly I suggest you should create an NSUUID string and archive it on disk and reuse it. When you initialise MCPeerID object the display name you should be passing would be displayName+UUID. Use display name for UI elements and UUID for identifying peer.
I hope it helps.
You will not get the same MCPeerID when you create two from the same display name. This ensures uniqueness when you have a name collision. It's common to use the device name as the display name. Not everyone personalizes theirs.
If you want to recognize and be recognized by previously connected peers, then you must save and retrieve the actual MCPeerID.
To see what I mean, paste the following code into a playground and run it.
import MultipeerConnectivity
let hostName = "TestPlaygroundHostName"
let firstPeerID = MCPeerID(displayName: hostName)
let secondPeerID = MCPeerID(displayName: hostName)
firstPeerID.hashValue == secondPeerID.hashValue

How do I check whether I can access a file saved with NSFileProtectionKey = NSFileProtectionCompleteUntilFirstUserAuthentication

I would like the determine if I have access to files that have been saved with the attribute NSFileProtectionKey = NSFileProtectionCompleteUntilFirstUserAuthentication.
I have tried [UIApplication sharedApplication].protectedDataAvailable, however from my tests it will return NO whenever the device is locked (if a pin code is set) even if the user has unlocked the device at least once since last starting the phone.
It says quite clearly in the docs: The value of this property is NO if data protection is enabled and the device is currently locked, and in this case files that were assigned the NSFileProtectionComplete or NSFileProtectionCompleteUnlessOpen protection key cannot be read or written by your app. i.e. this is not the correct property.
You need use one of the multi-tasking keys that causes the launch the app on boot - e.g. the voip key for UIBackgroundModes.
Mind you, you're pretty much testing the OS at that point - if you set the keys appropriately when creating the files it should work as advertised. If it doesn't then log a radar.

Can device token of Push Notification be used as a unique identifier?

Problem: using UDID is deprecated - we cannot use it anymore.
There are some solutions on the net: generate GUID and store it in the "safe place", iCloud, IdentifierForVendor starting with iOS6, OpenUID, SecuredID and so on...
Request:
I need to have a unique identifier of the Device to store user data on our server.
Question:
Can I use deviceToken of Push Notification as a unique identifier?
What are the pros and cons of this idea?
(-) user can disable push notifications
(+) unique number
(+) supported in all iOS
This is a terrible idea, the token can change if the user changes device or for some other unknown reason.
The user can have multiple devices
If the user reinstalls the app they can get an other token
It's not 100% that the user will keep the same token.
And most important of all: You are identifying devices not users!
One solution is to generate a UUID and save it in the user keychain where you retrieve it. But this can also be removed if the user clear the device.
You best option is to allow the user to login with an account, which that can create. Then you can combine this with the UUID in the keychain.
You should use identifierForVendor. The deviceToken for push notification is unique, but CAN change.
The token can change if the user reset the device, for unique device identifying you can use the following code
float currentVersion = 6.0;
NSString *udid = nil;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion)
{
//below code is taken from the Apple Sample code, to check you can download the files
https://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation
// OR
http://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation/VerificationController.zip (line number 319)
udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
}
else
{
//may cause apple rejection
udid = [UIDevice currentDevice].uniqueIdentifier;
//i think we can use the below link for ios5 or below but not sure it may accept or reject
https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5
}
//just saw a link which may help you better and have a look at image
http://www.doubleencore.com/2013/04/unique-identifiers/
can someone suggest the best way to persist the unique id even after reinstall app, delete app or system restart or system boot or factory reset

CFUUIDCreate UUID changes constantly

I am a beginner iPhone app developer and I am trying to show the iPhone or App unique identifier on a label through an IBAction button. I researched a little and know that some of the code have been deprecated and CFUUID is used instead. The code below is what I used. However, every time I touch the IBAction button, the UUID changes. What am I doing wrong?
CFUUIDRef udid = CFUUIDCreate(NULL);
NSString *udidString = (NSString *) CFUUIDCreateString(NULL, udid);
uuid.text= udidString;
I think you have misunderstood the purpose of CFUUIDCreate(), Read its documentation you'll understand.
I guess the API is serving it's purpose properly, which is to create universally unique identifier means every time you call this it will return you back unique identifier randomly.
You can use
[[UIDevice currentDevice] uniqueIdentifier]
However, this method is depreciated. In order to get a unique identifier for each device, you can still use CFUUIDCreateString and save the output to user defaults. Load this value each time the app runs. If the app is deleted and then reinstalled this value will be different.
If you do need a unique identifier across app installs you can use the network MAC address.
As mentioned above, CFUUIDCreate is intended to create a different UUID each time it is run. You can create one, and store it in your app if you like, or you could try something like https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5 - basically, it provides a uniqueGlobalDeviceIdentifier function on the UIDevice, using an MD5 hash of the MAC address as its basis.
[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]

Resources