Arbeitsprofilkontakte

In diesem Entwicklerhandbuch wird erläutert, wie du deine App für die Verwendung von Daten aus dem Arbeitsprofil. Wenn Sie die Kontakt-APIs von Android noch nicht verwendet haben sollten Sie sich mit dem Thema Contacts Provider (Kontaktanbieter) vertraut machen. die APIs.

Übersicht

Auf Geräten mit Arbeitsprofilen werden Kontakte in separaten lokalen für geschäftliche und private Profile. Wenn eine App standardmäßig in privaten Profil erstellen, werden die geschäftlichen Kontakte nicht angezeigt. Eine App kann jedoch Auf Kontaktdaten im Arbeitsprofil zugreifen Beispiel: Eine App, die Dies ist die Google Kontakte App für Android, in der sowohl private als auch Arbeitsverzeichnis-Kontakte in den Suchergebnissen.

Nutzer verwenden oft private Geräte und Apps für die Arbeit. Durch die Verwendung von Arbeitsprofilkontakten kann Ihre App Teil des Arbeitstages der Nutzer werden.

Nutzererfahrung

Überlegen Sie, wie Ihre App Kontaktdaten aus dem Arbeitsprofil darstellen könnte. Der beste Ansatz hängt von der Art Ihrer App und davon ab, warum Nutzer sollten Sie Folgendes beachten:

  • Soll Ihre App standardmäßig Kontakte aus dem Arbeitsprofil enthalten oder soll der Nutzer Opt-in?
  • Wie wirkt sich die Kombination oder Trennung von Kontakten im geschäftlichen und privaten Profil auf die User Flow?
  • Welche Auswirkungen hat es, wenn Sie versehentlich auf einen Kontakt im Arbeitsprofil tippen?
  • Was passiert mit der Benutzeroberfläche Ihrer App, wenn die Kontakte im Arbeitsprofil nicht vorhanden sind? verfügbar?

In Ihrer App sollte deutlich erkennbar sein, dass es sich um einen Kontakt im Arbeitsprofil handelt. Vielleicht können Sie über ein bekanntes Symbol für die Arbeit, z. B. eine Aktentasche.

<ph type="x-smartling-placeholder">
</ph> Screenshot mit Suchergebnissen in einer Liste
Abbildung 1: Trennung von Arbeitsprofilen durch die Google Kontakte App Kontakte

Die Google Kontakte App (Abbildung 1) führt folgende Schritte aus, um eine Mischung aus beruflichen und privaten Profilkontakten auflisten:

  1. Fügt eine Unterüberschrift ein, um geschäftliche und private Abschnitte der Liste zu trennen.
  2. Arbeitskontakte werden durch ein Aktentaschensymbol gekennzeichnet.
  3. Durch Antippen wird ein geschäftlicher Kontakt im Arbeitsprofil geöffnet.

Wenn die Person, die das Gerät verwendet, das Arbeitsprofil deaktiviert, kann Ihre App Kontaktinformationen im Arbeitsprofil oder über die Fernbedienung der Organisation nachschlagen Kontaktverzeichnisse. Je nachdem, wie Sie die Kontakte im Arbeitsprofil verwenden, können Sie lassen Sie diese Kontakte ohne Ton aus oder Sie müssen möglicherweise die Benutzeroberfläche deaktivieren. Steuerelementen.

Berechtigungen

Wenn Ihre App bereits mit den Kontakten des Nutzers funktioniert, werden deren READ_CONTACTS (oder möglicherweise WRITE_CONTACTS), die Sie in Ihrem App-Manifestdatei. Weil dieselbe Person das private Profil und die Arbeit Profil haben, benötigen Sie keine weitere Berechtigung, um auf Kontaktdaten aus der Arbeit zuzugreifen zu erstellen.

Ein IT-Administrator kann blockieren dem Arbeitsprofil, das Kontaktinformationen mit dem privaten Profil teilt. Wenn ein IT-Team der Zugriff blockiert, werden Ihre Kontaktsuchen als leere Ergebnisse zurückgegeben. Ihr Die App muss keine spezifischen Fehler beheben, wenn die Nutzenden die Arbeit ausgeschaltet haben. zu erstellen. Der Anbieter des Verzeichnis-Contents gibt weiterhin Informationen zum die geschäftlichen Kontaktverzeichnisse des Nutzers (siehe Abschnitt Verzeichnisse). Informationen zum Testen dieser Berechtigungen finden Sie im Abschnitt Entwicklung und Tests .

Kontaktsuche

