In Contact apps there's group like "iCloud", "yahoo", "gmail". In swift, is it possible to fetch contact from gmail source only?
3 Answers
Tested code. Hope it will solve your problem...
func getAppropriateName(for container: CNContainer?) -> String? {
var name = ""
if (container?.name == "Card") || container?.name == nil {
name = "iCloud"
}
else if (container?.name == "Address Book") {
name = "Google"
}
else if (container?.name == "Contacts") {
name = "Yahoo"
}
else {
name = "Facebook"
}
return name
}

- 1,563
- 20
- 28
-
is it really like this that "Address Book" will be always google? who to get gmail for that group – user8462556 Dec 01 '20 at 15:09
-
I wouldn't say that Yahoo or Facebook are safe to declare there, as "Contacts" is also used as a name by Outlook.com containers, and ANYTHING else would show Facebook in this code – Peter Johnson Aug 06 '21 at 11:33
iCloud/yahoo/gmail etc are CNContainer. Gmail/iCloud is of type CNContainerTypeCardDAV. So first you need to fetch all contacts, and then filter the array based on the CNContainerType of that contact. But unfortunately, we cannot identify which CardDav is it, i.e iCloud/Gmail.
Please see more details here: How do we know which CNContainer represents iCloud?
You can achieve this by looking at Contacts framework runtime headers here: https://github.com/JaviSoto/iOS10-Runtime-Headers/tree/master/Frameworks/Contacts.framework
You can call them by performSelector
message. It's a bit messy, but works.
Generally what you have to do is following:
CNContactStore* store = [CNContactStore new];
// fetch accounts that sync contacts with your device (array of CNAccount)
// since CNAccount class isn't available by default, we treat it as NSObject for our puproses
NSArray* accounts = [store performSelector:@selector(accountsMatchingPredicate:error:) withObject:nil withObject:nil];
// you can iterate through this array, I just use first one for this example
NSObject* account = [accounts firstObject];
// get identifier of the account for NSPredicate we use next
NSString* accountId = [account performSelector:@selector(identifier)];
// Display name of the account (aka Yahoo, Gmail etc.)
NSString* accountName = [account performSelector:@selector(_cnui_displayName)];
// NSPredicate that help us to get corresponding CNContainer
NSPredicate* containerPredicate = [[CNContainer class] performSelector:@selector(predicateForContainersInAccountWithIdentifier:) withObject:accountId];
// Fetching CNContainer
CNContainer* container = [[store containersMatchingPredicate:containerPredicate error:nil] firstObject];
After that it's all about general usage of CNContainers. Hope it will help.
PS. It works on iOS 10, for future versions you should check for Contacts.framework runtime changes.
PPS. I didn't check on swift, but should work either.
Sorry for my english. Good luck :)

- 69
- 1
- 9
-
1perform selector is not working for me and its crashing. is there a way to get this done ? – Sunil_Vaishnav Jun 02 '17 at 04:49
-
@Sunil_Vaishnav can you please provide your code that causes the crash? Or you're using the one that I wrote? – NewObjective Jun 13 '17 at 13:03
-
@Sunil_Vaishnav Did either of you figure this out? Is there an updated solution to this? I don't see a lot of posts asking how to identify which CNContainer is being synced to iCloud. – daniel Sep 20 '22 at 07:02