Kontakte und KontakteUI in Xamarin.iOS

In diesem Artikel wird die Arbeit mit den neuen Benutzeroberflächenframeworks für Kontakte und Kontakte in einer Xamarin.iOS-App behandelt. Diese Frameworks ersetzen die vorhandene Benutzeroberfläche für Adressbuch und Adressbuch, die in früheren Versionen von iOS verwendet wurden.

Mit der Einführung von iOS 9 hat Apple zwei neue Frameworks und ContactsUIveröffentlicht, Contacts die die vorhandenen Frameworks für adressbuch- und adressbuchbenutzeroberfläche ersetzen, die von iOS 8 und früher verwendet werden.

Die beiden neuen Frameworks enthalten die folgenden Funktionen:

  • Kontakte : Bietet Zugriff auf die Kontaktlistendaten des Benutzers. Da die meisten Apps nur schreibgeschützten Zugriff erfordern, wurde dieses Framework für threadsicheren, schreibgeschützten Zugriff optimiert.

  • ContactsUI : Stellt Xamarin.iOS-Ui-Elemente zum Anzeigen, Bearbeiten, Auswählen und Erstellen von Kontakten auf iOS-Geräten bereit.

Beispiel für ein Kontaktblatt auf einem iOS-Gerät

Wichtig

Die vorhandenen AddressBook Frameworks und AddressBookUI , die von iOS 8 (und früher) verwendet werden, sind in iOS 9 veraltet und sollten so bald wie möglich für jede vorhandene Xamarin.iOS-App durch die neuen Contacts Frameworks und ContactsUI ersetzt werden. Neue Apps sollten für die neuen Frameworks geschrieben werden.

In den folgenden Abschnitten sehen wir uns diese neuen Frameworks an und erfahren, wie Sie sie in einer Xamarin.iOS-App implementieren.

Das Kontakte-Framework

Das Contacts Framework bietet Xamarin.iOS-Zugriff auf die Kontaktinformationen des Benutzers. Da die meisten Apps nur schreibgeschützten Zugriff erfordern, wurde dieses Framework für threadsicheren, schreibgeschützten Zugriff optimiert.

Kontaktobjekte

Die CNContact -Klasse bietet threadsicheren, schreibgeschützten Zugriff auf die Eigenschaften eines Kontakts wie Name, Adresse oder Telefonnummern. CNContact Funktionen wie und NSDictionary enthält mehrere schreibgeschützte Auflistungen von Eigenschaften (z. B. Adressen oder Telefonnummern):

Contact-Objekt – Übersicht

Für jede Eigenschaft, die mehrere Werte aufweisen kann (z. B. E-Mail-Adresse oder Telefonnummern), werden sie als Array von NSLabeledValue Objekten dargestellt. NSLabeledValue ist ein threadsicheres Tupel, das aus einem schreibgeschützten Satz von Bezeichnungen und Werten besteht, bei dem die Bezeichnung den Wert für den Benutzer definiert (z. B. Home- oder Work-E-Mail). Das Contacts-Framework bietet eine Auswahl vordefinierter Bezeichnungen (über die CNLabelKey statischen Klassen und CNLabelPhoneNumberKey ), die Sie in Ihrer App verwenden können, oder Sie haben die Möglichkeit, benutzerdefinierte Bezeichnungen für Ihre Anforderungen zu definieren.

Verwenden Sie für jede Xamarin.iOS-App, die die Werte eines vorhandenen Kontakts anpassen (oder neue erstellen muss), die NSMutableContact Version der -Klasse und deren Unterklassen (z CNMutablePostalAddress. B. ).

Mit dem folgenden Code wird beispielsweise ein neuer Kontakt erstellt und der Kontaktsammlung des Benutzers hinzugefügt:

// 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);
}

Wenn dieser Code auf einem iOS 9-Gerät ausgeführt wird, wird der Sammlung des Benutzers ein neuer Kontakt hinzugefügt. Beispiel:

Ein neuer Kontakt, der der Sammlung des Benutzers hinzugefügt wurde

Kontaktformatierung und Lokalisierung

Das Contacts-Framework enthält mehrere Objekte und Methoden, mit denen Sie Inhalte für die Anzeige für den Benutzer formatieren und lokalisieren können. Der folgende Code würde beispielsweise einen Kontaktnamen und eine Postanschrift für die Anzeige korrekt formatieren:

Console.WriteLine(CNContactFormatter.GetStringFrom(contact, CNContactFormatterStyle.FullName));
Console.WriteLine(CNPostalAddressFormatter.GetStringFrom(workAddress, CNPostalAddressFormatterStyle.MailingAddress));

Für Eigenschaftenbezeichnungen, die Sie auf der Benutzeroberfläche Ihrer App anzeigen, verfügt das Contact-Framework auch über Methoden zum Lokalisieren dieser Zeichenfolgen. Auch dies basiert auf dem aktuellen Gebietsschema des iOS-Geräts, auf dem die App ausgeführt wird. Beispiel:

// Localized properties
Console.WriteLine(CNContact.LocalizeProperty(CNContactOptions.Nickname));
Console.WriteLine(CNLabeledValue<NSString>.LocalizeLabel(CNLabelKey.Home));

Abrufen vorhandener Kontakte

Mithilfe einer instance der CNContactStore -Klasse können Sie Kontaktinformationen aus der Kontaktdatenbank des Benutzers abrufen. Enthält CNContactStore alle Methoden, die zum Abrufen oder Aktualisieren von Kontakten und Gruppen aus der Datenbank erforderlich sind. Da diese Methoden synchron sind, wird empfohlen, sie in einem Hintergrundthread auszuführen, damit die Benutzeroberfläche nicht blockiert wird.

Mithilfe von Prädikaten (aus der CNContact -Klasse erstellt) können Sie die Ergebnisse filtern, die beim Abrufen von Kontakten aus der Datenbank zurückgegeben werden. Verwenden Sie den folgenden Code, um nur Kontakte abzurufen, die die Zeichenfolge Appleseedenthalten:

// Create predicate to locate requested contact
var predicate = CNContact.GetPredicateForContacts("Appleseed");

Wichtig

Generische prädikate und zusammengesetzte Prädikate werden vom Contacts-Framework nicht unterstützt.

Verwenden Sie beispielsweise den folgenden Code, um den Abruf nur auf die Eigenschaften GivenName und FamilyName des Kontakts zu beschränken:

// Define fields to be searched
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName};

Verwenden Sie schließlich den folgenden Code, um die Datenbank zu durchsuchen und die Ergebnisse zurückzugeben:

// Grab matching contacts
var store = new CNContactStore();
NSError error;
var contacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);

Wenn dieser Code nach dem Beispiel ausgeführt wird, das wir oben im Abschnitt Contacts-Objekt erstellt haben, würde er den soeben erstellten Kontakt "John Appleseed" zurückgeben.

Kontakt Zum Datenschutz

Da Endbenutzer den Zugriff auf ihre Kontaktinformationen pro Anwendung gewähren oder verweigern können, wird beim ersten Aufruf von bei ein Dialogfeld angezeigt, in dem CNContactStoresie aufgefordert werden, den Zugriff auf Ihre App zuzulassen.

Die Berechtigungsanforderung wird nur einmal angezeigt, wenn die App zum ersten Mal ausgeführt wird, und nachfolgende Ausführungen oder Aufrufe von CNContactStore verwenden die Berechtigung, die der Benutzer zu diesem Zeitpunkt ausgewählt hat.

Sie sollten Ihre App so entwerfen, dass sie den Benutzer ordnungsgemäß behandelt, der den Zugriff auf seine Kontaktdatenbank verweigert.

Abrufen von Teilkontakten

Ein Partieller Kontakt ist ein Kontakt, für den nur einige der verfügbaren Eigenschaften aus dem Kontaktspeicher abgerufen wurden. Wenn Sie versuchen, auf eine Eigenschaft zuzugreifen, die zuvor nicht abgerufen wurde, führt dies zu einer Ausnahme.

Sie können leicht überprüfen, ob ein gegebener Kontakt über die gewünschte Eigenschaft verfügt, indem Sie entweder die -Methode oder AreKeysAvailable die IsKeyAvailable -Methode des CNContact instance verwenden. Beispiel:

// 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);
}

Wichtig

Die GetUnifiedContact Methoden und GetUnifiedContacts der CNContactStore -Klasse geben nur einen Partiellen Kontakt zurück, der auf die Eigenschaften beschränkt ist, die von den bereitgestellten Abrufschlüsseln angefordert werden.

Vereinheitlichte Kontakte

Ein Benutzer verfügt möglicherweise über verschiedene Quellen von Kontaktinformationen für eine einzelne Person in seiner Kontaktdatenbank (z. B. iCloud, Facebook oder Google Mail). In iOS- und OS X-Apps werden diese Kontaktinformationen automatisch miteinander verknüpft und dem Benutzer als einheitlicher Kontakt angezeigt:

Übersicht über vereinheitlichte Kontakte

Bei diesem einheitlichen Kontakt handelt es sich um eine temporäre In-Memory-Ansicht der Linkkontaktinformationen, die einen eigenen eindeutigen Bezeichner erhalten (der bei Bedarf zum Refetch des Kontakts verwendet werden sollte). Standardmäßig gibt das Kontakteframework nach Möglichkeit einen einheitlichen Kontakt zurück.

Erstellen und Aktualisieren von Kontakten

Wie wir oben im Abschnitt Kontaktobjekte gesehen haben, verwenden Sie eine CNContactStore und eine instance von , CNMutableContact um neue Kontakte zu erstellen, die dann mithilfe von in CNSaveRequestdie Kontaktdatenbank des Benutzers geschrieben werden:

// 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);
}

Ein CNSaveRequest kann auch verwendet werden, um mehrere Kontakt- und Gruppierungsänderungen in einem einzelnen Vorgang zwischenzuspeichern und diese Änderungen in batch zu batchen CNContactStore.