Kontakte aus dem Arbeitsprofil können Sie über dieselben APIs und Prozesse abrufen, Ihre App verwendet, um Kontakte im privaten Profil abzurufen. Der Unternehmens-URI für Kontakte wird ab Android 7.0 (API-Level 24) unterstützt. Sie müssen folgende Anpassungen am URI:

  1. URI des Contentanbieters festlegen auf Contacts.ENTERPRISE_CONTENT_FILTER_URI, und geben den Namen des Kontakts als Abfragestring an.
  2. Legen Sie ein Kontaktverzeichnis für die Suche fest. Beispiel: ENTERPRISE_DEFAULT findet Kontakte in der Arbeit das lokale Geschäft des Profils.

Wenn Sie den URI ändern, können Sie alle Mechanismen für Contentanbieter ändern, z. B. CursorLoader: Diese Methode ist ideal, um Kontaktdaten in Benutzeroberflächen zu laden, erfolgt der Datenzugriff in einem Worker-Thread. Der Einfachheit halber sind die Beispiele in diesem Guide-Aufruf ContentResolver.query(). So finden Sie Kontakte im lokalen Kontaktverzeichnis des Arbeitsprofils:

Kotlin

// First confirm the device user has given permission for the personal profile.
// There isn't a separate work permission, but an IT admin can block access.
val readContactsPermission =
  ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.READ_CONTACTS)
if (readContactsPermission != PackageManager.PERMISSION_GRANTED) {
  return
}

// Fetch Jackie, James, & Jason (and anyone else whose names begin with "ja").
val nameQuery = Uri.encode("ja")

// Build the URI to look up work profile contacts whose name matches. Query
// the default work profile directory which is the locally-stored contacts.
val contentFilterUri =
  ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
    .buildUpon()
    .appendPath(nameQuery)
    .appendQueryParameter(
      ContactsContract.DIRECTORY_PARAM_KEY,
      ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
    )
    .build()

// Query the content provider using the generated URI.
var cursor =
  getContentResolver()
    .query(
      contentFilterUri,
      arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
      ),
      null,
      null,
      null
    )

// Print any results found using the work profile contacts' display name.
cursor?.use {
  while (it.moveToNext()) {
    Log.i(TAG, "Work profile contact: ${it.getString(2)}")
  }
}

Java

// First confirm the device user has given permission for the personal profile.
// There isn't a separate work permission, but an IT admin can block access.
int readContactsPermission = ContextCompat.checkSelfPermission(
    getBaseContext(), Manifest.permission.READ_CONTACTS);
if (readContactsPermission != PackageManager.PERMISSION_GRANTED) {
  return;
}

// Fetch Jackie, James, & Jason (and anyone else whose names begin with "ja").
String nameQuery = Uri.encode("ja");

// Build the URI to look up work profile contacts whose name matches. Query
// the default work profile directory which is the locally stored contacts.
Uri contentFilterUri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
    .buildUpon()
    .appendPath(nameQuery)
    .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
        String.valueOf(ContactsContract.Directory.ENTERPRISE_DEFAULT))
    .build();

// Query the content provider using the generated URI.
Cursor cursor = getContentResolver().query(
    contentFilterUri,
    new String[] {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
    },
    null,
    null,
    null);
if (cursor == null) {
  return;
}

// Print any results found using the work profile contacts' display name.
try {
  while (cursor.moveToNext()) {
    Log.i(TAG, "Work profile contact: " + cursor.getString(2));
  }
} finally {
  cursor.close();
}

Verzeichnisse

Viele Organisationen verwenden Remote-Verzeichnisse wie Microsoft Exchange oder LDAP. die Kontaktdaten für das gesamte Unternehmen enthalten. Deine App kann helfen mit Arbeitskollegen, die sich im Unternehmen des Unternehmens befinden, -Verzeichnis. Beachten Sie, dass diese Verzeichnisse normalerweise Tausende von Kontakten enthalten. und deine App benötigt eine aktive Netzwerkverbindung, um danach zu suchen. Sie können Directory-Contentanbieter, um die Verzeichnisse zu erhalten, die vom Nutzerkonten und weitere Informationen zu einzelnen Verzeichnissen.

Directory.ENTERPRISE_CONTENT_URI abfragen Contentanbieter, um Verzeichnisse aus dem privaten Profil und der Arbeit zu erhalten. Profil zurückgegeben. Das Durchsuchen von Arbeitsprofilverzeichnissen wird unterstützt in Android 7.0 (API-Level 24) oder höher In Ihrer App muss der Nutzer READ_CONTACTS-Berechtigungen, um mit dem Kontakt zusammenzuarbeiten Verzeichnisse enthalten.

