之前的项目兼容的版本在iOS9.0以上,所以在项目中使用了CNContacts框架获取用户的通讯录信息,大致的实现如下:

/// 判断字符串是否可用
/// 辅助函数
/// @param str 原始对象
BOOL isAvailableString(NSString *str) {if ([str isKindOfClass:[NSNull class]]) {return false;}if (!str || !str.length) {return false;}return true;
}/// 查看通讯录访问权限
void getAuthrization(void(^_Nonnull result)(BOOL granted)) {CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:(CNEntityTypeContacts)];if (authorizationStatus == CNAuthorizationStatusNotDetermined) {CNContactStore *contactStore = [[CNContactStore alloc] init];[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {if (result) {result(granted);}}];} else if (authorizationStatus == CNAuthorizationStatusAuthorized){if (result) {result(true);}} else {if (result) {result(true);}}
}/// 获取通讯录信息
/// @param result 结果回调
- (void)getAllContacts:(void(^)(NSArray *))result {getAuthrization(^(BOOL granted){if (granted) {CNContactStore *contactStore = [[CNContactStore alloc] init];CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactMiddleNameKey, CNContactNoteKey]];NSError *error = nil;__block NSMutableArray <NSDictionary<NSString *, NSString *> *> *allContacts = @[].mutableCopy;[contactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {NSString *familyName = contact.familyName;familyName = isAvailableString(familyName) ? familyName : @"";NSString *middleName = contact.middleName;middleName = isAvailableString(middleName) ? middleName : @"";NSString *givenName = contact.givenName;givenName = isAvailableString(givenName) ? givenName : @"";NSString *note = contact.note;note = isAvailableString(note) ? note : @"";NSString *fullName = [NSString stringWithFormat:@"%@%@%@", familyName, middleName, givenName];if (isAvailableString(fullName)) {[allContacts addObject:@{@"fullName" : fullName, @"note" : note}];}}];if (result) {result(allContacts);}}});
}

一直相安无事,正常运行.直到某一天早上突然发现,预警系统相当一部分用户的所有的联系人信息一夜之间全部为空,一脸懵逼.

其实在早前的发布大会上,已经说明了要对要用户通讯录隐私数据的使用权限做限制,尤其是"备注"信息,可能会涉及到用户的个人私密数据,例如银行卡密码,亲密人物关系等,所以在iOS13.x上使用用户通讯录数据时就需要注意.

在iOS 13.x 上获取用户的通讯录数据时,不能获取 "备注" 信息,否则会系统会抛出异常,从而导致获取信息失败.在获取的方法中,修改一下实现来查看一下是否有异常发生:

/// 获取通讯录信息
/// @param result 结果回调
- (void)getAllContacts:(void(^)(NSArray *))result {getAuthrization(^(BOOL granted){if (granted) {CNContactStore *contactStore = [[CNContactStore alloc] init];CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactMiddleNameKey, CNContactNoteKey]];NSError *error = nil;__block NSMutableArray <NSDictionary<NSString *, NSString *> *> *allContacts = @[].mutableCopy;BOOL fetchSuccess = [contactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {NSString *familyName = contact.familyName;familyName = isAvailableString(familyName) ? familyName : @"";NSString *middleName = contact.middleName;middleName = isAvailableString(middleName) ? middleName : @"";NSString *givenName = contact.givenName;givenName = isAvailableString(givenName) ? givenName : @"";NSString *note = contact.note;note = isAvailableString(note) ? note : @"";NSString *fullName = [NSString stringWithFormat:@"%@%@%@", familyName, middleName, givenName];if (isAvailableString(fullName)) {[allContacts addObject:@{@"fullName" : fullName, @"note" : note}];}}];if (!fetchSuccess || error) {NSLog(@"fetchSuccess : %@", fetchSuccess ? @"成功" : @"失败");NSLog(@"error : %@", error);}if (result) {result(allContacts);}}});
}

再次运行,输出信息果然是异常的:

 fetchSuccess : 失败error : Error Domain=CNErrorDomain Code=102 "(null)" UserInfo={CNKeyPaths=(note
), CNInvalidRecords=("<CNContactFetchRequest: 0x281ac7030: predicate=(null), keysToFetch=(\n    familyName,\n    givenName,\n    middleName,\n    note\n), unifyResults=1, sortOrder=0>"
)}

然后在CNErrorDomain定义中找到了关于Code=102的说明:

CONTACTS_EXTERN NSString * const CNErrorDomain NS_AVAILABLE(10_11, 9_0);typedef NS_ENUM(NSInteger, CNErrorCode)
{CNErrorCodeCommunicationError = 1,CNErrorCodeDataAccessError = 2,CNErrorCodeAuthorizationDenied = 100,CNErrorCodeNoAccessableWritableContainers NS_ENUM_AVAILABLE(10_13_3, 11_3) = 101,CNErrorCodeUnauthorizedKeys API_AVAILABLE(macos(10.14), ios(13.0), watchos(6.0)) = 102,CNErrorCodeFeatureDisabledByUser API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0)) = 103,CNErrorCodeRecordDoesNotExist = 200,CNErrorCodeInsertedRecordAlreadyExists = 201,CNErrorCodeContainmentCycle = 202,CNErrorCodeContainmentScope = 203,CNErrorCodeParentRecordDoesNotExist = 204,CNErrorCodeRecordIdentifierInvalid = 205,CNErrorCodeRecordNotWritable API_AVAILABLE(macos(10.14), ios(13.0), watchos(6.0)) = 206,CNErrorCodeParentContainerNotWritable API_AVAILABLE(macos(10.14), ios(13.0), watchos(6.0)) = 207,CNErrorCodeValidationMultipleErrors = 300,CNErrorCodeValidationTypeMismatch = 301,CNErrorCodeValidationConfigurationError = 302,CNErrorCodePredicateInvalid = 400,CNErrorCodePolicyViolation = 500,CNErrorCodeClientIdentifierInvalid = 600,CNErrorCodeClientIdentifierDoesNotExist = 601,CNErrorCodeClientIdentifierCollision = 602,CNErrorCodeChangeHistoryExpired = 603,CNErrorCodeChangeHistoryInvalidAnchor = 604,CNErrorCodeVCardMalformed NS_ENUM_AVAILABLE(10_13, 11_0) = 700,CNErrorCodeVCardSummarizationError NS_ENUM_AVAILABLE(10_14, 12_0) = 701,}  NS_ENUM_AVAILABLE(10_11, 9_0);

发现CNErrorCodeUnauthorizedKeys = 102是获取了未授权的属性key.由此真相大白,苹果爸爸不再授权获取note属性了.那么我是不是只要在CNContactFetchRequest初始化时,不加入CNContactNoteKey就可以了,大不了在访问时获取不到数据就完事了?

CNContactStore *contactStore = [[CNContactStore alloc] init];
CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactMiddleNameKey, /*CNContactNoteKey*/]];

再次运行,结果

Ignored Exception: A property was not requested when contact was fetched.
(0   CoreFoundation                      0x00000001a2f49c44 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 12565161   libobjc.A.dylib                     0x00000001a2c640c8 objc_exception_throw + 602   CoreFoundation                      0x00000001a2e393ac 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 1402043   Contacts                            0x00000001aa321d18 75694259-6C2D-34A1-828B-E0A506C23F35 + 8184564   ContactsDemo                        0x0000000100a91528 __33-[ViewController getAllContacts:]_block_invoke.83 + 4125   Contacts                            0x00000001aa2c0434 75694259-6C2D-34A1-828B-E0A506C23F35 + 4188686   Contacts                            0x00000001aa2f5a08 75694259-6C2D-34A1-828B-E0A506C23F35 + 6374487   CoreFoundation                      0x00000001a2f1b7c4 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 10669488   CoreFoundation                      0x00000001a2e19424 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 92529   Contacts                            0x00000001aa2f5914 75694259-6C2D-34A1-828B-E0A506C23F35 + 63720410  ContactsFoundation                  0x00000001ac8ac78c CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17806011  ContactsFoundation                  0x00000001ac8e4b24 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 40835612  ContactsFoundation                  0x00000001ac8e4b24 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 40835613  ContactsFoundation                  0x00000001ac8e4b24 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 40835614  ContactsFoundation                  0x00000001ac8e4b24 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 40835615  ContactsFoundation                  0x00000001ac8e4b24 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 40835616  Contacts                            0x00000001aa2881f8 75694259-6C2D-34A1-828B-E0A506C23F35 + 18892017  Contacts                            0x00000001aa2888b8 75694259-6C2D-34A1-828B-E0A506C23F35 + 19064818  Contacts                            0x00000001aa289024 75694259-6C2D-34A1-828B-E0A506C23F35 + 19254819  CoreFoundation                      0x00000001a2f50724 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 128387620  CoreFoundation                      0x00000001a2e19280 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 883221  Foundation                          0x00000001a34489cc 672CF0CB-4951-3B91-89DF-55E953AEA00F + 241095622  Foundation                          0x00000001a3211088 672CF0CB-4951-3B91-89DF-55E953AEA00F + 8615223  Foundation                          0x00000001a3449d04 672CF0CB-4951-3B91-89DF-55E953AEA00F + 241587624  Foundation                          0x00000001a32102d4 672CF0CB-4951-3B91-89DF-55E953AEA00F + 8264425  Foundation                          0x00000001a321e0ac 672CF0CB-4951-3B91-89DF-55E953AEA00F + 13943626  Foundation                          0x00000001a3450f44 672CF0CB-4951-3B91-89DF-55E953AEA00F + 244512427  Contacts                            0x00000001aa288c78 75694259-6C2D-34A1-828B-E0A506C23F35 + 19160828  Contacts                            0x00000001aa288738 75694259-6C2D-34A1-828B-E0A506C23F35 + 19026429  Contacts                            0x00000001aa288060 75694259-6C2D-34A1-828B-E0A506C23F35 + 18851230  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454431  ContactsFoundation                  0x00000001ac8abb08 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17485632  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454433  ContactsFoundation                  0x00000001ac8ab800 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17408034  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454435  ContactsFoundation                  0x00000001ac8ab800 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17408036  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454437  ContactsFoundation                  0x00000001ac8abb08 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17485638  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454439  ContactsFoundation                  0x00000001ac8ab45c CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17314840  ContactsFoundation                  0x00000001ac8c6780 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 28454441  ContactsFoundation                  0x00000001ac8ac638 CAD1A4FE-E7C1-3980-8391-9E6E7CA88370 + 17772042  Contacts                            0x00000001aa2f55d4 75694259-6C2D-34A1-828B-E0A506C23F35 + 63637243  Contacts                            0x00000001aa3584d0 75694259-6C2D-34A1-828B-E0A506C23F35 + 104161644  libsystem_trace.dylib               0x00000001a2b27d30 os_activity_apply_f + 8845  Contacts                            0x00000001aa358438 75694259-6C2D-34A1-828B-E0A506C23F35 + 104146446  Contacts                            0x00000001aa2f52a4 75694259-6C2D-34A1-828B-E0A506C23F35 + 63555647  Contacts                            0x00000001aa2c0320 75694259-6C2D-34A1-828B-E0A506C23F35 + 41859248  ContactsDemo                        0x0000000100a91180 __33-[ViewController getAllContacts:]_block_invoke + 48049  ContactsDemo                        0x0000000100a90dbc getAuthrization + 34050  ContactsDemo                        0x0000000100a90f7c -[ViewController getAllContacts:] + 12051  ContactsDemo                        0x0000000100a917f0 -[ViewController tableView:didSelectRowAtIndexPath:] + 10452  UIKitCore                           0x00000001a71b04c0 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1258822453  UIKitCore                           0x00000001a71afff8 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1258700054  UIKitCore                           0x00000001a71b06e0 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1258876855  UIKitCore                           0x00000001a6fe9078 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1072344856  UIKitCore                           0x00000001a6fd876c 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1065559657  UIKitCore                           0x00000001a70099a0 55D60569-DBB7-3BC9-8A97-DCAC95C64D4B + 1085686458  CoreFoundation                      0x00000001a2ec467c 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 71026859  CoreFoundation                      0x00000001a2ebf31c 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 68892460  CoreFoundation                      0x00000001a2ebf8cc 97285ACB-7B21-393A-ABF6-03F1DBB5D2A2 + 69038061  CoreFoundation                      0x00000001a2ebf098 CFRunLoopRunSpecific + 48062  GraphicsServices                    0x00000001ad029534 GSEventRunModal + 10863  UIKitCore                           0x00000001a6fdf7ac UIApplicationMain + 194064  ContactsDemo                        0x0000000100a92cb8 main + 12465  libdyld.dylib                       0x00000001a2d3ef30 0DC9A4BA-C3E8-3487-99DB-1B5C86597AF5 + 3888
)

尴尬....就连之前设定的日志

if (!fetchSuccess || error) {NSLog(@"fetchSuccess : %@", fetchSuccess ? @"成功" : @"失败");NSLog(@"error : %@", error);}

都没有打印,但是通过断点,那就说明fetchSuccess返回了成功,同时error为空,这种隐藏的异常是最难发现的.通过设置断点发现获取的遍历方法还是执行了的.为啥会这样呢,我们使用异常捕获来查看一下:

               @try {NSString *familyName = contact.familyName;familyName = isAvailableString(familyName) ? familyName : @"";NSString *middleName = contact.middleName;middleName = isAvailableString(middleName) ? middleName : @"";NSString *givenName = contact.givenName;givenName = isAvailableString(givenName) ? givenName : @"";NSString *note = contact.note;note = isAvailableString(note) ? note : @"";NSString *fullName = [NSString stringWithFormat:@"%@%@%@", familyName, middleName, givenName];if (isAvailableString(fullName)) {[allContacts addObject:@{@"fullName" : fullName, @"note" : note}];}} @catch (NSException *exception) {NSLog(@"exception == %@", exception);} @finally {}

然后发现:

exception == A property was not requested when contact was fetched.
exception == A property was not requested when contact was fetched.
...

所以,既然苹果粑粑不让用,在正常情况下就不要试图去申请,也不要视图去获取,因为你粑粑终究是你粑粑,如果非要不听话,那就要准备好背锅.然后删掉

contact.note

调用,代码正常运行.

最后我们可以在此处添加异常检测代码,以防止以后此处再次发生改动时可以及时找到原因.

- (void)getAllContacts:(void(^)(NSArray *))result {getAuthrization(^(BOOL granted){if (granted) {CNContactStore *contactStore = [[CNContactStore alloc] init];CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactMiddleNameKey, /*CNContactNoteKey*/]];NSError *error = nil;__block NSMutableArray <NSDictionary<NSString *, NSString *> *> *allContacts = @[].mutableCopy;BOOL fetchSuccess = [contactStore enumerateContactsWithFetchRequest:fetchRequest error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {@try {NSString *familyName = contact.familyName;familyName = isAvailableString(familyName) ? familyName : @"";NSString *middleName = contact.middleName;middleName = isAvailableString(middleName) ? middleName : @"";NSString *givenName = contact.givenName;givenName = isAvailableString(givenName) ? givenName : @"";NSString *note = /*contact.note*/@"";note = isAvailableString(note) ? note : @"";NSString *fullName = [NSString stringWithFormat:@"%@%@%@", familyName, middleName, givenName];if (isAvailableString(fullName)) {[allContacts addObject:@{@"fullName" : fullName, @"note" : note}];}} @catch (NSException *exception) {NSLog(@"exception == %@", exception);//添加异常检测[WEDExceptionManager sendExcetion:@"ContactEnumerateException" description:exception.description];} @finally {}}];if (!fetchSuccess || error) {//添加异常检测[WEDExceptionManager sendExcetion:@"ContactEnumerateException" description:error ? error.description : @"" ];}if (result) {result(allContacts);}}});
}

iOS 13.x获取通讯录信息时的注意事项相关推荐

  1. ios 简书 获取通讯录信息_iOS 13获取用户通讯录需要注意的

    获取通讯录还有一个最大的变化,就是iOS9以后 访问通讯录属性,要事先设置好,否则会奔溃, 下面是列表 // 姓名前缀 CNContactNamePrefixKey // 名 CNContactGiv ...

  2. ios 简书 获取通讯录信息_当心!你用的共享充电宝可能被植入木马盗取信息

    出门在外,你的焦虑感是否会随着手机电量的降低而同步提高呢?乘车.支付.娱乐.联系都离不开手机,一旦没了电简直要丢掉半条命.这个时候遍布大街小巷的共享充电宝简直成了救命稻草.然而在你放心使用共享充电宝时 ...

  3. ios 简书 获取通讯录信息_iOS9以后获取手机通讯录

    一.iOS 9 以前的通讯录框架 AddressBookUI框架:提供了联系人列表界面.联系人详情界面.添加联系人界面等,一般用于选择联系人. AddressBook 框架:纯 C 语言的 API,仅 ...

  4. ios 简书 获取通讯录信息_ios 各种权限整理

    联网权限 引入头文件 @import CoreTelephony; 应用启动后,检测应用中是否有联网权限 CTCellularData *cellularData = [[CTCellularData ...

  5. ios 简书 获取通讯录信息_iOS-授权获取通讯录

    - (void)getContact{ CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusF ...

  6. ios通过app读取通讯录信息

    iOS通过app读取通讯录信息,读取通讯录信息时需要加载AddressBookUI 和AddressBook两个包,并且引入头文件 #import <AddressBook/AddressBoo ...

  7. 【微信公众号开发】获取用户信息时,有时成功获取,有时提示“invalid openid hint”

    原因:保存openid的session在某个方法里被重新赋新值了.所以一旦调用了这个方法,再去获取用户信息时,就会报错.

  8. Android获取通讯录信息

    Android获取通讯录信息 欢迎关注本人网站:rytter的私人博客网站 权限申请 自Android6.0以后,Android权限申请全部要求为动态申请(注:通讯录权限为危险权限),权限申请方法如下 ...

  9. iOS开发编码规范与审核时的注意事项

    iOS开发编码规范与审核时的注意事项 一. 编码的排版格式 1 代码的缩进应使用空格(SPACE),不能使用制表符(TAB),并且缩进以2个字符为单位. 2 空格的使用 a) 关键字与其后的表达式之间 ...

最新文章

  1. CF853 (Div.1) A Planning(贪心)
  2. ⑤Windows Server 8 RemoteFX体验
  3. vue1与vue2的路由 以及vue2项目大概了解
  4. 2.2 逻辑回归-机器学习笔记-斯坦福吴恩达教授
  5. String字符串中获取所有匹配结果的索引值
  6. spring security config
  7. 制作 Windows8   to Go
  8. mysql 分组查出来横向展示_实战MySql查询
  9. Java刷新Jpanel_java – 刷新JPanel
  10. (11) python 使用baostock获取历史A股K线数据
  11. 耿楠《LaTeX 中文教程》随堂学习记录
  12. 软件工程__CMMCMMI
  13. safari浏览器关于时间日期格式的兼容问题
  14. 蓝牙、wifi、3G/4G、lora技术的对比
  15. cannot find -l****问题的解决办法
  16. 青岛科技大学计算机一级报名,2019年3月山东青岛科技大学计算机等级考试报名通知...
  17. macbook 如何稳定的使用第三方鼠标
  18. 串行通信基础、串行数据传输方式
  19. 她只用一个方法,就把英语拿下了!
  20. mysql生产cdm文件_PowerDesigner生成CDM模型

热门文章

  1. 达人评测 华为MatePad2和华为MatePad2 Pro 怎么样
  2. HP3777打印机一行清晰一行不清晰
  3. 总结:IOTA反驳DCI实验室提出的漏洞荒谬至极
  4. 如何实现数据库的读写分离
  5. python提取cad坐标_教你一个CAD坐标提取的小技巧
  6. OpenJudge-005雇佣兵(解析)
  7. android微信登录的app签名 和 项目正式签名替换默认签名
  8. Callnovo如何因小见大,高端定制——“快乐的音符跳动在异国他乡”篇
  9. android横屏分辨率,android适配不同分辨率hdpi、mdpi、ldpi横屏竖屏
  10. 在云计算行业内有什么证书比较有名?受市场认可大?