Um einen nicht veränderlichen Kontakt zu aktualisieren, der aus einem Abrufvorgang abgerufen wurde, müssen Sie zunächst eine veränderliche Kopie anfordern, die Sie dann ändern und wieder im Kontaktspeicher speichern. Beispiel:

// 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);
}

Kontaktänderungsbenachrichtigungen

Wenn ein Kontakt geändert wird, stellt der Kontaktspeicher eine CNContactStoreDidChangeNotification im Standardbenachrichtigungscenter bereit. Wenn Sie Kontakte zwischengespeichert haben oder gerade anzeigen, müssen Sie diese Objekte aus dem Kontaktspeicher (CNContactStore) aktualisieren.

Container und Gruppen

Die Kontakte eines Benutzers können entweder lokal auf dem Gerät des Benutzers oder als Kontakte vorhanden sein, die von einem oder mehreren Serverkonten (z. B. Facebook oder Google) mit dem Gerät synchronisiert werden. Jeder Kontaktpool verfügt über einen eigenen Container , und ein bestimmter Kontakt kann nur in einem Container vorhanden sein.

Übersicht über Container und Gruppen

In einigen Containern können Kontakte in eine oder mehrere Gruppen oder Untergruppen angeordnet werden. Dieses Verhalten hängt vom Sicherungsspeicher für einen bestimmten Container ab. Beispielsweise verfügt iCloud nur über einen Container, kann jedoch viele Gruppen (aber keine Untergruppen) haben. Microsoft Exchange hingegen unterstützt keine Gruppen, kann aber mehrere Container (einen für jeden Exchange-Ordner) haben.

Überlappung innerhalb von Containern und Gruppen

Das ContactsUI-Framework

In Situationen, in denen Ihre Anwendung keine benutzerdefinierte Benutzeroberfläche präsentieren muss, können Sie das ContactsUI-Framework verwenden, um UI-Elemente zum Anzeigen, Bearbeiten, Auswählen und Erstellen von Kontakten in Ihrer Xamarin.iOS-App anzuzeigen, zu bearbeiten, auszuwählen und zu erstellen.

Durch die Verwendung der integrierten Apple-Steuerelemente reduzieren Sie nicht nur die Menge an Code, die Sie erstellen müssen, um Kontakte in Ihrer Xamarin.iOS-App zu unterstützen, sondern stellen auch eine konsistente Oberfläche für die Benutzer der App bereit.

Der Ansichtscontroller für die Kontaktauswahl

Der Ansichtscontroller für die Kontaktauswahl (CNContactPickerViewController) verwaltet die Standardmäßige Kontaktauswahlansicht, mit der der Benutzer einen Kontakt oder eine Kontakteigenschaft aus der Kontaktdatenbank des Benutzers auswählen kann. Der Benutzer kann einen oder mehrere Kontakt (basierend auf seiner Verwendung) auswählen, und der Ansichtscontroller für die Kontaktauswahl fordert vor dem Anzeigen der Auswahl nicht zur Berechtigung auf.

Bevor Sie die CNContactPickerViewController -Klasse aufrufen, definieren Sie, welche Eigenschaften der Benutzer auswählen und Prädikate definieren kann, um die Anzeige und Auswahl von Kontakteigenschaften zu steuern.

Verwenden Sie eine instance der Klasse, die von CNContactPickerDelegate erbt, um auf die Interaktion des Benutzers mit der Auswahl zu reagieren. Beispiel:

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
    }
}

Damit der Benutzer eine E-Mail-Adresse aus den Kontakten in seiner Datenbank auswählen kann, können Sie den folgenden Code verwenden:

// 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);

Der Kontaktansichtscontroller

Die Contact View Controller -Klasse (CNContactViewController) stellt einen Controller bereit, um dem Endbenutzer eine Standardkontaktansicht zu präsentieren. In der Kontaktansicht können neue, unbekannte oder vorhandene Kontakte angezeigt werden, und der Typ muss angegeben werden, bevor die Ansicht durch Aufrufen des richtigen statischen Konstruktors (FromNewContact, FromUnknownContact, FromContact) angezeigt wird. Beispiel:

// Create a new contact view
var view = CNContactViewController.FromContact(contact);

// Display the view
PresentViewController(view, true, null);

Zusammenfassung

In diesem Artikel wird die Arbeit mit den Benutzeroberflächenframeworks "Kontakt" und "Kontakt" in einer Xamarin.iOS-Anwendung ausführlich erläutert. Zunächst wurden die verschiedenen Arten von Objekten behandelt, die das Contact-Framework bereitstellt, und wie Sie sie verwenden, um neue Kontakte zu erstellen oder auf vorhandene Kontakte zuzugreifen. Außerdem wurde das Framework für die Kontaktbenutzeroberfläche untersucht, um vorhandene Kontakte auszuwählen und Kontaktinformationen anzuzeigen.