How to get the realy fixed Device-ID in swift?












1















I use the below code since long time. I have thought it is unique



But I have deleted my app and reinstalled it, I get new different Device-ID.



if let uuid = UIDevice.current.identifierForVendor?.uuidString {
print(uuid)
}


every new reinstall, I get a new ID.



How do I get something which stays the same?










share|improve this question

























  • dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

    – Shobhakar Tiwari
    Aug 1 '18 at 20:17
















1















I use the below code since long time. I have thought it is unique



But I have deleted my app and reinstalled it, I get new different Device-ID.



if let uuid = UIDevice.current.identifierForVendor?.uuidString {
print(uuid)
}


every new reinstall, I get a new ID.



How do I get something which stays the same?










share|improve this question

























  • dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

    – Shobhakar Tiwari
    Aug 1 '18 at 20:17














1












1








1








I use the below code since long time. I have thought it is unique



But I have deleted my app and reinstalled it, I get new different Device-ID.



if let uuid = UIDevice.current.identifierForVendor?.uuidString {
print(uuid)
}


every new reinstall, I get a new ID.



How do I get something which stays the same?










share|improve this question
















I use the below code since long time. I have thought it is unique



But I have deleted my app and reinstalled it, I get new different Device-ID.



if let uuid = UIDevice.current.identifierForVendor?.uuidString {
print(uuid)
}


every new reinstall, I get a new ID.



How do I get something which stays the same?







swift deviceid






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 7:00









WMios

6,73093659




6,73093659










asked Aug 1 '18 at 20:14









user10118085user10118085

163




163













  • dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

    – Shobhakar Tiwari
    Aug 1 '18 at 20:17



















  • dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

    – Shobhakar Tiwari
    Aug 1 '18 at 20:17

















dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

– Shobhakar Tiwari
Aug 1 '18 at 20:17





dont use device id specific task , rather choose like , User id + device id ( identifierForVendor) which could be used as key to handle any scenario , in push notification related work , i rather choose this way . else if you want unique device id then you can go with third party lib which gives you unique id , else you need to write your own logic to generate unique id

– Shobhakar Tiwari
Aug 1 '18 at 20:17












3 Answers
3






active

oldest

votes


















2














Access to the unique device id (UDID) has been disallowed for ages now. identifierForVendor is its replacement, and its behaviour has always been documented.






