I am a junior professional software developer.
I'm working on app with device limit per user, we use UIDevice.current.identifierForVendor for identifying device. Unfortunately we have problem with "device limit is reached" when installing and reinstalling app.
According to identifierForVendor documentation:
The value in this property remains the same while the app (or another
app from the same vendor) is installed on the iOS device. The value
changes when the user deletes all of that vendor’s apps from the
device and subsequently reinstalls one or more of them.
The problem is obvious - after app is deleted and reinstalled we have a new identifierForVendor and we treat it as a new device.
According to another part of documentation:
Normally, the vendor is
determined by data provided by the App Store. If the app was not
installed from the app store (such as enterprise apps and apps still
in development), then a vendor identifier is calculated based on the
app’s bundle ID.
I have two questions:
Problem accurs when we install app from Xcode or TestFlight. Would it appear also when we install app from AppStore?
Is there any other way to limit device number and determine a device?
PS. I know, that there already were a few similar questions, bu in my opinion the answers were not exhaustive and it was a few years ago :)
You can try to do it with Keychain:
Generate UUID().uuidString
Save it to Keychain with some of Keychain wrappers (e.g. KeychainAccess) using key "UniqueDeveiceID" or something.
Send generated UUID to the server(or whatever)
As summary:
After the app starts just check the value for the key UniqueDeveiceID exists. Keychain is not cleaning after reinstall so you'll have to chance to check if it's a reinstall or a newly registered device.
Related
My goal is to obtain the identifierForVendor for a specific app that is on the App Store and that I have NOT developed nor have access to. Lets say this app's bundle id is com.example.app
And just to preface, I was able to grab the identifierForVendor of com.example.app by sniffing the network requests. However, this is not an efficient or scalable way to get it for multiple devices. So, I am looking into other methods.
I have tried to get the identifierForVendor of com.example.app by creating a custom iOS app on Xcode with the bundle id com.example.test
I was hoping the identifierForVendor would be the same considering their documentation notes that apps with the same bundle id will have the same identifierForVendor, but it was not. It seems that the identifierForVendor is also based on the developer profile or something.
Is there anyway for me to get this identifierForVendor value of an external app?
The short answer is that you cannot.
Apple does not provide any details on how this identifier is computed.
The identifier is unique for apps with the same initial bundle id components for a given developer on each device.
For example, apps with bundle ids com.example.app1 and com.example.app2, both from developer1 would have the same identifierForVendor on a given device.
An app with the bundle id com.example.app3 on the same device but from a different developer would have a different identifierForVendor; that is the for vendor bit.
Even if you use the same bundle ID prefix you won't get the same identifier as an app from another developer.
You should also note:
The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them.
I have a requirement wherein I should not allow the user to install my app in more than 1 device. This is an enterprise application and I distributed this using Enterprise developer account. Based on the Google search I use IdentifierForVendor to get unique device ID, but this doesn't seem to work now as when the user uninstalls and installs the new/same version of the app in the same device again, it returns new DeviceID. Now I am back to my old question - How to find a DeviceID for IOS?
What I think is a possible approach is to deactivate the DeviceID when the user uninstalls the application. But I am not sure how to achieve this as there are no cycle/function calls when the app is uninstalled.
Apple documentation says if all the apps from the same vendor is uninstalled from the device, then at the time of new installation of any app from that vendor will take new IdentifierForVendor.
So I would suggest store this unique id in Keychain and whenever you open the app check if there is any unique id stored in keychain if not then generate one and keep it there.
If app in uninstalled also , the key will be still there.
After you re-install the app , when you access the key in keychain it'll be still there.
This way you can achieve your objective of uniquely tracking a device.
Talking of keychain , it's worthwhile to take a look at Xamarin.Essentials Nuget.It provides many cross platform features including keychain.
Hope this helps.
I need to be able to identify an iOS device across uninstalls/reinstalls.
To do so, I plan to store the identifierForVendor in the keychain at first install, and retrieve it on following installs.
Is there any risk of being rejected of the AppStore by doing so?
I've seen several questions about that so I guess it would be allowed, but the Developer Program License Agreement states that:
Further, neither You nor Your Application will use any permanent,
device-based identifier, or any data derived therefrom, for purposes
of uniquely identifying a device.
I could also use a NSUUID instead, would it be safer?
Edit: add some context for answers suggesting to implement a login.
My app already has an identification system (with a login). It allows the user to connect to his account, and he should be able to see a list of the devices linked (i.e. from which he did connect at some point) to its account, in order to monitor or to unlink them.
The problem is that the identifierForVendor changes after an uninstall/reinstall of the app, leaving a "ghost" device in the user's list. Storing and retrieving it would allow a reinstall of the app not to be considered as a new device. It would only be used for this, and not for advertising or tracking in any way.
TL;DR:
Storing UUID in phone's Keychain will not get your app rejected. So don't worry.
The UUID you're trying to use is NOT a permanent identifier as we know, and storing them does not violate the licensing term that you quoted. Apple deprecated UDID's, MAC addresses, IMEI number etc. to prevent developers from tracking/spamming users based on their unique ID's. This is a privacy problem. Since UUID is a temporary ID, we are free to store them and use them later on, which does not do harm to the user.
I am quoting this from the link from Apple's resources here: Using identifierForVendor
The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
-----****UPDATE IN IOS 10.3:****-----
It seems that Apple has made some changes to how Keychain works in iOS 10.3+. Keychain items stored in the Keychain will be deleted when the all the apps from the specific vendor are uninstalled. According to Apple, the residence of sensitive information of an app even after the app is gone from the device may lead to security risks, so they decided to forbid this kind of behavior.
Developers relying on Keychain storage even after an uninstall for their apps can make use of this WORKAROUND to continue with the intended functionality. According to this workaround, any app can access the information stored in that specific Keychain Access Group, so it is recommended that adding an extra layer of encryption to your data will protect it with even more security, although keychain encrypts items by default.
You may generate a device-id(->similar to UUID) on the server and store that in Keychain of iOS. If your app is reinstalled on the device and you find that device-id in the keychain, then you will be able to identify the device.
In my project I am using identifierForVendor for unique key for identify iOS device. Will it be approve by Apple or not? Is there are any way to identify iOS device uniquely?
No, Apple will approve your app. identifierForVendor is the way to go after Apple stopped approving apps using UDID. Note that identifierForVendor will be the same for all of your apps per user (if a user has more than one of your apps installed, all of these apps will return the same identifierForVendor).
Another way to go is to create custom UDIDs.
Apple won't reject your app. It is the current way to uniquely identify a device that have installed your app. But if the user un-installs your app (all apps) and installs again, the identifierForVendor will return an entirely different UUID.
The value in this property remains the same while the app (or another
app from the same vendor) is installed on the iOS device. The value
changes when the user deletes all of that vendor’s apps from the
device and subsequently reinstalls one or more of them. The value can
also change when installing test builds using Xcode or when installing
an app on a device using ad-hoc distribution. Therefore, if your app
stores the value of this property anywhere, you should gracefully
handle situations where the identifier changes.
Reference : UIDevice Class Reference
In my iOS app, I have to restrict the user to use iOS app per device. To do this I found a solution that we can use the identifierForVendor method of UUID (Universally Unique Identifier) which will generate a unique ID to uniquely identify an app on a device. (Here, I am not using UDID (Unique Device Identifier) because Apple rejects apps if the app uses UDID).
So my question as is there any possibilities that the two devices will have the same UUID. any idea?
EDIT 1:
I have one more doubt as if I installed the same app on different two devices and save its UUID string into the device KeyChain. Both devices have same iCloud account. Now while doing iCloud sync for this two devices, is one my device KeyChain will gets overwritten?
EDIT 2:
I have found answer for EDIT 1 as 'Yes, through iCloud Keychain, the keychain would be synced to another one of my devices, and I’d get the same device identifier from here and from below answer too'
For the item to be synced with iCloud keychain, I’d need to explicitly set the kSecAttrSynchronizable attribute. Using the SecItem API, we can set this attribute while adding a keychain item.
Is there any tutorial how to add item in Keychain (Without third party libraries)?
No, Two device does not have the same UUID. I am 100% Sure about it. So go with identifierForVendor method.
But, The UUID may be changed when you reinstall the the application in your device (If there is not other application for the same vendor).
The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
EDIT
YOUR QUESTION
I have one more doubt as if I installed the same app on different two devices and save its UUID string into the device KeyChain. Both devices have same iCloud account. Now while doing iCloud sync for this two devices, is one my device KeyChain will gets overwritten?
ANSWER
YES. Your keychain will gets overwritten. So you have same UUID for both 2 devices.
I thought is NO!
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
Normally, the vendor is determined by data provided by the App Store. If the app was not installed from the app store (such as enterprise apps and apps still in development), then a vendor identifier is calculated based on the app’s bundle ID. The bundle ID is assumed to be in reverse-DNS format.