• Because the new app involves the collection of iOS device information and the judgment and restriction of many permissions, I will write an article to summarize.

  • IDFA: AD identifier, which is stored by the system for iOS6 and later. However, the AD identifier will be regenerated if the user restores location and privacy (Settings – “General” – “Restore -” Restore Location and Privacy). Or if the user explicitly restores the AD in the Settings (Settings program – “General -” about local – “Advertising -” restore the AD identifier), the IDFA will also be regenerated. And users can set – “privacy -” advertising to limit IDFA access, general users do not know there is this, ha ha, but still can not be used to make a unique id yo.

#import <AdSupport/ASIdentifierManager.h>
ASIdentifierManager *asIM = [[ASIdentifierManager alloc] init];
NSString *idfa = [asIM.advertisingIdentifier UUIDString];
Copy the code
  • IDFV: for iOS6.0 and later, it is used to identify the user of Vendor. App1 and com.test.app2 have the same IDFV, while com.app1 and com.app2 are two different IDFVs. To be precise, it is matched by the first two parts of the inversion of the BundleID. If the same, it is the same Vender, sharing the same IDFV value.
NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString];
Copy the code
  • IMEI, IMSI: International Mobile Equipment Identity (IMEI) is the abbreviation of International Mobile Equipment Identity (IMEI). It is an electronic serial number consisting of 15 digits. It corresponds to each Mobile phone and is unique in the world. Once assembled, each phone will be assigned a globally unique set of numbers, which will be recorded by the manufacturer from production to delivery. Mobile phone users can check their mobile phone’s IMEI code. Here we go! IOS5 is no longer accessible, but it’s accessible through a private Api, which is available on the web. Erica’s UIDevice extension on Git, previously available but not available because the IOKit Framework is not publicly available. Even if manually imported, it still cannot be used. It seems that obtaining IMEI will fail, as well as IMSI. But there is another possibility, someone with a com on Stack Overflow. Apple. Coretelephony. Identity. Get entitlement method, but the device must be jailbroken. In the attached link, for your reference: stackoverflow.com/questions/1… If it happens, just play it yourself, don’t put it on the shelf, it will be rejected.

  • MAC address:

-(NSString *)macAddress {
    int mib[6];
    size_t len;
    char *buf;
    unsigned char *ptr;
    struct if_msghdr *ifm;
    struct sockaddr_dl *sdl;
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    if ((mib[5] = if_nametoindex("en0")) = = 0) {printf("Error: if_nametoindex error\n");
        return NULL;
    }
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error! \n");
        return NULL;
    }
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        free(buf);
        return NULL;
    }
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *macStr = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",*ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    return macStr;
}
Copy the code
  • UUID: The obtained unique identifier changes every time it is run. Ideally, it is stored in the keychain as a unique identifier to identify the user device
CFUUIDRef uuid = CFUUIDCreate(NULL); assert(uuid ! = NULL); CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid);Copy the code

Before, I used a third-party library on Git, SSKeychain, to store the UUID in the keychain, and check whether there is a key string in each call. If there is, it will be used, and if there is not, it will be written in to ensure its uniqueness. Specific usage is as follows:

CFUUIDRef uuid = CFUUIDCreate(NULL); assert(uuid ! = NULL); CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid); NSString *identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
if(! identifierNumber){ [SSKeychainsetPassword: [NSString stringWithFormat:@"% @", uuidStr] forService:@"com.test.app1"account:@"user"];
identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
}
Copy the code
  • Network state judgment
/ / to monitor network status - (void) elm_networkTypeAsString {AFNetworkReachabilityManager * reachabilityManager = [AFNetworkReachabilityManager sharedManager]; [reachabilityManager startMonitoring]; [reachabilityManagersetReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            caseAFNetworkReachabilityStatusUnknown: {/ / self.net unknown workType = 1; }break;
            caseAFNetworkReachabilityStatusNotReachable: {/ / cannot be connected to the Internet self.net workType = 1; }break;
            caseAFNetworkReachabilityStatusReachableViaWWAN: {/ / cell phones bring network workType = @ self.net"Cellular network";
            }
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
            {
                //WIFI
                self.networkType = @"wifi"; }}}]; } or: - (void) networkingStatesFromStatebar {UIApplication * app = [UIApplication sharedApplication]; NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
    int type = 0;
    for (id child in children) {
        if ([child isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
            type = [[child valueForKeyPath:@"dataNetworkType"] intValue];
        }
    }
    switch (type) {
        case 0:
            self.networkType = 1;
            break;
            
        case 1:
            self.networkType = 2;
            break;
            
        case 2:
            self.networkType = 3;
            break;
            
        case 3:
            self.networkType = 4;
            break;
            
        case 4:
            self.networkType = 4;
            break;
            
        case 5:
            self.networkType = 5;
            break;
            
        default:
            break; }}Copy the code
  • IOS Address book permissions iOS address book permissions have two apis, one is released after iOS9, the advantage is that you don’t need to obtain permissions, you can click on the contact to directly obtain, you don’t need to click in to select, and you can select multiple functions. Since I’m compatible with iOS8, I’ve integrated both.
#import <AddressBookUI/ABPeoplePickerNavigationController.h>
#import <AddressBook/ABPerson.h>
#import <AddressBookUI/ABPersonViewController.h>
#import <ContactsUI/ContactsUI.h>
Copy the code
  • Obtaining a Contact
if ([[UIDevice currentDevice].systemVersion integerValue] > 8) {
            [self showcontactsUI];
        }else {
            [self showPeople];
        }
-(void)showPeople{
    ABPeoplePickerNavigationController *nav = [[ABPeoplePickerNavigationController alloc] init];
    nav.peoplePickerDelegate = self;
    nav.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false]; [self presentViewController:nav animated:YES completion:nil]; } -(void)showcontactsUI { // 1. Create a controller CNContactPickerViewController * picker = [CNContactPickerViewController new]; // 2. Set picker.delegate = self; // 4. Popup [self presentViewController: picker Animated :YES completion:nil]; } -(void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact { CNLabeledValue *labeledValue = contact.phoneNumbers[0]; CNPhoneNumber *phoneNumber = labeledValue.value; NSString *phoneNO = phoneNumber.stringValue; phoneNO = [phoneNO stringByReplacingOccurrencesOfString:@"-" withString:@""];
    NSString *name = [CNContactFormatter stringFromContact:contact style:CNContactFormatterStyleFullName];
    UITableViewCell *cell = [self.personTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:self.contactIndexPath.section]];
    cell.detailTextLabel.textColor = [UIColor colorWithHexString:FontColor333333];
    cell.detailTextLabel.text = phoneNO;
    if (self.contactIndexPath.section == 0) {
        self.firstModel.phone = phoneNO;
        self.firstModel.isEmergencyContact = YES;
        self.firstModel.tookTime = 0;
        self.nameTextFieldone.text = name;
        self.firstModel.contactName = name;
    }else if(self.contactIndexPath.section == 1){
        self.secendModel.phone =phoneNO;
        self.secendModel.isEmergencyContact = YES;
        self.secendModel.tookTime = 0;
        self.nameTextFieldtwo.text = name;
        self.secendModel.contactName = name;
    }
}
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
    [peoplePicker dismissViewControllerAnimated:YES completion:nil];
}
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
    ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
    
    long index = ABMultiValueGetIndexForIdentifier(phone,identifier);
    NSString *phoneNO = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phone, index);
    
    if ([phoneNO hasPrefix:@"+"]) {
        phoneNO = [phoneNO substringFromIndex:3];
    }
    
    phoneNO = [phoneNO stringByReplacingOccurrencesOfString:@"-" withString:@""];
    
    NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
    
    if (phone ) {
        UITableViewCell *cell = [self.personTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:self.contactIndexPath.section]];
        cell.detailTextLabel.textColor = [UIColor colorWithHexString:FontColor333333];
        cell.detailTextLabel.text = phoneNO;
        [peoplePicker dismissViewControllerAnimated:YES completion:nil];
    }
    
    if (self.contactIndexPath.section == 0) {
        self.firstModel.phone = phoneNO;
        self.firstModel.isEmergencyContact = YES;
        self.firstModel.tookTime = 0;
        self.nameTextFieldone.text = [NSString stringWithFormat:@"% @ % @", firstName, lastName];
        self.firstModel.contactName = [NSString stringWithFormat:@"% @ % @", firstName, lastName];
    }else if(self.contactIndexPath.section == 1){
        self.secendModel.phone = phoneNO;
        self.secendModel.isEmergencyContact = YES;
        self.secendModel.tookTime = 0;
        self.nameTextFieldtwo.text = [NSString stringWithFormat:@"% @ % @", firstName, lastName];
        self.secendModel.contactName = [NSString stringWithFormat:@"% @ % @", firstName, lastName]; }}Copy the code
  • Obtain all Contacts
- (void) getAddressBook {/ / 2. Create a directory ABAddressBookRef addressBook = ABAddressBookCreateWithOptions (NULL, NULL); / / 3. Get all the contacts CFArrayRef peosons = ABAddressBookCopyArrayOfAllPeople (addressBook); CFIndex count = CFArrayGetCount(Peosons);for (CFIndex i = 0 ; i < count; i++) {
        KZWConactPersonModel *personModel = [KZWConactPersonModel new];
        personModel.isEmergencyContact = NO;
        personModel.type = @"OTHER";
        personModel.source = @"TELEPHONE_BOOK"; personModel.tookTime = [[NSDate date] timeIntervalSince1970] - self.startTime; ABRecordRef person = CFArrayGetValueAtIndex(Peosons, I); / / 6. Get name nsstrings * lastName = CFBridgingRelease (ABRecordCopyValue (person, kABPersonLastNameProperty)); NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));if(lastName && ! firstName) { personModel.contactName = [NSString stringWithFormat:@"% @", lastName];
        }else if(firstName && ! lastName) { personModel.contactName = [NSString stringWithFormat:@"% @", firstName];
        }else if (firstName && lastName) {
            personModel.contactName = [NSString stringWithFormat:@"% @ % @", firstName,lastName]; } //7. Get phone ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty); //7.1 Obtaining the count of a Phone CFIndex phoneCount = ABMultiValueGetCount(phone); 7.2 Iterate over All phone numbersfor(CFIndex i = 0; i < phoneCount; i++) { NSString *value = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, i)); // Print labels and phone numbersif ([value hasPrefix:@"+"]) {
                value = [value substringFromIndex:3];
            }
            
            value = [value stringByReplacingOccurrencesOfString:@"-" withString:@""];
            personModel.phone = value;
            if(! firstName && ! lastName) { personModel.contactName = value; } [self.personArray addObject:personModel]; } //8.1 Release CFRelease(phone); } //8.1 Release the CF object CFRelease(Peosons); CFRelease(addressBook); [self uploadAddressBook]; }Copy the code
  • Because of the requirement that you can’t open the silent page if certain permissions are not obtained, you need to ask the user to click agree permissions before you decide, so I put this part of the code in the AppDelegate,
-(void)getAbleAddressBock { [self.locationManager requestWhenInUseAuthorization]; / / location permissions prompt pop-up ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus (); / / 2. Create AddrssBook ABAddressBookRef addressBook = ABAddressBookCreateWithOptions (NULL, NULL); //3. Authorize when there is no authorizationif(status == kABAuthorizationStatusNotDetermined) { ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {//3.1 Determine whether an error occursif (error) {
                CFRelease(addressBook);
                return; } //3.2 Check whether authorization is grantedif (granted) {
                NSLog(@"Authorized");
                CFRelease(addressBook);
            } else {
                NSLog(@"No authorization."); CFRelease(addressBook); }}); } AVAuthorizationStatus avstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; switch (avstatus) {caseAVAuthorizationStatusNotDetermined: {/ / licensing dialog does not appear, A licensing [AVCaptureDevice requestAccessForMediaType: AVMediaTypeVideo completionHandler: ^ (BOOL granted) {if(granted) {// First user accepted}else{// user rejected}}];break;
        }
        caseAVAuthorizationStatusAuthorized: {/ / has open authorization, can continuebreak;
        }
        case AVAuthorizationStatusDenied:
        caseAVAuthorizationStatusRestricted: / / the user explicitly refused to authorize, or camera device cannot be accessedbreak;
        default:
            break; }}Copy the code
  • Get permissions, and say what I’m doing here is I’m getting the permissions that the user wants, and if the user rejects those permissions, I’m going to collect them in an array and then the page says you’re not given those permissions, you can’t use them anymore, so click set permissions.
-(void)authorizations {
    AVAuthorizationStatus avstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    self.camera = [KZWAuthorizationModel new];
    self.camera.name = @"Allow access to camera"; self.camera.isTure = (avstatus == AVAuthorizationStatusAuthorized)? YES:NO; CLAuthorizationStatus CLstatus = [CLLocationManager authorizationStatus]; self.location = [KZWAuthorizationModel new]; self.location.name = @"Allow access to geographic location"; self.location.isTure = (CLstatus == kCLAuthorizationStatusAuthorizedWhenInUse)? YES:NO; self.abadress = [KZWAuthorizationModel new]; self.abadress.name = @"Allow access to address book"; self.abadress.isTure = (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)? YES:NO;if(avstatus ! = AVAuthorizationStatusAuthorized || CLstatus ! = kCLAuthorizationStatusAuthorizedWhenInUse || ABAddressBookGetAuthorizationStatus() ! = kABAuthorizationStatusAuthorized) { [self.authorizationsArray removeAllObjects]; [self.authorizationsArray addObject:self.camera]; [self.authorizationsArray addObject:self.location]; [self.authorizationsArray addObject:self.abadress]; [self showAuthorizationView:self.authorizationsArray]; }else {
       todo
    }
}
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
Copy the code
  • Get the APP version
+(NSString *)elm_version {
  return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
}
Copy the code
  • Obtaining the System Version
[UIDevice currentDevice].systemVersion 
Copy the code

Reference: http://blog.csdn.net/Sir_Coding/article/details/68943033