share|improve this answer































    2














    Since the value returned from identifierForVendor can be cleared when deleting the app or reset if the user resets it in the Settings app, you have to manage persisting it yourself.



    There are a few ways to accomplish this. You can setup a server that assigns a uuid which is then persisted and fetched server side via user login, or you can create and store it locally in the keychain.



    Items stored in the keychain will not be deleted when the app is deleted. This allows you to check if a uuid was previously stored, if so you can retrieve it, if not you can generate a new uuid and persist it.



    Here's a way you could do it locally:



    /// Creates a new unique user identifier or retrieves the last one created
    func getUUID() -> String? {

    // create a keychain helper instance
    let keychain = KeychainAccess()

    // this is the key we'll use to store the uuid in the keychain
    let uuidKey = "com.myorg.myappid.unique_uuid"

    // check if we already have a uuid stored, if so return it
    if let uuid = try? keychain.queryKeychainData(itemKey: uuidKey), uuid != nil {
    return uuid
    }

    // generate a new id
    guard let newId = UIDevice.current.identifierForVendor?.uuidString else {
    return nil
    }

    // store new identifier in keychain
    try? keychain.addKeychainData(itemKey: uuidKey, itemValue: newId)

    // return new id
    return newId
    }


    And here's the class for storing/retrieving from the keychain:



    import Foundation

    class KeychainAccess {

    func addKeychainData(itemKey: String, itemValue: String) throws {
    guard let valueData = itemValue.data(using: .utf8) else {
    print("Keychain: Unable to store data, invalid input - key: (itemKey), value: (itemValue)")
    return
    }

    //delete old value if stored first
    do {
    try deleteKeychainData(itemKey: itemKey)
    } catch {
    print("Keychain: nothing to delete...")
    }

    let queryAdd: [String: AnyObject] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: itemKey as AnyObject,
    kSecValueData as String: valueData as AnyObject,
    kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
    ]
    let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)

    if resultCode != 0 {
    print("Keychain: value not added - Error: (resultCode)")
    } else {
    print("Keychain: value added successfully")
    }
    }

    func deleteKeychainData(itemKey: String) throws {
    let queryDelete: [String: AnyObject] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: itemKey as AnyObject
    ]

    let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

    if resultCodeDelete != 0 {
    print("Keychain: unable to delete from keychain: (resultCodeDelete)")
    } else {
    print("Keychain: successfully deleted item")
    }
    }

    func queryKeychainData (itemKey: String) throws -> String? {
    let queryLoad: [String: AnyObject] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: itemKey as AnyObject,
    kSecReturnData as String: kCFBooleanTrue,
    kSecMatchLimit as String: kSecMatchLimitOne
    ]
    var result: AnyObject?
    let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
    SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
    }

    if resultCodeLoad != 0 {
    print("Keychain: unable to load data - (resultCodeLoad)")
    return nil
    }

    guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
    print("Keychain: error parsing keychain result - (resultCodeLoad)")
    return nil
    }
    return keyValue
    }
    }


    Then you can just have a user class where you get the identifier:



    let uuid = getUUID()
    print("UUID: (uuid)")


    If you put this in a test app in viewDidLoad, launch the app and note the uuid printed in the console, delete the app and relaunch and you'll have the same uuid.



    You can also create your own completely custom uuid in the app if you like by doing something like this:



    // convenience extension for creating an MD5 hash from a string
    extension String {

    func MD5() -> Data? {
    guard let messageData = data(using: .utf8) else { return nil }

    var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
    _ = digestData.withUnsafeMutableBytes { digestBytes in
    messageData.withUnsafeBytes { messageBytes in
    CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
    }
    }

    return digestData
    }
    }

    // extension on UUID to generate your own custom UUID
    extension UUID {

    static func custom() -> String? {
    guard let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
    return nil
    }

    let unique = bundleID + NSUUID().uuidString
    let hashData = unique.MD5()
    let md5String = hashData?.map { String(format: "%02hhx", $0) }.joined()

    return md5String
    }
    }


    Note that to use the MD5 function you will have to add the following import to an Objective-C bridging header in your app: (if you're building with Xcode < 10. In Xcode 10+ CommonCrypto is included so you can skip this step)



    #import <CommonCrypto/CommonCrypto.h>


    If your app does not have a bridging header, add one to your project and make sure to set it in build settings:



    Screenshot



    Once it's setup you can generate your own custom uuid like this:



    let otherUuid = UUID.custom()
    print("Other: (otherUuid)")


    Running the app and logging both outputs generates uuids something like this:



    // uuid from first example
    UUID: Optional("8A2496F0-EFD0-4723-8C6D-8E18431A49D2")

    // uuid from second custom example
    Other: Optional("63674d91f08ec3aaa710f3448dd87818")





    share|improve this answer


























    • Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

      – Gereon
      Aug 2 '18 at 6:05






    • 1





      @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

      – digitalHound
      Aug 2 '18 at 14:44











    • Thanks, that's really interesting!

      – Gereon
      Aug 2 '18 at 19:54











    • the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

      – user10118085
      Aug 2 '18 at 20:47













    • That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

      – digitalHound
      Aug 2 '18 at 21:57



















    0














    Unique Id in iPhone is UDID, which is not accessible in current version of OS, because it can be misused. So Apple has given the other option for the unique key but it change every time you install the app.
    --Cannot access UDID



    But there is another way to implement this feature.



    First you have to generate the Unique ID :



    func createUniqueID() -> String {
    let uuid: CFUUID = CFUUIDCreate(nil)
    let cfStr: CFString = CFUUIDCreateString(nil, uuid)

    let swiftString: String = cfStr as String
    return swiftString
    }


    After getting the this which is unique but changes after the app install and reinstall.
    Save this id to the Key-Chain on any key let say "uniqueID".



    To save the key in keyChain :



       func getDataFromKeyChainFunction() {
    let uniqueID = KeyChain.createUniqueID()
    let data = uniqueID.data(using: String.Encoding.utf8)
    let status = KeyChain.save(key: "uniqueID", data: data!)
    if let udid = KeyChain.load(key: "uniqueID") {
    let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
    print(uniqueID!)
    }
    }

    func save(key: String, data: Data) -> OSStatus {
    let query = [
    kSecClass as String : kSecClassGenericPassword as String,
    kSecAttrAccount as String : key,
    kSecValueData as String : data ] as [String : Any]
    SecItemDelete(query as CFDictionary)
    return SecItemAdd(query as CFDictionary, nil)
    }


    Next when you required to perform any task based on uniqueID ,first check if any data is saved in Key-Chain on key "uniqueID" .
    Even if you uninstall the app , the key-chain data is still persisted, it will delete by OS.



    func checkUniqueID() {
    if let udid = KeyChain.load(key: "uniqueID") {
    let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
    print(uniqueID!)
    } else {
    let uniqueID = KeyChain.createUniqueID()
    let data = uniqueID.data(using: String.Encoding.utf8)
    let status = KeyChain.save(key: "uniqueID", data: data!)
    print("status: ", status)
    }
    }


    In this way you can generate the uniqueID once and use this id every time.



    NOTE: But when you upload next version of your app, upload it with the same Provisioning Profile otherwise you cannot access the key-chain store of your last installed app.
    Key-Chain Store is associated with the Provisioning profile.



    Check Here






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51641614%2fhow-to-get-the-realy-fixed-device-id-in-swift%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      Access to the unique device id (UDID) has been disallowed for ages now. identifierForVendor is its replacement, and its behaviour has always been documented.






      share|improve this answer




























        2














        Access to the unique device id (UDID) has been disallowed for ages now. identifierForVendor is its replacement, and its behaviour has always been documented.






        share|improve this answer


























          2












          2








          2







          Access to the unique device id (UDID) has been disallowed for ages now. identifierForVendor is its replacement, and its behaviour has always been documented.






          share|improve this answer













          Access to the unique device id (UDID) has been disallowed for ages now. identifierForVendor is its replacement, and its behaviour has always been documented.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Aug 1 '18 at 20:24









          GereonGereon

          6,81941847




          6,81941847

























              2














              Since the value returned from identifierForVendor can be cleared when deleting the app or reset if the user resets it in the Settings app, you have to manage persisting it yourself.



              There are a few ways to accomplish this. You can setup a server that assigns a uuid which is then persisted and fetched server side via user login, or you can create and store it locally in the keychain.



              Items stored in the keychain will not be deleted when the app is deleted. This allows you to check if a uuid was previously stored, if so you can retrieve it, if not you can generate a new uuid and persist it.



              Here's a way you could do it locally:



              /// Creates a new unique user identifier or retrieves the last one created
              func getUUID() -> String? {

              // create a keychain helper instance
              let keychain = KeychainAccess()

              // this is the key we'll use to store the uuid in the keychain
              let uuidKey = "com.myorg.myappid.unique_uuid"

              // check if we already have a uuid stored, if so return it
              if let uuid = try? keychain.queryKeychainData(itemKey: uuidKey), uuid != nil {
              return uuid
              }

              // generate a new id
              guard let newId = UIDevice.current.identifierForVendor?.uuidString else {
              return nil
              }

              // store new identifier in keychain
              try? keychain.addKeychainData(itemKey: uuidKey, itemValue: newId)

              // return new id
              return newId
              }


              And here's the class for storing/retrieving from the keychain:



              import Foundation

              class KeychainAccess {

              func addKeychainData(itemKey: String, itemValue: String) throws {
              guard let valueData = itemValue.data(using: .utf8) else {
              print("Keychain: Unable to store data, invalid input - key: (itemKey), value: (itemValue)")
              return
              }

              //delete old value if stored first
              do {
              try deleteKeychainData(itemKey: itemKey)
              } catch {
              print("Keychain: nothing to delete...")
              }

              let queryAdd: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecValueData as String: valueData as AnyObject,
              kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
              ]
              let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)

              if resultCode != 0 {
              print("Keychain: value not added - Error: (resultCode)")
              } else {
              print("Keychain: value added successfully")
              }
              }

              func deleteKeychainData(itemKey: String) throws {
              let queryDelete: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject
              ]

              let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

              if resultCodeDelete != 0 {
              print("Keychain: unable to delete from keychain: (resultCodeDelete)")
              } else {
              print("Keychain: successfully deleted item")
              }
              }

              func queryKeychainData (itemKey: String) throws -> String? {
              let queryLoad: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecReturnData as String: kCFBooleanTrue,
              kSecMatchLimit as String: kSecMatchLimitOne
              ]
              var result: AnyObject?
              let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
              SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
              }

              if resultCodeLoad != 0 {
              print("Keychain: unable to load data - (resultCodeLoad)")
              return nil
              }

              guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
              print("Keychain: error parsing keychain result - (resultCodeLoad)")
              return nil
              }
              return keyValue
              }
              }


              Then you can just have a user class where you get the identifier:



              let uuid = getUUID()
              print("UUID: (uuid)")


              If you put this in a test app in viewDidLoad, launch the app and note the uuid printed in the console, delete the app and relaunch and you'll have the same uuid.



              You can also create your own completely custom uuid in the app if you like by doing something like this:



              // convenience extension for creating an MD5 hash from a string
              extension String {

              func MD5() -> Data? {
              guard let messageData = data(using: .utf8) else { return nil }

              var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
              _ = digestData.withUnsafeMutableBytes { digestBytes in
              messageData.withUnsafeBytes { messageBytes in
              CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
              }
              }

              return digestData
              }
              }

              // extension on UUID to generate your own custom UUID
              extension UUID {

              static func custom() -> String? {
              guard let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
              return nil
              }

              let unique = bundleID + NSUUID().uuidString
              let hashData = unique.MD5()
              let md5String = hashData?.map { String(format: "%02hhx", $0) }.joined()

              return md5String
              }
              }


              Note that to use the MD5 function you will have to add the following import to an Objective-C bridging header in your app: (if you're building with Xcode < 10. In Xcode 10+ CommonCrypto is included so you can skip this step)



              #import <CommonCrypto/CommonCrypto.h>


              If your app does not have a bridging header, add one to your project and make sure to set it in build settings:



              Screenshot



              Once it's setup you can generate your own custom uuid like this:



              let otherUuid = UUID.custom()
              print("Other: (otherUuid)")


              Running the app and logging both outputs generates uuids something like this:



              // uuid from first example
              UUID: Optional("8A2496F0-EFD0-4723-8C6D-8E18431A49D2")

              // uuid from second custom example
              Other: Optional("63674d91f08ec3aaa710f3448dd87818")





              share|improve this answer


























              • Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

                – Gereon
                Aug 2 '18 at 6:05






              • 1





                @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

                – digitalHound
                Aug 2 '18 at 14:44











              • Thanks, that's really interesting!

                – Gereon
                Aug 2 '18 at 19:54











              • the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

                – user10118085
                Aug 2 '18 at 20:47













              • That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

                – digitalHound
                Aug 2 '18 at 21:57
















              2














              Since the value returned from identifierForVendor can be cleared when deleting the app or reset if the user resets it in the Settings app, you have to manage persisting it yourself.



              There are a few ways to accomplish this. You can setup a server that assigns a uuid which is then persisted and fetched server side via user login, or you can create and store it locally in the keychain.



              Items stored in the keychain will not be deleted when the app is deleted. This allows you to check if a uuid was previously stored, if so you can retrieve it, if not you can generate a new uuid and persist it.



              Here's a way you could do it locally:



              /// Creates a new unique user identifier or retrieves the last one created
              func getUUID() -> String? {

              // create a keychain helper instance
              let keychain = KeychainAccess()

              // this is the key we'll use to store the uuid in the keychain
              let uuidKey = "com.myorg.myappid.unique_uuid"

              // check if we already have a uuid stored, if so return it
              if let uuid = try? keychain.queryKeychainData(itemKey: uuidKey), uuid != nil {
              return uuid
              }

              // generate a new id
              guard let newId = UIDevice.current.identifierForVendor?.uuidString else {
              return nil
              }

              // store new identifier in keychain
              try? keychain.addKeychainData(itemKey: uuidKey, itemValue: newId)

              // return new id
              return newId
              }


              And here's the class for storing/retrieving from the keychain:



              import Foundation

              class KeychainAccess {

              func addKeychainData(itemKey: String, itemValue: String) throws {
              guard let valueData = itemValue.data(using: .utf8) else {
              print("Keychain: Unable to store data, invalid input - key: (itemKey), value: (itemValue)")
              return
              }

              //delete old value if stored first
              do {
              try deleteKeychainData(itemKey: itemKey)
              } catch {
              print("Keychain: nothing to delete...")
              }

              let queryAdd: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecValueData as String: valueData as AnyObject,
              kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
              ]
              let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)

              if resultCode != 0 {
              print("Keychain: value not added - Error: (resultCode)")
              } else {
              print("Keychain: value added successfully")
              }
              }

              func deleteKeychainData(itemKey: String) throws {
              let queryDelete: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject
              ]

              let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

              if resultCodeDelete != 0 {
              print("Keychain: unable to delete from keychain: (resultCodeDelete)")
              } else {
              print("Keychain: successfully deleted item")
              }
              }

              func queryKeychainData (itemKey: String) throws -> String? {
              let queryLoad: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecReturnData as String: kCFBooleanTrue,
              kSecMatchLimit as String: kSecMatchLimitOne
              ]
              var result: AnyObject?
              let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
              SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
              }

              if resultCodeLoad != 0 {
              print("Keychain: unable to load data - (resultCodeLoad)")
              return nil
              }

              guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
              print("Keychain: error parsing keychain result - (resultCodeLoad)")
              return nil
              }
              return keyValue
              }
              }


              Then you can just have a user class where you get the identifier:



              let uuid = getUUID()
              print("UUID: (uuid)")


              If you put this in a test app in viewDidLoad, launch the app and note the uuid printed in the console, delete the app and relaunch and you'll have the same uuid.



              You can also create your own completely custom uuid in the app if you like by doing something like this:



              // convenience extension for creating an MD5 hash from a string
              extension String {

              func MD5() -> Data? {
              guard let messageData = data(using: .utf8) else { return nil }

              var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
              _ = digestData.withUnsafeMutableBytes { digestBytes in
              messageData.withUnsafeBytes { messageBytes in
              CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
              }
              }

              return digestData
              }
              }

              // extension on UUID to generate your own custom UUID
              extension UUID {

              static func custom() -> String? {
              guard let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
              return nil
              }

              let unique = bundleID + NSUUID().uuidString
              let hashData = unique.MD5()
              let md5String = hashData?.map { String(format: "%02hhx", $0) }.joined()

              return md5String
              }
              }


              Note that to use the MD5 function you will have to add the following import to an Objective-C bridging header in your app: (if you're building with Xcode < 10. In Xcode 10+ CommonCrypto is included so you can skip this step)



              #import <CommonCrypto/CommonCrypto.h>


              If your app does not have a bridging header, add one to your project and make sure to set it in build settings:



              Screenshot



              Once it's setup you can generate your own custom uuid like this:



              let otherUuid = UUID.custom()
              print("Other: (otherUuid)")


              Running the app and logging both outputs generates uuids something like this:



              // uuid from first example
              UUID: Optional("8A2496F0-EFD0-4723-8C6D-8E18431A49D2")

              // uuid from second custom example
              Other: Optional("63674d91f08ec3aaa710f3448dd87818")





              share|improve this answer


























              • Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

                – Gereon
                Aug 2 '18 at 6:05






              • 1





                @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

                – digitalHound
                Aug 2 '18 at 14:44











              • Thanks, that's really interesting!

                – Gereon
                Aug 2 '18 at 19:54











              • the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

                – user10118085
                Aug 2 '18 at 20:47













              • That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

                – digitalHound
                Aug 2 '18 at 21:57














              2












              2








              2







              Since the value returned from identifierForVendor can be cleared when deleting the app or reset if the user resets it in the Settings app, you have to manage persisting it yourself.



              There are a few ways to accomplish this. You can setup a server that assigns a uuid which is then persisted and fetched server side via user login, or you can create and store it locally in the keychain.



              Items stored in the keychain will not be deleted when the app is deleted. This allows you to check if a uuid was previously stored, if so you can retrieve it, if not you can generate a new uuid and persist it.



              Here's a way you could do it locally:



              /// Creates a new unique user identifier or retrieves the last one created
              func getUUID() -> String? {

              // create a keychain helper instance
              let keychain = KeychainAccess()

              // this is the key we'll use to store the uuid in the keychain
              let uuidKey = "com.myorg.myappid.unique_uuid"

              // check if we already have a uuid stored, if so return it
              if let uuid = try? keychain.queryKeychainData(itemKey: uuidKey), uuid != nil {
              return uuid
              }

              // generate a new id
              guard let newId = UIDevice.current.identifierForVendor?.uuidString else {
              return nil
              }

              // store new identifier in keychain
              try? keychain.addKeychainData(itemKey: uuidKey, itemValue: newId)

              // return new id
              return newId
              }


              And here's the class for storing/retrieving from the keychain:



              import Foundation

              class KeychainAccess {

              func addKeychainData(itemKey: String, itemValue: String) throws {
              guard let valueData = itemValue.data(using: .utf8) else {
              print("Keychain: Unable to store data, invalid input - key: (itemKey), value: (itemValue)")
              return
              }

              //delete old value if stored first
              do {
              try deleteKeychainData(itemKey: itemKey)
              } catch {
              print("Keychain: nothing to delete...")
              }

              let queryAdd: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecValueData as String: valueData as AnyObject,
              kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
              ]
              let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)

              if resultCode != 0 {
              print("Keychain: value not added - Error: (resultCode)")
              } else {
              print("Keychain: value added successfully")
              }
              }

              func deleteKeychainData(itemKey: String) throws {
              let queryDelete: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject
              ]

              let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

              if resultCodeDelete != 0 {
              print("Keychain: unable to delete from keychain: (resultCodeDelete)")
              } else {
              print("Keychain: successfully deleted item")
              }
              }

              func queryKeychainData (itemKey: String) throws -> String? {
              let queryLoad: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecReturnData as String: kCFBooleanTrue,
              kSecMatchLimit as String: kSecMatchLimitOne
              ]
              var result: AnyObject?
              let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
              SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
              }

              if resultCodeLoad != 0 {
              print("Keychain: unable to load data - (resultCodeLoad)")
              return nil
              }

              guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
              print("Keychain: error parsing keychain result - (resultCodeLoad)")
              return nil
              }
              return keyValue
              }
              }


              Then you can just have a user class where you get the identifier:



              let uuid = getUUID()
              print("UUID: (uuid)")


              If you put this in a test app in viewDidLoad, launch the app and note the uuid printed in the console, delete the app and relaunch and you'll have the same uuid.



              You can also create your own completely custom uuid in the app if you like by doing something like this:



              // convenience extension for creating an MD5 hash from a string
              extension String {

              func MD5() -> Data? {
              guard let messageData = data(using: .utf8) else { return nil }

              var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
              _ = digestData.withUnsafeMutableBytes { digestBytes in
              messageData.withUnsafeBytes { messageBytes in
              CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
              }
              }

              return digestData
              }
              }

              // extension on UUID to generate your own custom UUID
              extension UUID {

              static func custom() -> String? {
              guard let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
              return nil
              }

              let unique = bundleID + NSUUID().uuidString
              let hashData = unique.MD5()
              let md5String = hashData?.map { String(format: "%02hhx", $0) }.joined()

              return md5String
              }
              }


              Note that to use the MD5 function you will have to add the following import to an Objective-C bridging header in your app: (if you're building with Xcode < 10. In Xcode 10+ CommonCrypto is included so you can skip this step)



              #import <CommonCrypto/CommonCrypto.h>


              If your app does not have a bridging header, add one to your project and make sure to set it in build settings:



              Screenshot



              Once it's setup you can generate your own custom uuid like this:



              let otherUuid = UUID.custom()
              print("Other: (otherUuid)")


              Running the app and logging both outputs generates uuids something like this:



              // uuid from first example
              UUID: Optional("8A2496F0-EFD0-4723-8C6D-8E18431A49D2")

              // uuid from second custom example
              Other: Optional("63674d91f08ec3aaa710f3448dd87818")





              share|improve this answer















              Since the value returned from identifierForVendor can be cleared when deleting the app or reset if the user resets it in the Settings app, you have to manage persisting it yourself.



              There are a few ways to accomplish this. You can setup a server that assigns a uuid which is then persisted and fetched server side via user login, or you can create and store it locally in the keychain.



              Items stored in the keychain will not be deleted when the app is deleted. This allows you to check if a uuid was previously stored, if so you can retrieve it, if not you can generate a new uuid and persist it.



              Here's a way you could do it locally:



              /// Creates a new unique user identifier or retrieves the last one created
              func getUUID() -> String? {

              // create a keychain helper instance
              let keychain = KeychainAccess()

              // this is the key we'll use to store the uuid in the keychain
              let uuidKey = "com.myorg.myappid.unique_uuid"

              // check if we already have a uuid stored, if so return it
              if let uuid = try? keychain.queryKeychainData(itemKey: uuidKey), uuid != nil {
              return uuid
              }

              // generate a new id
              guard let newId = UIDevice.current.identifierForVendor?.uuidString else {
              return nil
              }

              // store new identifier in keychain
              try? keychain.addKeychainData(itemKey: uuidKey, itemValue: newId)

              // return new id
              return newId
              }


              And here's the class for storing/retrieving from the keychain:



              import Foundation

              class KeychainAccess {

              func addKeychainData(itemKey: String, itemValue: String) throws {
              guard let valueData = itemValue.data(using: .utf8) else {
              print("Keychain: Unable to store data, invalid input - key: (itemKey), value: (itemValue)")
              return
              }

              //delete old value if stored first
              do {
              try deleteKeychainData(itemKey: itemKey)
              } catch {
              print("Keychain: nothing to delete...")
              }

              let queryAdd: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecValueData as String: valueData as AnyObject,
              kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
              ]
              let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)

              if resultCode != 0 {
              print("Keychain: value not added - Error: (resultCode)")
              } else {
              print("Keychain: value added successfully")
              }
              }

              func deleteKeychainData(itemKey: String) throws {
              let queryDelete: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject
              ]

              let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

              if resultCodeDelete != 0 {
              print("Keychain: unable to delete from keychain: (resultCodeDelete)")
              } else {
              print("Keychain: successfully deleted item")
              }
              }

              func queryKeychainData (itemKey: String) throws -> String? {
              let queryLoad: [String: AnyObject] = [
              kSecClass as String: kSecClassGenericPassword,
              kSecAttrAccount as String: itemKey as AnyObject,
              kSecReturnData as String: kCFBooleanTrue,
              kSecMatchLimit as String: kSecMatchLimitOne
              ]
              var result: AnyObject?
              let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
              SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
              }

              if resultCodeLoad != 0 {
              print("Keychain: unable to load data - (resultCodeLoad)")
              return nil
              }

              guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
              print("Keychain: error parsing keychain result - (resultCodeLoad)")
              return nil
              }
              return keyValue
              }
              }


              Then you can just have a user class where you get the identifier:



              let uuid = getUUID()
              print("UUID: (uuid)")


              If you put this in a test app in viewDidLoad, launch the app and note the uuid printed in the console, delete the app and relaunch and you'll have the same uuid.



              You can also create your own completely custom uuid in the app if you like by doing something like this:



              // convenience extension for creating an MD5 hash from a string
              extension String {

              func MD5() -> Data? {
              guard let messageData = data(using: .utf8) else { return nil }

              var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
              _ = digestData.withUnsafeMutableBytes { digestBytes in
              messageData.withUnsafeBytes { messageBytes in
              CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
              }
              }

              return digestData
              }
              }

              // extension on UUID to generate your own custom UUID
              extension UUID {

              static func custom() -> String? {
              guard let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else {
              return nil
              }

              let unique = bundleID + NSUUID().uuidString
              let hashData = unique.MD5()
              let md5String = hashData?.map { String(format: "%02hhx", $0) }.joined()

              return md5String
              }
              }


              Note that to use the MD5 function you will have to add the following import to an Objective-C bridging header in your app: (if you're building with Xcode < 10. In Xcode 10+ CommonCrypto is included so you can skip this step)



              #import <CommonCrypto/CommonCrypto.h>


              If your app does not have a bridging header, add one to your project and make sure to set it in build settings:



              Screenshot



              Once it's setup you can generate your own custom uuid like this:



              let otherUuid = UUID.custom()
              print("Other: (otherUuid)")


              Running the app and logging both outputs generates uuids something like this:



              // uuid from first example
              UUID: Optional("8A2496F0-EFD0-4723-8C6D-8E18431A49D2")

              // uuid from second custom example
              Other: Optional("63674d91f08ec3aaa710f3448dd87818")






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Aug 30 '18 at 22:36

























              answered Aug 1 '18 at 22:14









              digitalHounddigitalHound

              2,7241723




              2,7241723













              • Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

                – Gereon
                Aug 2 '18 at 6:05






              • 1





                @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

                – digitalHound
                Aug 2 '18 at 14:44











              • Thanks, that's really interesting!

                – Gereon
                Aug 2 '18 at 19:54











              • the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

                – user10118085
                Aug 2 '18 at 20:47













              • That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

                – digitalHound
                Aug 2 '18 at 21:57



















              • Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

                – Gereon
                Aug 2 '18 at 6:05






              • 1





                @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

                – digitalHound
                Aug 2 '18 at 14:44











              • Thanks, that's really interesting!

                – Gereon
                Aug 2 '18 at 19:54











              • the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

                – user10118085
                Aug 2 '18 at 20:47













              • That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

                – digitalHound
                Aug 2 '18 at 21:57

















              Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

              – Gereon
              Aug 2 '18 at 6:05





              Is the keychain data still kept when uninstalling? According to forums.developer.apple.com/message/210531#210531 this changed in iOS 10.3

              – Gereon
              Aug 2 '18 at 6:05




              1




              1





              @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

              – digitalHound
              Aug 2 '18 at 14:44





              @Gereon Testing in the iPhone X simulator with iOS 11.4 it looks like it still works. Also working on my device running 11.4 as well.

              – digitalHound
              Aug 2 '18 at 14:44













              Thanks, that's really interesting!

              – Gereon
              Aug 2 '18 at 19:54





              Thanks, that's really interesting!

              – Gereon
              Aug 2 '18 at 19:54













              the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

              – user10118085
              Aug 2 '18 at 20:47







              the old device-id has been saved in database in my server. so if the user tries to login, the php code compares the first registred device-id and the current one. so if it is not the same, the user gets message "ths is not the registred device". what to do in this case ?

              – user10118085
              Aug 2 '18 at 20:47















              That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

              – digitalHound
              Aug 2 '18 at 21:57





              That's more of a subjective business logic question and all depends on what you want to do. You could get that scenario if a user tries to log in with more than one device, it doesn't necessarily mean that they've deleted the app. I would probably give them the option to update the registered device and replace the old id with the new one. If you wanted to lock it down then you could do it by having them click a link in an email you send to their registered email address on your system that uses deep linking and launches the app to send the updated uuid to your server.

              – digitalHound
              Aug 2 '18 at 21:57











              0














              Unique Id in iPhone is UDID, which is not accessible in current version of OS, because it can be misused. So Apple has given the other option for the unique key but it change every time you install the app.
              --Cannot access UDID



              But there is another way to implement this feature.



              First you have to generate the Unique ID :



              func createUniqueID() -> String {
              let uuid: CFUUID = CFUUIDCreate(nil)
              let cfStr: CFString = CFUUIDCreateString(nil, uuid)

              let swiftString: String = cfStr as String
              return swiftString
              }


              After getting the this which is unique but changes after the app install and reinstall.
              Save this id to the Key-Chain on any key let say "uniqueID".



              To save the key in keyChain :



                 func getDataFromKeyChainFunction() {
              let uniqueID = KeyChain.createUniqueID()
              let data = uniqueID.data(using: String.Encoding.utf8)
              let status = KeyChain.save(key: "uniqueID", data: data!)
              if let udid = KeyChain.load(key: "uniqueID") {
              let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
              print(uniqueID!)
              }
              }

              func save(key: String, data: Data) -> OSStatus {
              let query = [
              kSecClass as String : kSecClassGenericPassword as String,
              kSecAttrAccount as String : key,
              kSecValueData as String : data ] as [String : Any]
              SecItemDelete(query as CFDictionary)
              return SecItemAdd(query as CFDictionary, nil)
              }


              Next when you required to perform any task based on uniqueID ,first check if any data is saved in Key-Chain on key "uniqueID" .
              Even if you uninstall the app , the key-chain data is still persisted, it will delete by OS.



              func checkUniqueID() {
              if let udid = KeyChain.load(key: "uniqueID") {
              let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
              print(uniqueID!)
              } else {
              let uniqueID = KeyChain.createUniqueID()
              let data = uniqueID.data(using: String.Encoding.utf8)
              let status = KeyChain.save(key: "uniqueID", data: data!)
              print("status: ", status)
              }
              }


              In this way you can generate the uniqueID once and use this id every time.



              NOTE: But when you upload next version of your app, upload it with the same Provisioning Profile otherwise you cannot access the key-chain store of your last installed app.
              Key-Chain Store is associated with the Provisioning profile.



              Check Here






              share|improve this answer




























                0














                Unique Id in iPhone is UDID, which is not accessible in current version of OS, because it can be misused. So Apple has given the other option for the unique key but it change every time you install the app.
                --Cannot access UDID



                But there is another way to implement this feature.



                First you have to generate the Unique ID :



                func createUniqueID() -> String {
                let uuid: CFUUID = CFUUIDCreate(nil)
                let cfStr: CFString = CFUUIDCreateString(nil, uuid)

                let swiftString: String = cfStr as String
                return swiftString
                }


                After getting the this which is unique but changes after the app install and reinstall.
                Save this id to the Key-Chain on any key let say "uniqueID".



                To save the key in keyChain :



                   func getDataFromKeyChainFunction() {
                let uniqueID = KeyChain.createUniqueID()
                let data = uniqueID.data(using: String.Encoding.utf8)
                let status = KeyChain.save(key: "uniqueID", data: data!)
                if let udid = KeyChain.load(key: "uniqueID") {
                let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                print(uniqueID!)
                }
                }

                func save(key: String, data: Data) -> OSStatus {
                let query = [
                kSecClass as String : kSecClassGenericPassword as String,
                kSecAttrAccount as String : key,
                kSecValueData as String : data ] as [String : Any]
                SecItemDelete(query as CFDictionary)
                return SecItemAdd(query as CFDictionary, nil)
                }


                Next when you required to perform any task based on uniqueID ,first check if any data is saved in Key-Chain on key "uniqueID" .
                Even if you uninstall the app , the key-chain data is still persisted, it will delete by OS.



                func checkUniqueID() {
                if let udid = KeyChain.load(key: "uniqueID") {
                let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                print(uniqueID!)
                } else {
                let uniqueID = KeyChain.createUniqueID()
                let data = uniqueID.data(using: String.Encoding.utf8)
                let status = KeyChain.save(key: "uniqueID", data: data!)
                print("status: ", status)
                }
                }


                In this way you can generate the uniqueID once and use this id every time.



                NOTE: But when you upload next version of your app, upload it with the same Provisioning Profile otherwise you cannot access the key-chain store of your last installed app.
                Key-Chain Store is associated with the Provisioning profile.



                Check Here






                share|improve this answer


























                  0












                  0








                  0







                  Unique Id in iPhone is UDID, which is not accessible in current version of OS, because it can be misused. So Apple has given the other option for the unique key but it change every time you install the app.
                  --Cannot access UDID



                  But there is another way to implement this feature.



                  First you have to generate the Unique ID :



                  func createUniqueID() -> String {
                  let uuid: CFUUID = CFUUIDCreate(nil)
                  let cfStr: CFString = CFUUIDCreateString(nil, uuid)

                  let swiftString: String = cfStr as String
                  return swiftString
                  }


                  After getting the this which is unique but changes after the app install and reinstall.
                  Save this id to the Key-Chain on any key let say "uniqueID".



                  To save the key in keyChain :



                     func getDataFromKeyChainFunction() {
                  let uniqueID = KeyChain.createUniqueID()
                  let data = uniqueID.data(using: String.Encoding.utf8)
                  let status = KeyChain.save(key: "uniqueID", data: data!)
                  if let udid = KeyChain.load(key: "uniqueID") {
                  let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                  print(uniqueID!)
                  }
                  }

                  func save(key: String, data: Data) -> OSStatus {
                  let query = [
                  kSecClass as String : kSecClassGenericPassword as String,
                  kSecAttrAccount as String : key,
                  kSecValueData as String : data ] as [String : Any]
                  SecItemDelete(query as CFDictionary)
                  return SecItemAdd(query as CFDictionary, nil)
                  }


                  Next when you required to perform any task based on uniqueID ,first check if any data is saved in Key-Chain on key "uniqueID" .
                  Even if you uninstall the app , the key-chain data is still persisted, it will delete by OS.



                  func checkUniqueID() {
                  if let udid = KeyChain.load(key: "uniqueID") {
                  let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                  print(uniqueID!)
                  } else {
                  let uniqueID = KeyChain.createUniqueID()
                  let data = uniqueID.data(using: String.Encoding.utf8)
                  let status = KeyChain.save(key: "uniqueID", data: data!)
                  print("status: ", status)
                  }
                  }


                  In this way you can generate the uniqueID once and use this id every time.



                  NOTE: But when you upload next version of your app, upload it with the same Provisioning Profile otherwise you cannot access the key-chain store of your last installed app.
                  Key-Chain Store is associated with the Provisioning profile.



                  Check Here






                  share|improve this answer













                  Unique Id in iPhone is UDID, which is not accessible in current version of OS, because it can be misused. So Apple has given the other option for the unique key but it change every time you install the app.
                  --Cannot access UDID



                  But there is another way to implement this feature.



                  First you have to generate the Unique ID :



                  func createUniqueID() -> String {
                  let uuid: CFUUID = CFUUIDCreate(nil)
                  let cfStr: CFString = CFUUIDCreateString(nil, uuid)

                  let swiftString: String = cfStr as String
                  return swiftString
                  }


                  After getting the this which is unique but changes after the app install and reinstall.
                  Save this id to the Key-Chain on any key let say "uniqueID".



                  To save the key in keyChain :



                     func getDataFromKeyChainFunction() {
                  let uniqueID = KeyChain.createUniqueID()
                  let data = uniqueID.data(using: String.Encoding.utf8)
                  let status = KeyChain.save(key: "uniqueID", data: data!)
                  if let udid = KeyChain.load(key: "uniqueID") {
                  let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                  print(uniqueID!)
                  }
                  }

                  func save(key: String, data: Data) -> OSStatus {
                  let query = [
                  kSecClass as String : kSecClassGenericPassword as String,
                  kSecAttrAccount as String : key,
                  kSecValueData as String : data ] as [String : Any]
                  SecItemDelete(query as CFDictionary)
                  return SecItemAdd(query as CFDictionary, nil)
                  }


                  Next when you required to perform any task based on uniqueID ,first check if any data is saved in Key-Chain on key "uniqueID" .
                  Even if you uninstall the app , the key-chain data is still persisted, it will delete by OS.



                  func checkUniqueID() {
                  if let udid = KeyChain.load(key: "uniqueID") {
                  let uniqueID = String(data: udid, encoding: String.Encoding.utf8)
                  print(uniqueID!)
                  } else {
                  let uniqueID = KeyChain.createUniqueID()
                  let data = uniqueID.data(using: String.Encoding.utf8)
                  let status = KeyChain.save(key: "uniqueID", data: data!)
                  print("status: ", status)
                  }
                  }


                  In this way you can generate the uniqueID once and use this id every time.



                  NOTE: But when you upload next version of your app, upload it with the same Provisioning Profile otherwise you cannot access the key-chain store of your last installed app.
                  Key-Chain Store is associated with the Provisioning profile.



                  Check Here







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 5 '18 at 6:58









                  VIJAY SINGH RAGHAVVIJAY SINGH RAGHAV

                  309




                  309






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51641614%2fhow-to-get-the-realy-fixed-device-id-in-swift%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      MongoDB - Not Authorized To Execute Command

                      in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

                      How to fix TextFormField cause rebuild widget in Flutter