Freigeben über


Kontakte und KontakteUI in Xamarin.iOS

In diesem Artikel wird die Arbeit mit den neuen Benutzeroberflächenframeworks "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 wird.

Mit der Einführung von iOS 9 hat Apple zwei neue Frameworks, Contacts und ContactsUI veröffentlicht, welche die vorhandenen Frameworks für Adressbuch und Adressbuch-Benutzeroberfläche ersetzen, die bis iOS 8 verwendet werden.

Die beiden neuen Frameworks enthalten die folgenden Funktionen:

  • Kontakte – Ermöglicht den 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 bereit, um Kontakte auf iOS-Geräten anzuzeigen, zu bearbeiten, auszuwählen und zu erstellen.

Beispielkontaktblatt auf einem iOS-Gerät

Wichtig

Die vorhandenen AddressBook und AddressBookUI Frameworks, 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 und ContactsUI Frameworks ersetzt werden. Neue Apps sollten mit den neuen Frameworks geschrieben werden.

In den folgenden Abschnitten befassen wir uns mit diesen neuen Frameworks und deren Implementierung in einer Xamarin.iOS-App.

Das Kontakteframework

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 Telefon Zahlen. CNContact funktioniert wie ein NSDictionary und enthält mehrere schreibgeschützte Auflistungen von Eigenschaften (z. B. Adressen oder Telefonnummern):

Übersicht über das Contact-Objekt

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, in 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 und CNLabelPhoneNumberKey statische Klassen), 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 muss (oder neue Erstellen), die NSMutableContact Version der Klasse und deren Unterklassen (z CNMutablePostalAddress. B. ).

Der folgende Code erstellt z. B. einen neuen Kontakt und fügt ihn der Kontaktsammlung des Benutzers hinzu:

// 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. Zum Beispiel:

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

Kontaktformatierung und Lokalisierung

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

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

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

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

Abrufen vorhandener Kontakte

Mithilfe einer Instanz 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, um die Benutzeroberfläche zu blockieren.

Mithilfe von Prädikaten (basierend auf der CNContact Klasse) können Sie die zurückgegebenen Ergebnisse filtern, wenn Kontakte aus der Datenbank abgerufen 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 und zusammengesetzte Prädikate werden vom Contacts-Framework nicht unterstützt.

Wenn Sie beispielsweise den Abruf auf die Eigenschaften "GivenName" und "FamilyName" des Kontakts beschränken möchten, verwenden Sie den folgenden Code:

// 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 wurde, das wir oben im Abschnitt "Contacts Object " erstellt haben, würde er den soeben erstellten "John Appleseed"-Kontakt zurückgeben.

Datenschutz für den Kontaktzugriff

Da Endbenutzern den Zugriff auf ihre Kontaktinformationen pro Anwendung gewähren oder verweigern können, wird beim ersten Aufruf an das CNContactStoreDialogfeld ein Dialogfeld angezeigt, in dem sie aufgefordert werden, den Zugriff für Ihre App zuzulassen.

Die Berechtigungsanforderung wird nur einmal angezeigt, das erste Mal, wenn die App ausgeführt wird, und nachfolgende Ausführungen oder Aufrufe an die CNContactStore 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 teilweiser Kontakte

Ein Teilkontakt 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 ganz einfach überprüfen, ob ein bestimmter Kontakt über die gewünschte Eigenschaft verfügt, indem Sie entweder die Methoden oder AreKeysAvailable Methoden IsKeyAvailable der CNContact Instanz verwenden. Zum 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 GetUnifiedContacts und Methoden der CNContactStore Klasse geben nur einen Teilkontakt zurück, der auf die eigenschaften beschränkt ist, die von den bereitgestellten Abrufschlüsseln angefordert wurden.

Einheitliche Kontakte

Ein Benutzer hat möglicherweise unterschiedliche Kontaktquellen für eine einzelne Person in ihrer 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 einzelner einheitlicher Kontakt angezeigt:

Übersicht über einheitliche Kontakte

Dieser einheitliche Kontakt ist eine temporäre, speicherinterne Ansicht der Linkkontaktinformationen, die einen eigenen eindeutigen Bezeichner erhalten (der verwendet werden sollte, um den Kontakt bei Bedarf zurückzuweisen). Standardmäßig gibt das Kontakteframework nach Möglichkeit einen einheitlichen Kontakt zurück.