Da Android Kontaktinformationen in verschiedenen Remote-Verzeichnisse haben, verfügt die Klasse Directory über Methoden, die Sie aufrufen können, um weitere zu einem Verzeichnis:

isEnterpriseDirectoryId()
Rufen Sie diese Methode auf, um herauszufinden, ob das Verzeichnis zu einem Arbeitsprofilkonto gehört. Beachte, dass der Contentanbieter ENTERPRISE_CONTENT_URI den Kontakt zurückgibt Verzeichnisse für das private und das Arbeitsprofil zusammen.
isRemoteDirectoryId()
Rufen Sie diese Methode auf, um herauszufinden, ob es sich bei dem Verzeichnis um ein Remote-Verzeichnis handelt. Remote-Verzeichnisse können Unternehmenskontaktspeicher oder die sozialen Netzwerke des Nutzers sein.

Das folgende Beispiel zeigt, wie Sie diese Methoden zum Filtern von Arbeitsprofilen verwenden können Verzeichnisse enthalten:

Kotlin

// First, confirm the device user has given READ_CONTACTS permission.
// This permission is still needed for directory listings ...

// Query the content provider to get directories for BOTH the personal and
// work profiles.
val cursor =
  getContentResolver()
    .query(
      ContactsContract.Directory.ENTERPRISE_CONTENT_URI,
      arrayOf(ContactsContract.Directory._ID, ContactsContract.Directory.PACKAGE_NAME),
      null,
      null,
      null
    )

// Print the package name of the work profile's local or remote contact directories.
cursor?.use {
  while (it.moveToNext()) {
    val directoryId = it.getLong(0)
    if (ContactsContract.Directory.isEnterpriseDirectoryId(directoryId)) {
      Log.i(TAG, "Directory: ${it.getString(1)}")
    }
  }
}

Java

// First, confirm the device user has given READ_CONTACTS permission.
// This permission is still needed for directory listings ...

// Query the content provider to get directories for BOTH the personal and
// work profiles.
Cursor cursor = getContentResolver().query(
    ContactsContract.Directory.ENTERPRISE_CONTENT_URI,
    new String[]{
        ContactsContract.Directory._ID,
        ContactsContract.Directory.PACKAGE_NAME
    },
    null,
    null,
    null);
if (cursor == null) {
  return;
}

// Print the package name of the work profile's local or remote contact directories.
try {
  while (cursor.moveToNext()) {
    long directoryId = cursor.getLong(0);

    if (ContactsContract.Directory.isEnterpriseDirectoryId(directoryId)) {
      Log.i(TAG, "Directory: " + cursor.getString(1));
    }
  }
} finally {
  cursor.close();
}

Im Beispiel werden die ID und der Paketname für das Verzeichnis abgerufen. So zeigen Sie einen Nutzer an: über die Nutzer eine Kontaktverzeichnis-Quelle auswählen können, müssen Sie möglicherweise um weitere Informationen zum Verzeichnis abzurufen. Um weitere Metadatenfelder anzuzeigen, die finden Sie in der Directory-Klassenreferenz.

Telefonnummernsuche

Apps können Abfragen ausführen PhoneLookup.CONTENT_FILTER_URI, um effizient nach Kontaktdaten für eine Telefonnummer zu suchen. Du erhältst Suchergebnisse von sowohl beim privaten als auch im Arbeitsprofil den Anbieter kontaktieren, wenn Sie diesen URI durch PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI Dieser Inhalts-URI für das Arbeitsprofil ist in Android 5.0 (API-Level 21) verfügbar oder höher liegen.

Das folgende Beispiel zeigt eine App, die den Inhalts-URI des Arbeitsprofils abfragt: Benutzeroberfläche für eingehende Anrufe konfigurieren:

Kotlin

fun onCreateIncomingConnection(
  connectionManagerPhoneAccount: PhoneAccountHandle,
  request: ConnectionRequest
): Connection {
  var request = request
  // Get the telephone number from the incoming request URI.
  val phoneNumber = this.extractTelephoneNumber(request.address)

  var displayName = "Unknown caller"
  var isCallerInWorkProfile = false

  // Look up contact details for the caller in the personal and work profiles.
  val lookupUri =
    Uri.withAppendedPath(
      ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
      Uri.encode(phoneNumber)
    )
  val cursor =
    getContentResolver()
      .query(
        lookupUri,
        arrayOf(
          ContactsContract.PhoneLookup._ID,
          ContactsContract.PhoneLookup.DISPLAY_NAME,
          ContactsContract.PhoneLookup.CUSTOM_RINGTONE
        ),
        null,
        null,
        null
      )

  // Use the first contact found and check if they're from the work profile.
  cursor?.use {
    if (it.moveToFirst() == true) {
      displayName = it.getString(1)
      isCallerInWorkProfile = ContactsContract.Contacts.isEnterpriseContactId(it.getLong(0))
    }
  }

  // Return a configured connection object for the incoming call.
  val connection = MyAudioConnection()
  connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED)

  // Our app's activity uses this value to decide whether to show a work badge.
  connection.setIsCallerInWorkProfile(isCallerInWorkProfile)

  // Configure the connection further ...
  return connection
}

