Contacts and ContactsUI en Xamarin.iOS
En este artículo se describe cómo trabajar con los nuevos marcos de interfaz de usuario contactos y contactos en una aplicación xamarin.iOS. Estos marcos reemplazan la libreta de direcciones y la interfaz de usuario de la libreta de direcciones existentes que se usaban en versiones anteriores de iOS.
Con la introducción de iOS 9, Apple ha publicado dos nuevos marcos, y , que reemplazan a los marcos de interfaz de usuario de libreta de direcciones y libreta de direcciones ContactsContactsUI existentes usados por iOS 8 y versiones anteriores.
Los dos nuevos marcos de trabajo contienen la siguiente funcionalidad:
Contactos: proporciona acceso a los datos de la lista de contactos del usuario. Dado que la mayoría de las aplicaciones solo requieren acceso de solo lectura, este marco se ha optimizado para el acceso seguro para subprocesos y de solo lectura.
ContactsUI: proporciona elementos de interfaz de usuario de Xamarin.iOS para mostrar, editar, seleccionar y crear contactos en dispositivos iOS.
Importante
Los marcos y existentes que usa iOS 8 (y versiones anteriores) han quedado en desuso en iOS 9 y deben reemplazarse por los nuevos marcos y lo antes posible para cualquier aplicación AddressBookAddressBookUIContactsContactsUI xamarin.iOS existente. Aplicaciones nuevas deben escribirse en los nuevos marcos de trabajo.
En las secciones siguientes, echaremos un vistazo a estos nuevos marcos y a cómo implementarlos en una aplicación xamarin.iOS.
Marco de contactos
Contacts Framework proporciona acceso a Xamarin.iOS a la información de contacto del usuario. Dado que la mayoría de las aplicaciones solo requieren acceso de solo lectura, este marco se ha optimizado para el acceso seguro para subprocesos y de solo lectura.
Objetos de contacto
La clase proporciona acceso seguro para subprocesos y de solo lectura a las propiedades de un contacto, como nombre, dirección CNContact o Teléfono números. CNContact funciones como y contiene varias colecciones de propiedades de solo lectura NSDictionary (como direcciones o números de teléfono):
Para cualquier propiedad que pueda tener varios valores (como dirección de correo electrónico o números de teléfono), se representarán como una matriz de NSLabeledValue objetos. NSLabeledValue es una tupla segura para subprocesos que consta de un conjunto de etiquetas y valores de solo lectura donde la etiqueta define el valor para el usuario (por ejemplo, correo electrónico de inicio o trabajo). El marco contactos proporciona una selección de etiquetas predefinidas (a través de las clases estáticas y ) que puede usar en la aplicación o tiene la opción de definir etiquetas personalizadas para CNLabelKeyCNLabelPhoneNumberKey sus necesidades.
Para cualquier aplicación de Xamarin.iOS que necesite ajustar los valores de un contacto existente (o crear otros nuevos), use la versión de la clase y sus subclases NSMutableContact (como CNMutablePostalAddress ).
Por ejemplo, el código siguiente creará un nuevo contacto y lo agregará a la colección de contactos del usuario:
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Add email addresses
var homeEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@mac.com"));
var workEmail = new CNLabeledValue<NSString>(CNLabelKey.Work, new NSString("john.appleseed@apple.com"));
contact.EmailAddresses = new CNLabeledValue<NSString>[] { homeEmail, workEmail };
// Add phone numbers
var cellPhone = new CNLabeledValue<CNPhoneNumber>(CNLabelPhoneNumberKey.iPhone, new CNPhoneNumber("713-555-1212"));
var workPhone = new CNLabeledValue<CNPhoneNumber>("Work", new CNPhoneNumber("408-555-1212"));
contact.PhoneNumbers = new CNLabeledValue<CNPhoneNumber>[] { cellPhone, workPhone };
// Add work address
var workAddress = new CNMutablePostalAddress()
{
Street = "1 Infinite Loop",
City = "Cupertino",
State = "CA",
PostalCode = "95014"
};
contact.PostalAddresses = new CNLabeledValue<CNPostalAddress>[] { new CNLabeledValue<CNPostalAddress>(CNLabelKey.Work, workAddress) };
// Add birthday
var birthday = new NSDateComponents()
{
Day = 1,
Month = 4,
Year = 1984
};
contact.Birthday = birthday;
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
// Attempt to save changes
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error))
{
Console.WriteLine("New contact saved");
}
else
{
Console.WriteLine("Save error: {0}", error);
}
Si este código se ejecuta en un dispositivo iOS 9, se agregará un nuevo contacto a la colección del usuario. Por ejemplo:
Formato y localización de contactos
El marco de contactos contiene varios objetos y métodos que pueden ayudarle a dar formato y a buscar contenido para mostrarlo al usuario. Por ejemplo, el código siguiente formatearía correctamente un nombre de contactos y una dirección de correo para su presentación:
Console.WriteLine(CNContactFormatter.GetStringFrom(contact, CNContactFormatterStyle.FullName));
Console.WriteLine(CNPostalAddressFormatter.GetStringFrom(workAddress, CNPostalAddressFormatterStyle.MailingAddress));
En el caso de las etiquetas de propiedad que se van a mostrar en la interfaz de usuario de la aplicación, el marco de contacto también tiene métodos para la localización de esas cadenas. De nuevo, esto se basa en la configuración regional actual del dispositivo iOS en el que se ejecuta la aplicación. Por ejemplo:
// Localized properties
Console.WriteLine(CNContact.LocalizeProperty(CNContactOptions.Nickname));
Console.WriteLine(CNLabeledValue<NSString>.LocalizeLabel(CNLabelKey.Home));
Capturar contactos existentes
Mediante el uso de una instancia de la clase , puede capturar información de contacto de la CNContactStore base de datos de contactos del usuario. contiene todos los métodos necesarios para capturar o actualizar contactos CNContactStore y grupos de la base de datos. Dado que estos métodos son sincrónicos, se recomienda ejecutarlos en un subproceso en segundo plano para evitar bloquear la interfaz de usuario.
Mediante el uso de predicados (creados a partir de la clase ), puede filtrar los resultados devueltos al CNContact capturar contactos de la base de datos. Para capturar solo los contactos que contienen la cadena Appleseed , use el código siguiente:
// Create predicate to locate requested contact
var predicate = CNContact.GetPredicateForContacts("Appleseed");
Importante
El marco de contactos no admite predicados genéricos y compuestos.
Por ejemplo, para limitar la captura solo a las propiedades GivenName y FamilyName del contacto, use el código siguiente:
// Define fields to be searched
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName};
Por último, para buscar en la base de datos y devolver los resultados, use el código siguiente:
// Grab matching contacts
var store = new CNContactStore();
NSError error;
var contacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);
Si este código se ejecuta después del ejemplo que creamos en la sección Objeto contacts anterior, devolvería el contacto "John Appleseed" que acaba de crear.
Póngase en contacto con access privacy
Dado que los usuarios finales pueden conceder o denegar el acceso a su información de contacto por aplicación, la primera vez que realice una llamada a , se mostrará un cuadro de diálogo en el que se le pedirá que permita el acceso a la CNContactStore aplicación.
La solicitud de permiso solo se presentará una vez, la primera vez que se ejecute la aplicación y las ejecuciones o llamadas posteriores a usarán el permiso que el usuario seleccionó CNContactStore en ese momento.
Debe diseñar la aplicación para que controle correctamente el usuario que deniega el acceso a su base de datos de contacto.
Capturar contactos parciales
Un contacto parcial es un contacto para el que solo se han obtenido algunas de las propiedades disponibles del almacén de contactos. Si intenta acceder a una propiedad que no se ha capturado previamente, se producirá una excepción.
Puede comprobar fácilmente si un contacto determinado tiene la propiedad deseada mediante los IsKeyAvailableAreKeysAvailable métodos o de la CNContact instancia. Por ejemplo:
// Does the contact contain the requested key?
if (!contact.IsKeyAvailable(CNContactOption.PostalAddresses)) {
// No, re-request to pull required info
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.PostalAddresses};
var store = new CNContactStore();
NSError error;
contact = store.GetUnifiedContact(contact.Identifier, fetchKeys, out error);
}
Importante
Los GetUnifiedContactGetUnifiedContacts métodos y de la CNContactStore clase GetUnifiedContact un contacto parcial limitado a las propiedades solicitadas de las claves de captura proporcionadas.
Contactos unificados
Un usuario puede tener diferentes orígenes de información de contacto para una sola persona en su base de datos de contacto (como iCloud, Facebook o Google Mail). En las aplicaciones iOS y OS X, esta información de contacto se vinculará automáticamente y se mostrará al usuario como un único contacto unificado:
Este contacto unificado es una vista temporal en memoria de la información de contacto del vínculo a la que se le asignará su propio identificador único (que se debe usar para volver a realizar la captura del contacto si es necesario). De forma predeterminada, el marco contactos devolverá un contacto unificado siempre que sea posible.
Crear y actualizar contactos
Como vimos en la sección Objetos de contacto anterior, se usa y una instancia de para crear nuevos contactos que se escriben en la base de datos de contactos del usuario mediante CNMutableContactCNSaveRequest :
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("New contact saved");
} else {
Console.WriteLine("Save error: {0}", error);
}
También se puede usar para almacenar en caché varios cambios de contacto y de grupo en una sola operación CNSaveRequest y procesar por lotes esas modificaciones en CNContactStore .
Para actualizar un contacto no mutable obtenido de una operación de captura, primero debe solicitar una copia mutable que, a continuación, modifique y guarde de nuevo en el almacén de contactos. Por ejemplo:
// Get mutable copy of contact
var mutable = contact.MutableCopy() as CNMutableContact;
var newEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@xamarin.com"));
// Append new email
var emails = new NSObject[mutable.EmailAddresses.Length+1];
mutable.EmailAddresses.CopyTo(emails,0);
emails[mutable.EmailAddresses.Length+1] = newEmail;
mutable.EmailAddresses = emails;
// Update contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.UpdateContact(mutable);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("Contact updated.");
} else {
Console.WriteLine("Update error: {0}", error);
}
Notificaciones de cambio de contacto
Cada vez que se modifica un contacto, el Almacén de contactos envía un elemento al CNContactStoreDidChangeNotification Centro de notificaciones predeterminado. Si ha almacenado en caché o está mostrando actualmente algún contacto, deberá actualizar esos objetos desde el Almacén de contactos ( CNContactStore ).
Contenedores y grupos
Los contactos de un usuario pueden existir localmente en el dispositivo del usuario o como contactos sincronizados con el dispositivo desde una o varias cuentas de servidor (como Facebook o Google). Cada grupo de contactos tiene su propio contenedor y un contacto determinado solo puede existir en un contenedor.
Algunos contenedores permiten que los contactos se ordenen en uno o varios grupos o subgrupos. Este comportamiento depende del almacén de respaldo de un contenedor determinado. Por ejemplo, iCloud solo tiene un contenedor, pero puede tener muchos grupos (pero no subgrupos). Microsoft Exchange por otro lado, no admite grupos, pero puede tener varios contenedores (uno para cada Exchange carpeta).
Marco ContactsUI
En situaciones en las que la aplicación no necesita presentar una interfaz de usuario personalizada, puede usar el marco ContactsUI para presentar elementos de la interfaz de usuario para mostrar, editar, seleccionar y crear contactos en la aplicación xamarin.iOS.
Con los controles integrados de Apple no solo se reduce la cantidad de código que se tiene que crear para admitir contactos en la aplicación xamarin.iOS, sino que se presenta una interfaz coherente a los usuarios de la aplicación.
Controlador de vista del selector de contactos
El controlador de vista del selector de contactos ( ) administra la vista del selector de contactos estándar que permite al usuario seleccionar una propiedad Contact o Contact de la base de datos de CNContactPickerViewController contactos del usuario. El usuario puede seleccionar uno o varios contactos (en función de su uso) y el controlador de vista del selector de contactos no solicita permiso antes de mostrar el selector.
Antes de llamar a la clase , defina las propiedades que el usuario puede seleccionar y definir predicados para controlar la presentación y selección CNContactPickerViewController de Propiedades de contacto.
Use una instancia de la clase que hereda de para responder a la interacción del usuario CNContactPickerDelegate con el selector. Por ejemplo:
using System;
using System.Linq;
using UIKit;
using Foundation;
using Contacts;
using ContactsUI;
namespace iOS9Contacts
{
public class ContactPickerDelegate: CNContactPickerDelegate
{
#region Constructors
public ContactPickerDelegate ()
{
}
public ContactPickerDelegate (IntPtr handle) : base (handle)
{
}
#endregion
#region Override Methods
public override void ContactPickerDidCancel (CNContactPickerViewController picker)
{
Console.WriteLine ("User canceled picker");
}
public override void DidSelectContact (CNContactPickerViewController picker, CNContact contact)
{
Console.WriteLine ("Selected: {0}", contact);
}
public override void DidSelectContactProperty (CNContactPickerViewController picker, CNContactProperty contactProperty)
{
Console.WriteLine ("Selected Property: {0}", contactProperty);
}
#endregion
}
}
Para permitir que el usuario seleccione una dirección de correo electrónico de los contactos de su base de datos, puede usar el código siguiente:
// Create a new picker
var picker = new CNContactPickerViewController();
// Select property to pick
picker.DisplayedPropertyKeys = new NSString[] {CNContactKey.EmailAddresses};
picker.PredicateForEnablingContact = NSPredicate.FromFormat("emailAddresses.@count > 0");
picker.PredicateForSelectionOfContact = NSPredicate.FromFormat("emailAddresses.@count == 1");
// Respond to selection
picker.Delegate = new ContactPickerDelegate();
// Display picker
PresentViewController(picker,true,null);
Controlador de vista de contactos
La clase Contact View Controller ( CNContactViewController ) proporciona un controlador para presentar una vista de contacto estándar al usuario final. La vista Contacto puede mostrar nuevos contactos nuevos, desconocidos o existentes y el tipo debe especificarse antes de que se muestre la vista llamando al constructor estático correcto ( FromNewContact , FromUnknownContact , FromContact ). Por ejemplo:
// Create a new contact view
var view = CNContactViewController.FromContact(contact);
// Display the view
PresentViewController(view, true, null);
Resumen
En este artículo se ha realizado un análisis detallado de cómo trabajar con los marcos de interfaz de usuario contacto y contacto en una aplicación de Xamarin.iOS. En primer lugar, se tratan los distintos tipos de objetos que proporciona el marco de contacto y cómo se usan para crear contactos nuevos o tener acceso a los existentes. También se ha examinado el marco de la interfaz de usuario de contacto para seleccionar los contactos existentes y mostrar la información de contacto.




