Contacts

RSS for tag

Access the user's contacts and format and localize contact information using Contacts.

Posts under Contacts tag

45 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Displaying limited contacts list in UIKit
I have an app that was written in UIKit. It's too large, and it would be much too time consuming at this point to convert it to SwiftUI. I want to incorporate the new limited contacts into this app. The way it's currently written everything works fine except for showing the limited contacts in the contact picker. I have downloaded and gone though the Apple tutorial app but I'm having trouble thinking it through into UIKit. After a couple of hours I decided I need help. I understand I need to pull the contact IDs of the contacts that are in the limited contacts list. Not sure how to do that or how to get it to display in the picker. Any help would be greatly appreciated. func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) { switch CNContactStore.authorizationStatus(for: .contacts) { case .authorized: completionHandler(true) case .denied: showSettingsAlert(completionHandler) case .restricted, .notDetermined: CNContactStore().requestAccess(for: .contacts) { granted, error in if granted { completionHandler(true) } else { DispatchQueue.main.async { [weak self] in self?.showSettingsAlert(completionHandler) } } } // iOS 18 only case .limited: completionHandler(true) @unknown default: break } } // A text field that displays the name of the chosen contact @IBAction func contact_Fld_Tapped(_ sender: TextField_Designable) { sender.resignFirstResponder() // The contact ID that is saved to the Db getTheCurrentContactID() let theAlert = UIAlertController(title: K.Titles.chooseAContact, message: nil, preferredStyle: .actionSheet) // Create a new contact let addContact = UIAlertAction(title: K.Titles.newContact, style: .default) { [weak self] _ in self?.requestAccess { _ in let openContact = CNContact() let vc = CNContactViewController(forNewContact: openContact) vc.delegate = self // this delegate CNContactViewControllerDelegate DispatchQueue.main.async { self?.present(UINavigationController(rootViewController: vc), animated: true) } } } let getContact = UIAlertAction(title: K.Titles.fromContacts, style: .default) { [weak self] _ in self?.requestAccess { _ in self?.contactPicker.delegate = self DispatchQueue.main.async { self?.present(self!.contactPicker, animated: true) } } } let editBtn = UIAlertAction(title: K.Titles.editContact, style: .default) { [weak self] _ in self?.requestAccess { _ in let store = CNContactStore() var vc = CNContactViewController() do { let descriptor = CNContactViewController.descriptorForRequiredKeys() let editContact = try store.unifiedContact(withIdentifier: self!.oldContactID, keysToFetch: [descriptor]) vc = CNContactViewController(for: editContact) } catch { print("Getting contact to edit failed: \(self!.VC_String) \(error)") } vc.delegate = self // delegate for CNContactViewControllerDelegate self?.navigationController?.isNavigationBarHidden = false self?.navigationController?.navigationItem.hidesBackButton = false self?.navigationController?.pushViewController(vc, animated: true) } } let cancel = UIAlertAction(title: K.Titles.cancel, style: .cancel) { _ in } if oldContactID.isEmpty { editBtn.isEnabled = false } theAlert.addAction(getContact) // Select from contacts theAlert.addAction(addContact) // Create new contact theAlert.addAction(editBtn) // Edit this contact theAlert.addAction(cancel) let popOver = theAlert.popoverPresentationController popOver?.sourceView = sender popOver?.sourceRect = sender.bounds popOver?.permittedArrowDirections = .any present(theAlert,animated: true) } func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) { switch CNContactStore.authorizationStatus(for: .contacts) { case .authorized: completionHandler(true) case .denied: showSettingsAlert(completionHandler) case .restricted, .notDetermined: CNContactStore().requestAccess(for: .contacts) { granted, error in if granted { completionHandler(true) } else { DispatchQueue.main.async { [weak self] in self?.showSettingsAlert(completionHandler) } } } // iOS 18 only case .limited: completionHandler(true) @unknown default: break } } // MARK: - Contact Picker Delegate extension AddEdit_Quote_VC: CNContactPickerDelegate { func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { selectedContactID = contact.identifier let company: String = contact.organizationName let companyText = company == "" ? K.Titles.noCompanyName : contact.organizationName contactNameFld_Outlet.text = CNContactFormatter.string(from: contact, style: .fullName)! companyFld_Outlet.text = companyText save_Array[0] = K.AppFacing.true_App setSaveBtn_AEQuote() } } extension AddEdit_Quote_VC: CNContactViewControllerDelegate { func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool { return false } func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) { selectedContactID = contact?.identifier ?? "" if selectedContactID != "" { let company: String = contact?.organizationName ?? "" let companyText = company == "" ? K.Titles.noCompanyName : contact!.organizationName contactNameFld_Outlet.text = CNContactFormatter.string(from: contact!, style: .fullName) companyFld_Outlet.text = companyText getTheCurrentContactID() if selectedContactID != oldContactID { save_Array[0] = K.AppFacing.true_App setSaveBtn_AEQuote() } } dismiss(animated: true, completion: nil) } }
0
0
117
2d
Using ContactAccessButton freezes the entire app
When using both the ContactsAccessButton demo project, as well as when implementing it in my own, the whole app freezes after entering a few characters and searching through contacts. I don't know if this is necessarily reproducable because it's probably related to the contacts in my contact book. Typing in "Lex" does not freeze the app, but typing in "Adam No" freezes it. I get the following console error before my app freezes and I'm forced to force quit it: #ContactsButton Failed to get service proxy: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service with pid 3387 named com.apple.ContactsUI.ContactsButtonXPCService" UserInfo={NSDebugDescription=connection to service with pid 3387 named com.apple.ContactsUI.ContactsButtonXPCService} #ContactsButton Failed to get remote content: nil (got this a number of times ContactsAccessButton really doesn't seem production ready...
1
1
134
1w
Request .full contacts authorization after being granted .limited
We're adjusting to the new iOS 18 .limited contacts access mode. In our app, we don't request contacts right away. We have a search bar where users can search through their own contacts and select one using the ContactAccessButton. If they do select one, then they're prompted to "Grant Limited Access", not "Grant Full Access", as the screenshot shows below. Later on, we want to offer the ability for users to sync their entire contact book with our app. This will improve their experience on the app by automatically finding all their friends already on the app, without them having to do the manual work of clicking on every single contact in the ContactsAccessPicker. Is this possible right now? It doesn't seem like it—when I call ContactsStore.requestAccess(for: .contacts) while in .limited access mode, nothing happens. But I would like to show a prompt that gives the user the ability to grant all their contacts to improve their experience.
1
0
147
4d
Contact Prodvider Extension key 'com.apple.contact.provider.extension' not accepting in Testflight submission
ERROR ITMS-90349: "Invalid Info.plist value. The value of the EXExtensionPointldentifier key, com.apple.contact.provider.extension, in the Info.plist of "MainApp.app/Extensions/ContactProviderExtension.appex" is invalid. We were working on new iOS18 Contacts Provider extension and when try to test the feature in testflight we were unable to submit the build and getting the above error. The extensionPointldentifier 'com.apple.contact.provider.extension' was auto generated by xcode and apple doc mentioned the same value to use for Contacts Provider extension support. But it is not accepting in testflight. https://developer.apple.com/documentation/contactprovider/contactproviderextension Any help will be appreciated.
0
1
354
3w
iOS 18 recent update
I updated to the newest version of iOS 18 Beta this morning. One feature I preferred on the previous version was that when you're going into the call screen, you had to press the small phone icon rather than the persons name, to make the call. It stopped me accidentally calling people a lot of the time.. This feature seems to have gone on the newest version, or is that a bug? Essentially, the little (i) icon become a phone icon, and you used that to call, rather than the main contact name box.
0
1
247
Aug ’24
ContactAccessButton and ContactAccessPicker issues
We are trying to adopt the new iOS18 ContactAccessButton and ContactAccessPicker in our app and we are facing below issues and requirements in UI and functionality. is there a way to optionally hide the ContactAccessButton UI when there is no matching results ?. The search button in the ContactAccessButton UI is not working when showing no matches and browse contacts. The console showing below error #ContactsButton response after touch -- Should not show UI #ContactsButton: match for callback was unexpectedly nil? The ContactAccessPicker view and contact selection view opened from ContactAccessButton - view results are not presented properly. The presented view not fully covered the presenting screen and blank screen appears in edges Cancel button in ContactAccessPicker UI when list shown is not working.
4
2
272
3w
Contact Provider Extension "enumerateContent" Method Called Multiple Times
I'm facing an issue with the enumerateContent method in my Contact Provider extension. The method is being called multiple times before I call the first observer.didEnumerate.. Here's a sample of my code: class TestContactProviderRootContainerEnumerator : ContactItemEnumerator { let handler = TestContactProviderUsecaseHandler() func configure(for domain: ContactProviderDomain) { log.error("---> configure") } func enumerateContent(in page: ContactItemPage, for observer: ContactItemContentObserver) { let requestPage = getPageIndex(from: page.offset, pageSize: observer.suggestedPageSize) log.error("---> Begin Enumerate Content page=\(requestPage) pageSize =\(observer.suggestedPageSize)") func completion(items: [ContactItem], hasMore: Bool) { observer.didEnumerate(items) do { let generationMarker = try getGenerationMarker(page: page) if hasMore { let nextPage = ContactItemPage(generationMarker: generationMarker, offset: page.offset + items.count) log.error("---> nextPage set offset \(page.offset + items.count) nextPage: \(getPageIndex(from: page.offset + items.count, pageSize: observer.suggestedPageSize))") observer.didFinishEnumeratingPage(upTo: nextPage) }else { observer.didFinishEnumeratingContent(upTo: generationMarker) } }catch { observer.didFinishEnumeratingContentWithError(error) return } } log.error("---> Start Request page=\(requestPage) pageSize =\(observer.suggestedPageSize)") handler.requestForRecordsList(page: requestPage, perPage: observer.suggestedPageSize, sortBy: Field.Contact.lastName, modifiedSince: nil, completion: { contactItems, hasMore, error in log.error("---> Finish Request page=\(requestPage) pageSize =\(observer.suggestedPageSize)") if let error { log.error("---> Error: \(error)") observer.didFinishEnumeratingContentWithError(error) return } completion(items: contactItems, hasMore: hasMore) log.error("---> End Enumerate Content page=\(requestPage) pageSize =\(observer.suggestedPageSize)") }) } } Below are the logs that I'm seeing: ---> configure ---> Begin Enumerate Content page=1 pageSize =20 ---> Start Request page=1 pageSize =20 ---> Begin Enumerate Content page=1 pageSize =20 ---> Begin Enumerate Content page=1 pageSize =20 ---> Begin Enumerate Content page=1 pageSize =20 ....10+times ---> Begin Enumerate Content page=1 pageSize =20 ---> Finish Request page=1 pageSize =20 ---> Begin Enumerate Content page=1 pageSize =20​​ ​---> nextPage set offset 20 nextPage: 2​​ ​---> Begin Enumerate Content page=1 pageSize =20 ---> Begin Enumerate Content page=1 pageSize =20​ ​---> Begin Enumerate Content page=2 pageSize =20 ---> Begin Enumerate Content page=2 pageSize =20​ ​---> Start Request page=2 pageSize =20​ ​---> Begin Enumerate Content page=2 pageSize =20 ---> Begin Enumerate Content page=2 pageSize =20​ ​....10+times ---> Begin Enumerate Content page=2 pageSize =20 ---> Begin Enumerate Content page=2 pageSize =20 Has anyone else experienced this issue? Any ideas on why this is happening or how to fix it.
2
0
268
Aug ’24
Its not possible to use a Contact Provider Extension from within a Notification Service Extension
A Notification Service Extension is one of the more capable extensions, and there's a lot that can be done within it (for example, it can invoke a Call Extension). However its not possible to use a Contact Provider Extension within it. If a CPE has been enabled by the main app, then if a push is sent to the NSE, then within the NSE the ContactProviderManager class reports that the CPE is disabled and its not possible to anything with it. For example a call to ContactProviderManager.signalEnumerator() will hang and not complete. I was hoping to create a contact and make it available to the system on receipt of a push, but this isn't going to possible. Is this intentional and by design, or just due to the immaturity of this feature/iOS beta? The documentation of a Contact provider Extension says: "signalEnumerator() An example of using this call is to handle a push notification to your app when the provided contacts from your server update" It therefore seems strange that the main cited use case for ContactProviderManager.signalEnumerator() isn't actually possible if the push is delivered to an extension rather than the app.
3
0
398
Aug ’24
How does an app manage its own contacts?
In the documentation for the Contact Provider Extension contact provider it says Use the Contact Provider framework if your app manages its own contacts and wants to make them available in other apps that use the Contacts framework. But how does an app manage its own contacts? What needs to be done differently if it manages its own contacts versus managing a user's contacts? Does the user still need to grant contacts access for example? Is there a special group/domain that should be used (how) to add app contacts? There's no mention of any of this that I can see in the documentation for CNContact or CNContactStore.
4
0
331
Jul ’24
Refreshing Contact Provider Extension from NSE
Hi, While testing the new Contact Provider Extension in the iOS 18 betas I noticed that the Notification Service Extension is unable to connect to the CPE in order to trigger a refresh. The ContactProviderManager init throws an "Extension Not Found" error. The CPE documentation mentions a main use case of using notifications to trigger CPE updates: "An example of using this call is to handle a push notification to your app when the provided contacts from your server update." source Is the main app the only way to trigger a CPE update? The documentation does not specify this limitation. I have tested this on a physical iPhone 15 running iOS 18 beta 4. Thanks, Wes
4
1
365
Aug ’24
imageData property of CNContact
After setting the imageData property of CNContact through the API, I can see in the address book that the contact's avatar has been set to the imageData image, But when my phone version is iOS 17.1.0, when this contact calls in and locks the screen, I can see that this image is displayed in full screen, But when my phone version is iOS 17.5.1, when this contact calls in, the screen is locked and the image can only be displayed on the avatar, with a blurred image in the background, After iOS 17, contacts can set their avatars and posters separately in their contact list. How can I set these two images through code, just like setting the imageData property of CNContact through API. I see that there is a parameter in the CNContact property called _fullscreenImageData, but there is no value inside, and I am unable to obtain data for this parameter. I don't know how to manipulate this data in order to achieve the effect of setting up posters in the iOS 17.5.1 system.
2
0
253
Jul ’24
imageData property of CNContact
After setting the imageData property of CNContact through the API, I can see in the address book that the contact's avatar has been set to the imageData image, But when my phone version is iOS 17.1.0, when this contact calls in and locks the screen, I can see that this image is displayed in full screen, But when my phone version is iOS 17.5.1, when this contact calls in, the screen is locked and the image can only be displayed on the avatar, with a blurred image in the background, After iOS 17, contacts can set their avatars and posters separately in their contact list. How can I set these two images through code, just like setting the imageData property of CNContact through API. I see that there is a parameter in the CNContact property called _fullscreenImageData, but there is no value inside, and I am unable to obtain data for this parameter. I don't know how to manipulate this data in order to achieve the effect of setting up posters in the iOS 17.5.1 system.
1
0
245
Jul ’24
Get notified on 'Selected Contacts' updates
Is there a way for the application to get notified when user updates their 'Selected Contacts' from the Settings app when the Contacts permission on the application is set to the new iOS 18 CNAuthorizationStatusLimited status? My logic already listens for the CNContactStoreDidChangeNotification notification, but it doesn't look like it is being fired under this scenario. Do we have to setup a new CNChangeHistoryFetchRequest every time the application becomes active and compare the result? Is the value of the currentHistoryToken updated when user selects / deselects entries from their 'Selected Contacts'?
2
0
388
Jul ’24
iOS 18 Beta 2 XCTest: Unable to record and play contacts permission system dialog
Unable to record and play the new contacts permission system dialog. App: https://developer.apple.com/documentation/contacts/accessing-a-person-s-contact-data-using-contacts-and-contactsui func handleContactsAccessAlert() { let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowButton = springboard.buttons["Allow Full Access"] allowButton.tap() let access6ContactsButton = springboard.alerts["Allow full access to 6 contacts?"].scrollViews.otherElements.buttons["Allow"] access6ContactsButton.tap() } func handleContactsPermissionAlert() { let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowButton = springboard.buttons["Continue"] if allowButton.exists { allowButton.tap() sleep(5) handleContactsAccessAlert() } } func testContactPermissions() { let app = XCUIApplication() app.launch() app.buttons["Request Access"].tap() sleep(5) handleContactsPermissionAlert() sleep(5) app.collectionViews/*@START_MENU_TOKEN@*/.staticTexts["Kate Bell"]/*[[".cells.staticTexts[\"Kate Bell\"]",".staticTexts[\"Kate Bell\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap() }
3
1
492
2w
Issue with iPhone QR Code Contact Preview Displaying Email Instead of Organization
Post Content: Hi everyone, I’m encountering an issue with how iPhone displays contact information from a vCard QR code in the contact preview. When I scan the QR code with my iPhone camera, the contact preview shows the email address between the name and the contact image, instead of displaying the organization name. Here’s the structure of the vCard I’m using: BEGIN:VCARD VERSION:3.0 FN:Ahmad Rana N:Rana;Ahmad;;; ORG:Company 3 TEL;TYPE=voice,msg:+1234567890 EMAIL:a(at the rate)gmail.com URL:https://example.com IMPP:facebook:fb END:VCARD What I Expect: When I scan it with camera and in the contact preview before creating the camera I want organization name between name and image of the preview but I get email instead of ogrganization name. If only organisation is passed then it displays correctly but when I pass email it displayed email in between. Steps I’ve Taken: Verified the vCard structure to ensure it follows the standard format. Reordered the fields in the vCard to prioritize the organization name and job title. Tested with a simplified vCard containing only the name, organization, and email. Despite these efforts, the email address continues to be displayed in the contact preview between the name and the contact image, while the organization name is not shown as expected. Question: How can I ensure that the organization name is displayed correctly in the contact preview on iPhone when scanning a QR code? Are there specific rules or best practices for field prioritization in vCards that I might be missing? I would appreciate any insights or suggestions on how to resolve this issue. Thank you!
2
0
459
Jul ’24
iOS18 Contacts bug report
Dear developers, I am experiencing a bug with Contacts on my iPhone13 since downloading the beta. Some names in the listing of contacts do not correspond with their card once opened in the Contacts app. The option to share contacts in 3rd party apps has disappeared. Noticed specifically in WhatsApp where my contacts are no longer synced and no longer show against numbers. Best regards
1
0
383
Jul ’24
CNContact instantMessage field duplicates after serializaiton/deserialization
Hello folks, I stumbled upon a weird CNContact serialization problem. I use the Contacts framework to update the AIM field, which is one of the instantMessageAddresses within a single Contact. Here is the simplified code I used: func updateAIMFieldOn(contact: CNContact, aimValue: String) { do { guard let mutableContact = contact.mutableCopy() as? CNMutableContact else { logger.error("[CM] Couldn't update contact with aim \(aimValue)") return } var updatedAddresses = mutableContact.instantMessageAddresses updatedAddresses.append(CNLabeledValue(label: "", value: CNInstantMessageAddress(username: aimValue, service: CNInstantMessageServiceAIM))) mutableContact.instantMessageAddresses = updatedAddresses let saveRequest = CNSaveRequest() saveRequest.update(mutableContact) try CNContactStore().execute(saveRequest) logger.verbose("Contact's AIM updated successfully!") } catch { logger.error("Couldn't update contact") } } And after serializing the contact to data, and then deserializing, the contact got two AIM fields with the same value: X-AIM;type=pref:some:part:of_my_aim_value IMPP;X-SERVICE-TYPE=AIM;type=pref:some:part:of_my_aim_value Why does it work in this manner? Is it possible that ":" char causes that? Format of my aim username is {some:part:of_my_aim_value}. I didn't find any information in the docs. Thanks!
0
0
439
Jun ’24