Java

public Connection onCreateIncomingConnection (
    PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
  // Get the telephone number from the incoming request URI.
  String phoneNumber = this.extractTelephoneNumber(request.getAddress());

  String displayName = "Unknown caller";
  boolean isCallerInWorkProfile = false;

  // Look up contact details for the caller in the personal and work profiles.
  Uri lookupUri = Uri.withAppendedPath(
      ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
      Uri.encode(phoneNumber));
  Cursor cursor = getContentResolver().query(
      lookupUri,
      new String[]{
          ContactsContract.PhoneLookup._ID,
          ContactsContract.PhoneLookup.DISPLAY_NAME,
          ContactsContract.PhoneLookup.CUSTOM_RINGTONE
      },
      null,
      null,
      null);

  // Use the first contact found and check if they're from the work profile.
  if (cursor != null) {
    try {
      if (cursor.moveToFirst() == true) {
        displayName = cursor.getString(1);
        isCallerInWorkProfile =
            ContactsContract.Contacts.isEnterpriseContactId(cursor.getLong(0));
      }
    } finally {
      cursor.close();
    }
  }

  // Return a configured connection object for the incoming call.
  MyConnection connection = new MyConnection();
  connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED);

  // Our app's activity uses this value to decide whether to show a work badge.
  connection.setIsCallerInWorkProfile(isCallerInWorkProfile);

  // Configure the connection further ...
  return connection;
}

Suche nach E-Mail-Adressen

Ihre App kann private oder geschäftliche Kontaktdaten für eine E-Mail-Adresse abrufen, indem sie Abfragen Email.ENTERPRISE_CONTENT_LOOKUP_URI Bei dieser URL wird zuerst in den persönlichen Kontakten nach einer genauen Übereinstimmung gesucht. Wenn aber keine persönlichen Kontakte gefunden werden, sucht er beruflichen Kontakte für ein Spiel. Dieser URI ist in Android 6.0 (API-Level 23) verfügbar. oder höher.

So finden Sie die Kontaktinformationen für eine E-Mail-Adresse:

Kotlin

// Build the URI to look up contacts from the personal and work profiles that
// are an exact (case-insensitive) match for the email address.
val emailAddress = "somebody@example.com"
val contentFilterUri =
  Uri.withAppendedPath(
    ContactsContract.CommonDataKinds.Email.ENTERPRISE_CONTENT_LOOKUP_URI,
    Uri.encode(emailAddress)
  )

// Query the content provider to first try to match personal contacts and,
// if none are found, then try to match the work contacts.
val cursor =
  contentResolver.query(
    contentFilterUri,
    arrayOf(
      ContactsContract.CommonDataKinds.Email.CONTACT_ID,
      ContactsContract.CommonDataKinds.Email.ADDRESS,
      ContactsContract.Contacts.DISPLAY_NAME
    ),
    null,
    null,
    null
  )
    ?: return

// Print the name of the matching contact. If we want to work-badge contacts,
// we can call ContactsContract.Contacts.isEnterpriseContactId() with the ID.
cursor.use {
  while (it.moveToNext()) {
    Log.i(TAG, "Matching contact: ${it.getString(2)}")
  }
}

Java

// Build the URI to look up contacts from the personal and work profiles that
// are an exact (case-insensitive) match for the email address.
String emailAddress = "somebody@example.com";
Uri contentFilterUri = Uri.withAppendedPath(
    ContactsContract.CommonDataKinds.Email.ENTERPRISE_CONTENT_LOOKUP_URI,
    Uri.encode(emailAddress));

// Query the content provider to first try to match personal contacts and,
// if none are found, then try to match the work contacts.
Cursor cursor = getContentResolver().query(
    contentFilterUri,
    new String[]{
        ContactsContract.CommonDataKinds.Email.CONTACT_ID,
        ContactsContract.CommonDataKinds.Email.ADDRESS,
        ContactsContract.Contacts.DISPLAY_NAME
    },
    null,
    null,
    null);
if (cursor == null) {
  return;
}

