IOS 7.0
Apple once again ruthlessly banned MAC addresses in IOS 7, and all of the MAC addresses that were acquired using the previous method became 02:00:00:00:00:00. There are problems in the total solution ah, so look around for information, and finally have the idea whether you can use Keychain to save the unique identifier obtained, so that even if the app is deleted and then loaded back, you can also read back from the keychain. After having the direction to do, look at the official documents about keychain, see the official use of Keychain demo, probably spent an afternoon time, the problem finally solved.
Ii. Introduction of Keychain
We engage in iOS development, must know OS X inside the keychain (keychain), usually to township and debugging, all have to install certificates and the like, these certificates are stored in keychain, and we usually browse the page records of the account password is also recorded in the keychain. Keychain in iOS is simpler than OS X, and the whole system has only one keychain, and each program can record data in keychain, and can only read the data recorded in keychain by its own program. The Security.framework framework in iOS provides four main ways to manipulate keychain:
Query Osstatus secitemcopymatching (cfdictionaryref query, Cftyperef *result);//Add Osstatus Secitemadd (CFDictionaryRef attributes, Cftyperef *result);//update Itemosstatus secitemupdate in keychain (cfdictionaryref query, Cfdictionaryref attributestoupdate)//delete Itemosstatus Secitemdelete in keychain (cfdictionaryref query)
These four method parameters are more complex, once the error will cause the Operation keychain failure, this piece of documentation described in more detail, you can check the official documents Keychain Services Reference.
As mentioned earlier that each app only allows access to the data it records in keychain, is there no other way to access the data that exists in other apps keychain?
Apple provides a way to allow multiple apps from the same sender to access each app, specifying Accessgroup, which is the Access group, when Secitemadd adds data. An app can belong to a colleague belonging to multiple groupings, and adding a Keychain data access group requires two things:
A. Set the code Signing entitlements inside the app Target's bulibsetting and point to the plist file that contains the grouping information for the Aceessgroup. The file must be in the same directory as the project file, I add access to the group because of the Plist file location problem, operation Keychain failure, it took a long time to find the problem.
b, create a new Keychainaccessgroups.plist file in the project directory, the topmost node in the structure of the file must be an array named "Keychain-access-groups", And each item in the array is a nsstring that describes the grouping. There are also requirements for the format of string: "appidentifier.com.***", where Appidentifier is the first part of your signature.
C, in the code to add data to keychain, set Ksecattraccessgroup, the code is as follows:
NSString *accessgroup = [NSString stringwithutf8string: "APPIdentifier.com.cnblogs.smileEvday"]; if (accessgroup! = nil) {#if target_iphone_simulator //Ignore The Access group if running on the IPHONE SIMULATOR . //Apps that is built for the simulator aren ' t signed, so there ' s no Keychain Access group //For the Simulato R to check. This means, all apps can see all keychain items if run //on the simulator. //If a Secitem contains an Access group attribute, Secitemadd and secitemupdate on the //simulator would retur n-25243 (Errsecnoaccessforitem). #else [Dictforquery setobject:accessgroup forkey: (ID) ksecattraccessgroup];# endif }
This code is directly copied from the official demo, according to the note we can see that the simulator is not supported Accessgroup, so it is only a precompiled macro to add selectively.
Third, use Keychain to save and obtain Udid
Said so much finally get to the point, how to get the Udid on iOS 7. The second part of the knowledge we put into the direct application can easily achieve the effect we want, we first look at how to add the obtained Identifierforvendor to the code in the keychain.
+ (BOOL) Settudidtokeychain: (nsstring*) udid{nsmutabledictionary *dictforadd = [[Nsmutabledictionary alloc] init]; [Dictforadd SetValue: (ID) Ksecclassgenericpassword Forkey: (ID) ksecclass]; [Dictforadd setvalue:[nsstring Stringwithutf8string:kkeychainudiditemidentifier] forKey:kSecAttrDescription]; [Dictforadd setvalue:@ "UUID" Forkey: (ID) ksecattrgeneric]; Default attributes for keychain item. [Dictforadd setobject:@ "" Forkey: (ID) ksecattraccount]; [Dictforadd setobject:@ "" Forkey: (ID) Ksecattrlabel]; The Keychain Access group attribute determines if this item can be shared//amongst multiple apps whose code signin g entitlements contain the same Keychain Access group. NSString *accessgroup = [NSString Stringwithutf8string:kkeychainudidaccessgroup]; if (accessgroup! = nil) {#if target_iphone_simulator//Ignore The Access group if running on the IPHONE Simulat Or. Apps that is built for the simulator aren ' tSigned, so there's no Keychain Access group//for the simulator to check. This means, all apps can see all keychain items if run//on the simulator. If A Secitem contains an Access group attribute, Secitemadd and secitemupdate on the//simulator would return-25243 (Errsecnoaccessforitem). #else [Dictforadd setobject:accessgroup forkey: (ID) ksecattraccessgroup]; #end if} const char *udidstr = [Udid utf8string]; NSData *keychainitemvalue = [NSData datawithbytes:udidstr Length:strlen (UDIDSTR)]; [Dictforadd setvalue:keychainitemvalue Forkey: (ID) ksecvaluedata]; Osstatus writeerr = NOERR; if ([Svudidtools Getudidfromkeychain]) {//There is item in keychain [Svudidtools Updateudidinkeychain:udid ]; [Dictforadd release]; return YES; } else {//Add item to Keychain Writeerr = Secitemadd ((cfdictionaryref) Dictforadd, NULL); if (writeerr! = errsecsuccess) { NSLog (@ "ADD KeyChain Item Error!!! Error code:%ld ", Writeerr); [Dictforadd release]; return NO; } else {NSLog (@ "ADD KeyChain Item Success!!!"); [Dictforadd release]; return YES; }} [Dictforadd release]; return NO;}
In the above code, first build a dictionary to add to the data in the keychain, including some basic keychain item data type, description, Access grouping and the most important data and other information, Finally, the UUID we need to save is saved to keychain by calling the Secitemadd method.
The code for obtaining the corresponding data in keychain is as follows:
+ (nsstring*) getudidfromkeychain{nsmutabledictionary *dictforquery = [[Nsmutabledictionary alloc] init]; [Dictforquery SetValue: (ID) Ksecclassgenericpassword Forkey: (ID) ksecclass]; Set Attr Description for query [Dictforquery setvalue:[nsstring Stringwithutf8string:kkeychainudiditemidentifier] Forkey:ksecattrdescription]; Set Attr Identity for query NSData *keychainitemid = [NSData datawithbytes:kkeychainudiditemidentifier Length:strlen (Kkeychainudiditemidentifier)]; [Dictforquery setobject:keychainitemid Forkey: (ID) ksecattrgeneric]; The Keychain Access group attribute determines if this item can be shared//amongst multiple apps whose code signin g entitlements contain the same Keychain Access group. NSString *accessgroup = [NSString Stringwithutf8string:kkeychainudidaccessgroup]; if (accessgroup! = nil) {#if target_iphone_simulator//Ignore the Access Group IF running on the IPhone simulator. Apps that is built for the simulator aren ' t signed, so there ' s no Keychain Access group//For the SI Mulator to check. This means, all apps can see all keychain items if run//on the simulator. If A Secitem contains an Access group attribute, Secitemadd and secitemupdate on the//simulator would return-25243 (Errsecnoaccessforitem). #else [Dictforquery setobject:accessgroup forkey: (ID) ksecattraccessgroup]; #e NDIF} [Dictforquery SetValue: (ID) kcfbooleantrue Forkey: (ID) ksecmatchcaseinsensitive]; [Dictforquery SetValue: (ID) ksecmatchlimitone Forkey: (ID) ksecmatchlimit]; [Dictforquery SetValue: (ID) kcfbooleantrue Forkey: (ID) ksecreturndata]; Osstatus queryerr = NOERR; NSData *udidvalue = nil; NSString *udid = nil; Queryerr = secitemcopymatching ((cfdictionaryref) Dictforquery, (cftyperef*) &udidvalue); Nsmutabledictionary *dict = nil; [Dictforquery SetValue: (ID) kcfbooleantrue Forkey: (ID) ksecreturnattributes]; Queryerr = secitemcopymatching ((cfdictionaryref) Dictforquery, (cftyperef*) &dict); if (Queryerr = = Errsecitemnotfound) {NSLog (@ "KeyChain Item:%@ not Found!!!", [NSString STRINGWITHUTF8STRING:KKEYC Hainudiditemidentifier]); } else if (queryerr! = errsecsuccess) {NSLog (@ "KeyChain Item query Error!!! Error code:%ld ", Queryerr); } if (Queryerr = = errsecsuccess) {NSLog (@ "KeyChain Item:%@", udidvalue); if (udidvalue) {udid = [nsstring stringWithUTF8String:udidValue.bytes]; }} [Dictforquery release]; return udid;}
The process of the above code is similar, first create a dictionary, which sets the search criteria, and then through the Secitemcopymatching method to get to our previous saved to keychain data.
Iv. Summary
This article describes a workaround that allows the same udid information to be obtained after the app is deleted using keychain.
You may have questions about whether you can still get the UDID data that was previously recorded if the system is upgraded?
The answer is yes, I did the test specifically. Even if we remove the program, the system after upgrading and then installed back, still can get to the same udid. But when we restore the entire system to the previous record of the Udid, this point I think it should not, but the phone is too much data, no test, if you are interested in testing, to verify my guess.
Full code Address: Https://github.com/smileEvday/SvUDID
If you want to be in a real running, you need to replace two places:
The first place is the Appidentifier in Accessgroup in the plist file.
The second place is the appidentifier of the SVUDIDTOOLS.M in Kkeychainudidaccessgroup appidentity for the profile you are using.
[Transfer from: http://blog.sina.com.cn/s/blog_6f9200bd0101faz4.html]