Erstellen und Aktualisieren von Kontakten

Wie im Abschnitt "Kontaktobjekte " oben gezeigt, verwenden Sie eine CNContactStore und eine Instanz eines CNMutableContact , um neue Kontakte zu erstellen, die dann mithilfe einer CNSaveRequest:

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

Eine CNSaveRequest kann auch verwendet werden, um mehrere Kontakt- und Gruppenänderungen in einem einzigen Vorgang zwischenzuspeichern und diese Änderungen an der CNContactStore.

Um einen nicht änderbaren Kontakt zu aktualisieren, der von einem Abrufvorgang abgerufen wurde, müssen Sie zuerst eine änderbare Kopie anfordern, die Sie dann ändern und im Kontaktspeicher speichern. Zum 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, veröffentlicht der Kontaktspeicher ein CNContactStoreDidChangeNotification Element im Standardbenachrichtigungscenter. Wenn Sie kontakte zwischengespeichert oder aktuell angezeigt haben, 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 Mit dem Gerät synchronisierte Kontakte von einem oder mehreren Serverkonten (z. B. Facebook oder Google) vorhanden sein. Jeder Kontaktpool verfügt über einen eigenen Container , und ein bestimmter Kontakt kann nur in einem Container vorhanden sein.

Übersicht über Container und Gruppen

Einige Container ermöglichen die Anordnung von Kontakten in einer oder mehreren Gruppen oder Untergruppen. Dieses Verhalten hängt vom Sicherungsspeicher für einen bestimmten Container ab. iCloud hat beispielsweise nur einen Container, kann aber viele Gruppen (aber keine Untergruppen) haben. Microsoft Exchange unterstützt dagegen keine Gruppen, kann aber mehrere Container haben (eine für jeden Exchange-Ordner).

Überlappen innerhalb von Containern und Gruppen

The ContactsUI Framework

In Situationen, in denen Ihre Anwendung keine benutzerdefinierte Benutzeroberfläche darstellen muss, können Sie mithilfe des ContactsUI-Frameworks UI-Elemente anzeigen, bearbeiten, auswählen und erstellen Sie Kontakte in Ihrer Xamarin.iOS-App.

Durch die Verwendung der integrierten Steuerelemente von Apple reduzieren Sie nicht nur die Menge an Code, den Sie erstellen müssen, um Kontakte in Ihrer Xamarin.iOS-App zu unterstützen, aber Sie stellen den Benutzern der App eine konsistente Schnittstelle bereit.

Der Kontaktauswahl-Ansichtscontroller

Der Kontaktauswahl-Ansichtscontroller (CNContactPickerViewController) verwaltet die standardmäßige Kontaktauswahlansicht, mit der der Benutzer eine Kontakt- oder Kontakteigenschaft aus der Kontaktdatenbank des Benutzers auswählen kann. Der Benutzer kann einen oder mehrere Kontakte (basierend auf seiner Verwendung) auswählen, und der Kontaktauswahl-Ansichtscontroller 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 definieren kann, um die Anzeige und Auswahl von Kontakteigenschaften zu steuern.

Verwenden Sie eine Instanz der Klasse, von CNContactPickerDelegate der geerbt wird, um auf die Interaktion des Benutzers mit der Auswahl zu reagieren. Zum 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 der 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 Klasse "Contact View Controller" (CNContactViewController) stellt einen Controller bereit, um dem Endbenutzer eine standardmäßige Kontaktansicht zu präsentieren. Die Kontaktansicht kann neue neue, unbekannte oder vorhandene Kontakte anzeigen, und der Typ muss angegeben werden, bevor die Ansicht angezeigt wird, indem der richtige statische Konstruktor (FromNewContact, , FromUnknownContact) FromContactaufgerufen 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 Frameworks "Contact" und "Contact UI" in einer Xamarin.iOS-Anwendung ausführlich erläutert. Zunächst wurden die verschiedenen Objekttypen behandelt, die das Contact-Framework bereitstellt und wie Sie sie zum Erstellen neuer oder Zugreifen auf vorhandene Kontakte verwenden. Außerdem wurde das Framework für die Kontaktbenutzeroberfläche untersucht, um vorhandene Kontakte auszuwählen und Kontaktinformationen anzuzeigen.