// Print the name of the matching contact. If we want to work-badge contacts,
// we can call ContactsContract.Contacts.isEnterpriseContactId() with the ID.
try {
  while (cursor.moveToNext()) {
    Log.i(TAG, "Matching contact: " + cursor.getString(2));
  }
} finally {
  cursor.close();
}

Geschäftliche Kontakte anzeigen

Apps, die im privaten Profil ausgeführt werden, können im Arbeitsprofil eine Kontaktkarte anzeigen. Anruf ContactsContract.QuickContact.showQuickContact() Zoll Android 5.0 oder höher, um die Kontakte App im Arbeitsprofil zu starten und Kontaktkarte verwenden.

Um einen korrekten URI für das Arbeitsprofil zu generieren, müssen Sie Folgendes aufrufen: ContactsContract.Contacts.getLookupUri() und übergeben Sie Kontakt-ID und Suchschlüssel. Das folgende Beispiel zeigt, wie Sie den URI abrufen können. und dann die Karte einblenden:

Kotlin

// Query the content provider using the ENTERPRISE_CONTENT_FILTER_URI address.
// We use the _ID and LOOKUP_KEY columns to generate a work-profile URI.
val cursor =
  getContentResolver()
    .query(
      contentFilterUri,
      arrayOf(ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY),
      null,
      null
    )

// Show the contact details card in the work profile's Contacts app. The URI
// must be created with getLookupUri().
cursor?.use {
  if (it.moveToFirst() == true) {
    val uri = ContactsContract.Contacts.getLookupUri(it.getLong(0), it.getString(1))
    ContactsContract.QuickContact.showQuickContact(
      activity,
      Rect(20, 20, 100, 100),
      uri,
      ContactsContract.QuickContact.MODE_LARGE,
      null
    )
  }
}

Java

// Query the content provider using the ENTERPRISE_CONTENT_FILTER_URI address.
// We use the _ID and LOOKUP_KEY columns to generate a work-profile URI.
Cursor cursor = getContentResolver().query(
    contentFilterUri,
    new String[] {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.LOOKUP_KEY,
    },
    null,
    null,
    null);
if (cursor == null) {
  return;
}

// Show the contact details card in the work profile's Contacts app. The URI
// must be created with getLookupUri().
try {
  if (cursor.moveToFirst() == true) {
    Uri uri = ContactsContract.Contacts.getLookupUri(
        cursor.getLong(0), cursor.getString(1));
    ContactsContract.QuickContact.showQuickContact(
        getActivity(),
        new Rect(20, 20, 100, 100),
        uri,
        ContactsContract.QuickContact.MODE_LARGE,
        null);
  }
} finally {
  cursor.close();
}

Verfügbarkeit

In der folgenden Tabelle ist zusammengefasst, welche Android-Versionen Arbeitsprofil unterstützen Kontaktdaten im privaten Profil:

Android-Version Support
5.0 (API-Level 21) Mit PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI können Sie die Namen von geschäftlichen Kontakten für Telefonnummern nachschlagen.
6.0 (API-Level 23) Namen von geschäftlichen Kontakten für E-Mail-Adressen finden Sie mit Email.ENTERPRISE_CONTENT_LOOKUP_URI.
7.0 (API-Level 24) Fragen Sie die Namen von geschäftlichen Kontakten aus Arbeitsverzeichnissen mit Contacts.ENTERPRISE_CONTENT_FILTER_URI ab.
Listen Sie alle Verzeichnisse in den beruflichen und privaten Profilen mit Directory.ENTERPRISE_CONTENT_URI auf.

Entwicklung und Tests

So erstellen Sie ein Arbeitsprofil:

  1. Installieren Sie unsere DPC-Test-App.
  2. Öffnen Sie die App Set up Test DPC (nicht das Symbol der Test DPC App).
  3. Folgen Sie der Anleitung auf dem Bildschirm, um ein verwaltetes Profil einzurichten.
  4. Öffnen Sie im Arbeitsprofil die App Kontakte und fügen Sie einige Beispielkontakte hinzu.

So simulieren Sie, dass ein IT-Administrator den Zugriff auf Kontakte im Arbeitsprofil blockiert:

  1. Öffnen Sie im Arbeitsprofil die App Test DPC.
  2. Suchen Sie nach der Einstellung Profilübergreifende Kontaktsuche deaktivieren oder dem Profilübergreifende Anrufer-ID-Einstellung deaktivieren
  3. Setzen Sie den Schalter auf An.

Weitere Informationen zum Testen Ihrer App mit Arbeitsprofilen finden Sie unter App testen für Kompatibilität mit Arbeitsprofilen.

Weitere Informationen

Weitere Informationen zu Kontakten oder dem Arbeitsprofil finden Sie in den folgenden Ressourcen: