J'ai une API qui renvoie les numéros de téléphone au format: + 1415xxxxxxx (E164)
À l'heure actuelle, ces numéros sont placés dans la cellule d'un UITableView et sont présentés comme prévu. Toutefois, j'aimerais pouvoir rechercher les contacts des utilisateurs sur le téléphone pour voir s'il existe une correspondance - si également renvoyer le prénom , nom et photo connue.
En consultant les pages Apple ( https://developer.Apple.com/library/watchos/documentation/Contacts/Reference/Contacts_Framework/index.html )
import ContactsUI
mais alors je ne suis pas sûr, est-ce que je charge le contactDB dans un dictionnaire puis le recherche? Je peux trouver beaucoup de choses sur la recherche par nom et moins sur la recherche par numéro:
let predicate = CNContact.predicateForContactsMatchingName("Sam")
J'essaie d'obtenir une fonction que je peux appeler, qui effectue une recherche à l'aide du numéro de téléphone et me renvoie le prénom, le nom et l'image.
func searchForContactUsingNumber(PhoneNumber: String)
{
// Search Via phoneNumber
let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingPhoneNumber(PhoneNumber), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey,CNContactImageData])
return FirstName, GivenName,UIImage
}
J'ai l'impression que je vais à ce sujet à l'envers mais je ne suis pas sûr de la voie à suivre. Des idées?
Afin d’obtenir rapidement cet exemple opérationnel, j’ai utilisé les sources d’informations suivantes:
Filtrer les non-chiffres de la chaîne
https://stackoverflow.com/a/32700339/558933
http://www.appcoda.com/ios-contacts-framework/
Le bloc de code ci-dessous inclut le contrôle d'autorisation car je devais le faire fonctionner pour pouvoir tester dans le simulateur. Le code est juste le contrôleur de vue Single-View Apps et vous pouvez connecter une UIButton
dans le Storyboard à la méthode findContactInfoForPhoneNumber:
pour obtenir si exécuter. La sortie est vers la console - vous devrez remplacer ces instructions print
par quelque chose d'autre.
Si le code du contrôleur d'affichage complet ne vous intéresse pas, il suffit de regarder la méthode searchForContactUsingPhoneNumber(phoneNumber: String)
. J'ai suivi les conseils d'Apple dans la documentation pour exécuter le cadre CNContact
de manière asynchrone.
Le code supprime tous les symboles +
, -
et (
qui pourraient se trouver dans un numéro de téléphone et ne font que correspondre aux chiffres, de sorte que le numéro de téléphone pour lequel vous faites correspondre DOIT être exactement le même.
//
// ViewController.Swift
// ContactsTest
//
// Created by Robotic Cat on 13/04/2016.
//
import UIKit
import Contacts
class ViewController: UIViewController {
// MARK: - App Logic
func showMessage(message: String) {
// Create an Alert
let alertController = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.Alert)
// Add an OK button to dismiss
let dismissAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (action) -> Void in
}
alertController.addAction(dismissAction)
// Show the Alert
self.presentViewController(alertController, animated: true, completion: nil)
}
func requestForAccess(completionHandler: (accessGranted: Bool) -> Void) {
// Get authorization
let authorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts)
// Find out what access level we have currently
switch authorizationStatus {
case .Authorized:
completionHandler(accessGranted: true)
case .Denied, .NotDetermined:
CNContactStore().requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (access, accessError) -> Void in
if access {
completionHandler(accessGranted: access)
}
else {
if authorizationStatus == CNAuthorizationStatus.Denied {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
self.showMessage(message)
})
}
}
})
default:
completionHandler(accessGranted: false)
}
}
@IBAction func findContactInfoForPhoneNumber(sender: UIButton) {
self.searchForContactUsingPhoneNumber("(888)555-1212)")
}
func searchForContactUsingPhoneNumber(phoneNumber: String) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), { () -> Void in
self.requestForAccess { (accessGranted) -> Void in
if accessGranted {
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataKey, CNContactPhoneNumbersKey]
var contacts = [CNContact]()
var message: String!
let contactsStore = CNContactStore()
do {
try contactsStore.enumerateContactsWithFetchRequest(CNContactFetchRequest(keysToFetch: keys)) {
(contact, cursor) -> Void in
if (!contact.phoneNumbers.isEmpty) {
let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
for phoneNumber in contact.phoneNumbers {
if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber {
let phoneNumberString = phoneNumberStruct.stringValue
let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
if phoneNumberToCompare == phoneNumberToCompareAgainst {
contacts.append(contact)
}
}
}
}
}
if contacts.count == 0 {
message = "No contacts were found matching the given phone number."
}
}
catch {
message = "Unable to fetch contacts."
}
if message != nil {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.showMessage(message)
})
}
else {
// Success
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// Do someting with the contacts in the main queue, for example
/*
self.delegate.didFetchContacts(contacts) <= which extracts the required info and puts it in a tableview
*/
print(contacts) // Will print all contact info for each contact (multiple line is, for example, there are multiple phone numbers or email addresses)
let contact = contacts[0] // For just the first contact (if two contacts had the same phone number)
print(contact.givenName) // Print the "first" name
print(contact.familyName) // Print the "last" name
if contact.isKeyAvailable(CNContactImageDataKey) {
if let contactImageData = contact.imageData {
print(UIImage(data: contactImageData)) // Print the image set on the contact
}
} else {
// No Image available
}
})
}
}
}
})
}
}
ContactList avec ContactUI Framework avec Tableview personnalisé
import UIKit
class ContactCell: UITableViewCell {
@IBOutlet weak var PersonNameLabel: UILabel!
@IBOutlet weak var PersonMobileNOLabel: UILabel!
@IBOutlet weak var PersonImage: UIImageView!
@IBOutlet weak var PersonEmailLabel: UILabel!
}
ContactViewController
import ContactsUI
class ContactViewController: UIViewController,CNContactPickerDelegate,UITableViewDelegate,UITableViewDataSource{
var objects = [CNContact]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.getContacts()
}
func getContacts() {
let store = CNContactStore()
switch CNContactStore.authorizationStatus(for: .contacts){
case .authorized:
self.retrieveContactsWithStore(store: store)
// This is the method we will create
case .notDetermined:
store.requestAccess(for: .contacts){succeeded, err in
guard err == nil && succeeded else{
return
}
self.retrieveContactsWithStore(store: store)
}
default:
print("Not handled")
}
}
func retrieveContactsWithStore(store: CNContactStore)
{
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey,CNContactImageDataKey, CNContactEmailAddressesKey] as [Any]
let request = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
var cnContacts = [CNContact]()
do {
try store.enumerateContacts(with: request){
(contact, cursor) -> Void in
if (!contact.phoneNumbers.isEmpty) {
}
if contact.isKeyAvailable(CNContactImageDataKey) {
if let contactImageData = contact.imageData {
print(UIImage(data: contactImageData)) // Print the image set on the contact
}
} else {
// No Image available
}
if (!contact.emailAddresses.isEmpty) {
}
cnContacts.append(contact)
self.objects = cnContacts
}
} catch let error {
NSLog("Fetch contact error: \(error)")
}
NSLog(">>>> Contact list:")
for contact in cnContacts {
let fullName = CNContactFormatter.string(from: contact, style: .fullName) ?? "No Name"
NSLog("\(fullName): \(contact.phoneNumbers.description)")
}
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objects.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! ContactCell
let contact = self.objects[indexPath.row]
print("theis my contact arrau \(self.objects.count)")
let formatter = CNContactFormatter()
cell.PersonNameLabel.text = formatter.string(from: contact )
if let actualNumber = contact.phoneNumbers.first?.value as? CNPhoneNumber {
//Get the label of the phone number
//Strip out the stuff you don't need
print(actualNumber.stringValue)
cell.PersonMobileNOLabel.text = actualNumber.stringValue
}
else{
cell.PersonMobileNOLabel.text = "N.A "
}
if let actualEmail = (contact as AnyObject).emailAddresses?.first?.value as String? {
print(actualEmail)
cell.PersonEmailLabel.text = actualEmail
}
else{
cell.PersonEmailLabel.text = "N.A "
}
if let imageData = contact.imageData {
//If so create the image
let userImage = UIImage(data: imageData)
cell.PersonImage.image = userImage;
}
else{
cell.PersonImage.image = UIImage (named: "N.A")
}
return cell
}
}
La méthode correcte consiste à indexer les numéros de téléphone dans votre propre base de données afin de pouvoir rechercher l'identifiant du contact.