-
因為新app涉及到iOS裝置資訊收集和很多許可權的判斷和限制,所以寫篇文章總結下。
-
IDFA: 廣告標示符,它是由系統儲存著的,iOS6及以後使用。但是如果使用者還原位置與隱私的話這個廣告識別符號就會重新生成(設定程式 -》 通用 -》 還原 -》還原位置與隱私) 。或者使用者更明確的將設定中的廣告還原掉(設定程式 -》 通用-》 關於本機 -》廣告 -》 還原廣告標示符) ,IDFA也會重新生成。而且使用者可以在設定-》隱私 -》廣告裡面限制IDFA獲取,一般使用者都不知道有這個,哈哈,不過還是不能用來做唯一標識的id呦。
#import <AdSupport/ASIdentifierManager.h>
ASIdentifierManager *asIM = [[ASIdentifierManager alloc] init];
NSString *idfa = [asIM.advertisingIdentifier UUIDString];
複製程式碼
- IDFV: iOS6.0及以後使用,是給Vendor標識使用者用的,vendor:賣主,小販。經過測試發現com.test.app1和com.test.app2具有相同的idfv,而如果是com.app1和com.app2則是兩個不同的idfv。準確點說,就是通過BundleID的反轉的前兩部分進行匹配,如果相同就是同一個Vender,共享同一個idfv的值。
NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString];
複製程式碼
-
IMEI,IMSI: IMEI(International Mobile Equipment Identity)是國際移動裝置身份碼的縮寫,國際移動裝備辨識碼,是由15位數字組成的”電子串號”,它與每臺手機一一對應,而且該碼是全世界唯一的。每一部手機在組裝完成後都將被賦予一個全球唯一的一組號碼,這個號碼從生產到交付使用都將被製造生產的廠商所記錄。手機使用者可以在手機中查到自己手機的IMEI碼。 重點來了 !iOS5以後不能再獲取了,但通過私有Api能獲取,這是在網上能查到的。git上的erica的UIDevice擴充套件檔案,以前可用但由於IOKit framework沒有公開,所以也無法使用。就算手動匯入,依舊無法使用,看來獲取IMEI要失敗了,同時失敗的還有IMSI。不過還存在另外一種可能,Stack Overflow上有人提供採用com.apple.coretelephony.Identity.get entitlement方法,but device must be jailbroken;在此附上鍊接,供大家參考:stackoverflow.com/questions/1… 如果實現了,自己拿來玩就行,別上架,這是會被拒掉的。
-
mac地址: 這個好像也不能拿了,拿到的是無效的:
-(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;
}
複製程式碼
- UUID ,獲取唯一識別符號 每次執行都會發生變化,最理想的就是儲存在keychain裡面,以此作為標識使用者裝置的唯一識別符號
CFUUIDRef uuid = CFUUIDCreate(NULL);
assert(uuid != NULL);
CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid);
複製程式碼
之前使用了Git上的一個第三方庫,SSKeychain,將UUID儲存在keychain裡面,每次呼叫先檢查鑰匙串裡面有沒有,有則使用,沒有則寫進去,保證其唯一性,具體使用如下:
CFUUIDRef uuid = CFUUIDCreate(NULL);
assert(uuid != NULL);CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid);
NSString *identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
if (!identifierNumber){
[SSKeychain setPassword: [NSString stringWithFormat:@"%@", uuidStr] forService:@"com.test.app1"account:@"user"];
identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
}
複製程式碼
- 網路狀態判斷
//監聽網路狀態
-(void)elm_networkTypeAsString{
AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
[reachabilityManager startMonitoring];
[reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusUnknown:
{
//未知網路
self.networkType = 1;
}
break;
case AFNetworkReachabilityStatusNotReachable:
{
//無法聯網
self.networkType = 1;
}
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
{
//手機自帶網路
self.networkType = @"蜂窩網路";
}
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
{
//WIFI
self.networkType = @"wifi";
}
}
}];
}
或者:
- (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;
}
}
複製程式碼
- iOS通訊錄許可權 iOS通訊錄許可權有2個api,一個是iOS9之後出的,好處是不需要獲取許可權可以點選聯絡人直接獲取不需要再點選進去選,而且有多選功能。因為我是相容到iOS8,所以我把2個都整合了。
#import <AddressBookUI/ABPeoplePickerNavigationController.h>
#import <AddressBook/ABPerson.h>
#import <AddressBookUI/ABPersonViewController.h>
#import <ContactsUI/ContactsUI.h>
複製程式碼
- 獲取單個聯絡人
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. 建立控制器
CNContactPickerViewController * picker = [CNContactPickerViewController new];
// 2. 設定代理
picker.delegate = self;
// 4. 彈出
[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];
}
}
複製程式碼
- 獲取全部聯絡人
-(void)getAddressBook {
//2. 建立通訊錄
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
//3. 獲取所有聯絡人
CFArrayRef peosons = ABAddressBookCopyArrayOfAllPeople(addressBook);
//4. 遍歷所有聯絡人來獲取資料(姓名和電話)
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;
//5. 獲取單個聯絡人
ABRecordRef person = CFArrayGetValueAtIndex(peosons, i);
//6. 獲取姓名
NSString *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. 獲取電話
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
//7.1 獲取電話的count數
CFIndex phoneCount = ABMultiValueGetCount(phones);
//7.2 遍歷所有電話號碼
for (CFIndex i = 0; i < phoneCount; i++) {
NSString *value = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, i));
// 列印標籤和電話號
if ([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 釋放 CF 物件
CFRelease(phones);
}
//8.1 釋放 CF 物件
CFRelease(peosons);
CFRelease(addressBook);
[self uploadAddressBook];
}
複製程式碼
- 許可權判斷 因為需求需要在某些許可權沒有得到的情況下不能開啟默寫頁面,所以你需要在判斷前讓使用者去點選同意許可權,所以我把這部分程式碼放在了appdelegate中,
-(void)getAbleAddressBock {
[self.locationManager requestWhenInUseAuthorization]; //位置許可權提示的彈起
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
//2. 建立 AddrssBook
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
//3. 沒有授權時就授權
if (status == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
//3.1 判斷是否出錯
if (error) {
CFRelease(addressBook);
return;
}
//3.2 判斷是否授權
if (granted) {
NSLog(@"已經授權");
CFRelease(addressBook);
} else {
NSLog(@"沒有授權");
CFRelease(addressBook);
}
});
}
AVAuthorizationStatus avstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
switch (avstatus) {
case AVAuthorizationStatusNotDetermined:{
// 許可對話沒有出現,發起授權許可
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
//第一次使用者接受
}else{
//使用者拒絕
}
}];
break;
}
case AVAuthorizationStatusAuthorized:{
// 已經開啟授權,可繼續
break;
}
case AVAuthorizationStatusDenied:
case AVAuthorizationStatusRestricted:
// 使用者明確地拒絕授權,或者相機裝置無法訪問
break;
default:
break;
}
}
複製程式碼
- 獲取許可權,並判斷 我這裡的處理是先獲取使用者需要的許可權,如果使用者拒絕了這些許可權,我就用一個陣列收集起來然後頁面展示你這些許可權沒有給,不能繼續使用,點選去設定許可權那裡。
-(void)authorizations {
AVAuthorizationStatus avstatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
self.camera = [KZWAuthorizationModel new];
self.camera.name = @"允許訪問相機";
self.camera.isTure = (avstatus == AVAuthorizationStatusAuthorized)?YES:NO;
CLAuthorizationStatus CLstatus = [CLLocationManager authorizationStatus];
self.location = [KZWAuthorizationModel new];
self.location.name = @"允許訪問地理位置";
self.location.isTure = (CLstatus == kCLAuthorizationStatusAuthorizedWhenInUse)?YES:NO;
self.abadress = [KZWAuthorizationModel new];
self.abadress.name = @"允許訪問通訊錄";
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]];
複製程式碼
- 獲取app版本
+(NSString *)elm_version {
return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
}
複製程式碼
- 獲取系統版本
[UIDevice currentDevice].systemVersion
複製程式碼
參考:http://blog.csdn.net/Sir_Coding/article/details/68943033