最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - How to Determine if a Contact is Stored in iCloud, Google, or Another Account in Swift? - Stack Overflow

programmeradmin6浏览0评论

I am using CNContactStore to fetch contacts from an iOS device. While retrieving contacts, I want to check whether each contact is stored in iCloud, Google, Yahoo, or another account. However, I am only getting generic container names like "Card" or "Address Book" instead of the actual account names.

Here is my current code:

func fetchContacts(completion: @escaping ([ContactModel]) -> Void) {
    let store = CNContactStore()
    
    DispatchQueue.global(qos: .userInitiated).async {
        let keys: [CNKeyDescriptor] = [
            CNContactIdentifierKey as CNKeyDescriptor,
            CNContactGivenNameKey as CNKeyDescriptor,
            CNContactFamilyNameKey as CNKeyDescriptor,
            CNContactPhoneNumbersKey as CNKeyDescriptor
        ]
        
        var contacts = [ContactModel]()
        
        do {
            // Fetch all containers (iCloud, Google, Outlook, etc.)
            let containers = try store.containers(matching: nil)
            
            for container in containers {
                let request = CNContactFetchRequest(keysToFetch: keys)
                request.predicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
                
                try store.enumerateContacts(with: request) { (contact, _) in
                    let fullName = "\(contact.givenName) \(contact.familyName)"
                    let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue }
                    
                    // Checking container type
                    print("Container Name: \(container.name), Type: \(container.type.rawValue)")

                    // Attempting to map account type
                    let accountName: String
                    switch container.type {
                    case .cardDAV:
                        accountName = container.name.contains("iCloud") ? "iCloud" : "Google/Yahoo (CardDAV)"
                    case .exchange:
                        accountName = "Outlook/Exchange"
                    case .local:
                        accountName = "Device Contacts"
                    default:
                        accountName = container.name
                    }
                    
                    let contactModel = ContactModel(contact: contact, accountName: accountName)
                    contacts.append(contactModel)
                }
            }
            
            DispatchQueue.main.async {
                completion(contacts)
            }
        } catch {
            print("Failed to fetch contacts: \(error)")
        }
    }
}

Using CNContainer.name → Returns "Card" or "Address Book", not "iCloud", "Google", etc.

How can I accurately determine whether a contact belongs to iCloud, Google, Yahoo, or another account?

I am using CNContactStore to fetch contacts from an iOS device. While retrieving contacts, I want to check whether each contact is stored in iCloud, Google, Yahoo, or another account. However, I am only getting generic container names like "Card" or "Address Book" instead of the actual account names.

Here is my current code:

func fetchContacts(completion: @escaping ([ContactModel]) -> Void) {
    let store = CNContactStore()
    
    DispatchQueue.global(qos: .userInitiated).async {
        let keys: [CNKeyDescriptor] = [
            CNContactIdentifierKey as CNKeyDescriptor,
            CNContactGivenNameKey as CNKeyDescriptor,
            CNContactFamilyNameKey as CNKeyDescriptor,
            CNContactPhoneNumbersKey as CNKeyDescriptor
        ]
        
        var contacts = [ContactModel]()
        
        do {
            // Fetch all containers (iCloud, Google, Outlook, etc.)
            let containers = try store.containers(matching: nil)
            
            for container in containers {
                let request = CNContactFetchRequest(keysToFetch: keys)
                request.predicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
                
                try store.enumerateContacts(with: request) { (contact, _) in
                    let fullName = "\(contact.givenName) \(contact.familyName)"
                    let phoneNumbers = contact.phoneNumbers.map { $0.value.stringValue }
                    
                    // Checking container type
                    print("Container Name: \(container.name), Type: \(container.type.rawValue)")

                    // Attempting to map account type
                    let accountName: String
                    switch container.type {
                    case .cardDAV:
                        accountName = container.name.contains("iCloud") ? "iCloud" : "Google/Yahoo (CardDAV)"
                    case .exchange:
                        accountName = "Outlook/Exchange"
                    case .local:
                        accountName = "Device Contacts"
                    default:
                        accountName = container.name
                    }
                    
                    let contactModel = ContactModel(contact: contact, accountName: accountName)
                    contacts.append(contactModel)
                }
            }
            
            DispatchQueue.main.async {
                completion(contacts)
            }
        } catch {
            print("Failed to fetch contacts: \(error)")
        }
    }
}

Using CNContainer.name → Returns "Card" or "Address Book", not "iCloud", "Google", etc.

How can I accurately determine whether a contact belongs to iCloud, Google, Yahoo, or another account?

Share Improve this question edited Feb 27 at 13:13 Kiryl Famin 33310 bronze badges asked Feb 27 at 10:26 Codebane the SwiftbreakerCodebane the Swiftbreaker 871 silver badge8 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

As already discussed here, the Contacts framework does not provide information as to whether a particular container corresponds to iCloud, Google, Yahoo. The only additional info you can get is using CNContainer.type:

CNContainerType.cardDAV: Typically used for iCloud, Google, Yahoo contacts. However, distinguishing between Google and Yahoo requires additional logic.

CNContainerType.exchange: Used for Outlook/Exchange contacts.

CNContainerType.local: Used for "On My iPhone" contacts.

in Container object which we fetch we got this properties externalIdentifier=/carddav/v1/principals/garejakirit%40gmail/lists/default/

externalModificationTag="6bae89da88eb93cc.701"

externalSyncTag=https://www.googleapis/carddav/v1/synctoken/0802100118E4A18AF598E68B03220C08A4A886BE0610D8E2FA8701

so using externalIdentifier we can get gmail or any other email and if iCloud than a 64 letter unique code

and using this externalSyncTag we can get source if google than we got google api and if any other than that api so that's how we can determine the source of contact i did like this but is there any better way to do that please discuss here

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论