Mit den Funktionen in diesem Leitfaden werden Netzwerk- und Telefonieverwaltungsfunktionen beschrieben, die Sie in Ihrer DPC-App (Device Policy Controller) implementieren können. Dieses Dokument enthält Codebeispiele. Sie können auch die App Test DPC als Quellcode für Android-Unternehmensfunktionen verwenden.
Eine DPC-App kann auf privaten Geräten im Profilinhabermodus oder auf vollständig verwalteten Geräten im Geräteinhabermodus ausgeführt werden. In der folgenden Tabelle sehen Sie, welche Features verfügbar sind, wenn der DPC im Profilinhabermodus oder Geräteinhabermodus ausgeführt wird:
Funktion | Profilinhaber | Geräteinhaber |
Profilübergreifend auf Arbeitskontakte zugreifen | ✓ | |
Sichere Netzwerkverbindung für geschäftlichen Traffic sicherstellen | ✓ | ✓ |
Eine einzelne WLAN-ID für Regionen einrichten | ✓ | ✓ |
Separate Telefon für das Arbeitsprofil angeben | ✓ |
Profilübergreifend auf Arbeitskontakte zugreifen
EMMs können dem privaten Profil eines Nutzers den Zugriff auf seine geschäftlichen Kontakte ermöglichen, sodass die privaten und beruflichen Kontakte eines Nutzers über die lokale Suche und die Remoteverzeichnis-Suche zugänglich sind. Auf privaten Geräten kann ein einzelner Dialer im privaten Profil sowohl private als auch geschäftliche Anrufe tätigen und empfangen. Darüber hinaus sind Arbeitskontakte gut in die System-UI integriert. Wenn das Arbeitsprofil verschlüsselt ist, sind seine Daten für das private Profil nicht verfügbar.
In die System-UI eingebunden
Auf der System-UI werden eingehende geschäftliche Anrufe durch ein Aktentaschensymbol angezeigt. Das callLog
zeigt auch das Symbol zum Kennzeichnen eingehender und ausgehender geschäftlicher Anrufe an. Die Apps „Persönliche Telefon“- und „Kontakt“-App können die Anrufer-ID eines geschäftlichen Kontakts über eine Remote-Verzeichnissuche anzeigen lassen. Der Kontakt muss also nicht bereits auf dem lokalen Gerät synchronisiert sein. Die Messaging-App kann eine lokale Anrufer-ID und eine Suche durchführen.
Das Android Compatibility Definition Document (CDD) enthält Anforderungen für geschäftliche Kontakte, die in der Standard-Telefon-App angezeigt werden sollen, sowie Anforderungen, dass Kontakte und Messaging-Apps gekennzeichnet sein müssen, um darauf hinzuweisen, dass sie aus dem Arbeitsprofil stammen.
Geschäftliche Kontakte sind zugänglich und suchbar
Der Nutzer kann über sein privates Profil, das auf dem Suchbildschirm der Telefon-App angezeigt wird, auf geschäftliche Kontakte zugreifen und diese anrufen. Der Nutzer kann mithilfe der automatischen Vervollständigung nach geschäftlichen Kontakten suchen, die lokal mit dem Gerät synchronisiert und über eine Remoteverzeichnis-Suche aufgelistet werden.
Berufliche Kontakte im primären Profil verwalten
Der DPC steuert die Berechtigung zum Durchsuchen geschäftlicher Kontakte. Der DPC wird im Profilinhabermodus ausgeführt und verwaltet die Sichtbarkeit der geschäftlichen Kontakte im privaten Profil. Weitere Informationen finden Sie unter Device Policy Controller erstellen.
Die Suche nach geschäftlichen Kontakten über das private Profil ist standardmäßig aktiviert.
Mit
DevicePolicyManager.getCrossProfileContactsSearchDisabled()
können Sie sehen, wie die Richtlinie festgelegt ist.Verwenden Sie
DevicePolicyManager.setCrossProfileContactsSearchDisabled()
, um die Suche nach geschäftlichen Kontakten anhand des privaten Profils zu aktivieren oder zu deaktivieren.
Sichere Netzwerkverbindung für geschäftlichen Traffic sicherstellen
Wenn ein Geräterichtlinien-Controller entweder im Modus „Geräteeigentümer“ oder im Profilinhabermodus ausgeführt wird, kann er über eine durchgehend aktive VPN-Verbindung (Virtual Private Network) erzwingen, dass Anwendungen Traffic über eine angegebene VPN-App weiterleiten, die nicht umgangen werden kann. Mithilfe einer durchgehend aktiven VPN-Verbindung kann der DPC sicherstellen, dass der Netzwerkverkehr von einem Arbeitsprofil oder einem verwalteten Gerät ohne Eingriff des Nutzers einen VPN-Dienst durchläuft. Dadurch wird eine sichere Netzwerkverbindung für kontinuierlichen Traffic innerhalb eines Arbeitsprofils erstellt.
Über durchgehend aktive VPN-Verbindungen
Als Teil des System-Frameworks wird das VPN-Routing automatisch verwaltet, damit der Nutzer den VPN-Dienst nicht umgehen kann. Wenn der VPN-Dienst im Sperrmodus getrennt ist, kann kein Datenverkehr in das offene Internet gelangen. Für Anwendungen, die VpnService
implementieren, bietet ein durchgehend aktives VPN ein Framework zum Verwalten einer sicheren VPN-Verbindung über einen vertrauenswürdigen Server und zur Aufrechterhaltung dieser Verbindung. Der VPN-Dienst startet die Verbindung über App-Updates automatisch neu, unabhängig davon, ob sie über WLAN oder Mobilfunk erfolgt. Und falls das Gerät neu gestartet wird, startet das Framework die VPN-Verbindung neu.
Die Verbindung zum VPN-Dienst ist für den Nutzer transparent. Bei einem unternehmenseigenen Gerät muss der Nutzer keinen Einwilligungsdialog für ein VPN im Always-on-Modus bestätigen. Über die VPN-Netzwerkeinstellungen des Nutzers kann manuell eine durchgehend aktive Verbindung aktiviert werden.
Wenn DISALLOW_CONFIG_VPN
den Wert true
hat, kann der Nutzer das VPN nicht konfigurieren. Aktivieren Sie DISALLOW_DEBUGGING_FEATURES
, um zu verhindern, dass Nutzer das durchgehend aktive VPN mit dem Befehl „adb debug“ überschreiben.
Wenn Sie verhindern möchten, dass ein Nutzer das VPN deinstalliert, rufen Sie DevicePolicyManager.setUninstallBlocked
auf.
VPN-Dienst einrichten
Die Organisation, die Ihre Unternehmenslösung für Android verwendet, richtet das VPN ein.
- Installieren Sie eine VPN-App, die
VpnService
implementiert. Sie können nach aktiven VPN-Diensten suchen, indem Sie einen Intent-Filter verwenden, der der AktionVpnService.SERVICE_INTERFACE
entspricht. - Deklarieren Sie im Manifest der App eine
VpnService
, die durch die BerechtigungBIND_VPN_SERVICE
geschützt ist. - Konfigurieren Sie
VpnService
so, dass es vom System gestartet wird. Vermeiden Sie es, die VPN-App so einzustellen, dass sie auf einen Systemstart wartet und ihren eigenen Lebenszyklus steuert. - Legen Sie die verwalteten Konfigurationen für die VPN-Anwendung fest (siehe Beispiel unten).
Durchgehend aktive VPN-Verbindung aktivieren
Der DPC kann durch Aufrufen von DevicePolicyManager.setAlwaysOnVpnPackage()
über eine bestimmte Anwendung eine durchgehend aktive VPN-Verbindung konfigurieren.
Diese Verbindung wird automatisch gewährt und bleibt nach einem Neustart bestehen. Wenn lockdownEnabled
auf „false“ gesetzt ist, ist der Netzwerkverkehr möglicherweise ab dem Zeitpunkt des Neustarts des Smartphones und der Verbindung des VPN nicht sicher. Dies ist nützlich, wenn Sie die Netzwerkverbindung nicht beenden möchten, wenn das VPN ausfällt oder das VPN nicht erforderlich ist.
Durchgehend aktive VPN-Verbindung prüfen
Der DPC kann den Namen des Pakets lesen, das eine durchgehend aktive VPN-Verbindung für den aktuellen Nutzer mit DevicePolicyManager.getAlwaysOnVpnPackage().
verwaltet
Wenn kein solches Paket vorhanden ist oder das VPN in den Systemeinstellungen erstellt wurde, wird null
zurückgegeben.
Beispiel
In der TestDPC-App verwendet AlwaysOnVpnFragment.java
diese APIs, um die Einstellung für eine durchgehend aktive VPN-Verbindung zu aktivieren.
Im folgenden Beispiel:
- Die verwalteten Konfigurationen des VPN-Dienstes werden vom
DevicePolicyManager
mithilfe der MethodesetApplicationRestrictions()
festgelegt. - Verwaltete Konfigurationen verwenden beliebige Schlüssel/Wert-Paare, die in dieser Beispielanwendung an anderer Stelle verwendet werden, um die Netzwerkeinstellungen des VPN zu konfigurieren (siehe Verwaltete Konfigurationen prüfen).
- In diesem Beispiel wird das Installationsprogramm für das Android-Paket einer Sperrliste hinzugefügt, damit Systempakete über das VPN nicht aktualisiert werden. Der gesamte Netzwerkverkehr des Nutzers innerhalb des Arbeitsprofils oder des Geräts wird über diese VPN-App geleitet, mit Ausnahme des Paketinstallationsprogramms. Für seine Updates wird das offene Internet verwendet.
DevicePolicyManager
aktiviert dann die durchgehend aktive VPN-Verbindung für das VPN-Paket mithilfe vonsetAlwaysOnVpnPackage()
und aktiviert den Sperrmodus.
Kotlin
// Set VPN's managed configurations val config = Bundle().apply { putString(Extras.VpnApp.ADDRESS, "192.0.2.0") putString(Extras.VpnApp.IDENTITY, "vpn.account1") putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate") putStringArray(Extras.VpnApp.DENYLIST, arrayOf("com.android.packageinstaller")) } val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager val admin = myDeviceAdminReceiver.getComponentName(this) // Name of package to update managed configurations val vpnPackageName = "com.example.vpnservice" // Associate managed configurations with DeviceAdminReceiver dpm.setApplicationRestrictions(admin, vpnPackageName, config) // Enable always-on VPN connection through VPN package try { val lockdownEnabled = true dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled) } catch (ex: Exception) { throw PolicyException() }
Java
// Set VPN's managed configurations final Bundle config = new Bundle(); config.putString(Extras.VpnApp.ADDRESS, "192.0.2.0"); config.putString(Extras.VpnApp.IDENTITY, "vpn.account1"); config.putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate"); config.putStringArray(Extras.VpnApp.DENYLIST, new String[]{"com.android.packageinstaller"}); DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName admin = myDeviceAdminReceiver.getComponentName(this); // Name of package to update managed configurations final String vpnPackageName = "com.example.vpnservice"; // Associate managed configurations with DeviceAdminReceiver dpm.setApplicationRestrictions(admin, vpnPackageName, config); // Enable always-on VPN connection through VPN package try { boolean lockdownEnabled = true; dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled)); } catch (Exception ex) { throw new PolicyException(...); }
Eine einzige WLAN-ID für mehrere Regionen einrichten
Wenn ein Device Policy Controller (DPC) entweder im Modus „Geräteeigentümer“ oder im Profilinhabermodus ausgeführt wird, kann er einer einzelnen WLAN-Konfiguration mehrere CA-Zertifikate (Certificate Authority, CA) zuordnen. Mit dieser Konfiguration kann ein Gerät eine Verbindung zu Wireless-Zugangspunkten herstellen, die denselben Netzwerknamen oder Service Set Identifier (SSID) haben, aber mit unterschiedlichen CA-Zertifikaten konfiguriert sind. Dies ist nützlich, wenn sich die drahtlosen Netzwerke Ihrer Organisation in mehreren geografischen Regionen befinden und für jede Region eine andere Zertifizierungsstelle erforderlich ist. Für rechtsgültige Signaturen kann beispielsweise eine lokale Behörde erforderlich sein, die eine regionale Zertifizierungsstelle benötigt.
Hinweis:setCaCertificate
wird seit API 18 (Jelly Bean) von Android unterstützt. IT-Administratoren müssen ihre Netzwerke jedoch für jede Zertifizierungsstelle separat bereitstellen, damit Geräte unabhängig von ihrer Region an jedem Zugangspunkt eine nahtlose Authentifizierung haben.
CA-Zertifikate angeben, um den Server zu identifizieren
Wenn Sie eine Liste von X.509-Zertifikaten angeben möchten, die den Server mit derselben SSID identifizieren, schließen Sie alle relevanten Zertifizierungsstellen mit WifiEnterpriseConfig.setCaCertificates()
in die WLAN-Konfiguration ein.
Ein Serverzertifikat ist gültig, wenn seine Zertifizierungsstelle mit einem der angegebenen Zertifikate übereinstimmt.
Standardnamen werden den Zertifikaten automatisch zugewiesen und innerhalb der Konfiguration verwendet. WifiManager
installiert das Zertifikat und speichert die Konfiguration automatisch, wenn das Netzwerk aktiviert wird. Beim Löschen der Konfiguration wird das Zertifikat entfernt.
Wenn Sie alle CA-Zertifikate abrufen möchten, die mit der WLAN-Konfiguration verknüpft sind, verwenden Sie WifiEnterpriseConfig.getCaCertificates()
, um eine Liste von X509Certificate
-Objekten zurückzugeben.
Drahtloskonfiguration mit mehreren CA-Zertifikaten hinzufügen
- Überprüfen Sie die Identität des Servers:
- Laden Sie die X.509-CA-Zertifikate.
- Laden Sie den privaten Schlüssel und das Zertifikat des Clients. Ein Beispiel für das Lesen einer Zertifikatsdatei finden Sie unter Sicherheit mit HTTPS und SSL.
- Erstellen Sie eine neue
WifiConfiguration
und legen Sie die SSID und die Schlüsselverwaltung fest. - Richten Sie die
WifiEnterpriseConfig
-Instanz auf diesemWifiConfiguration
ein.- Ermitteln Sie den Server mit einer Liste von
X509Certificate
-Objekten mithilfe vonsetCaCertificates()
. - Legen Sie die Clientanmeldedaten, die Identität und das Passwort fest.
- Legen Sie das erweiterbare Authentifizierungsprotokoll (EAP) und die Methode der Phase 2 beim Herstellen der Verbindung fest.
- Ermitteln Sie den Server mit einer Liste von
- Fügen Sie das Netzwerk mit der
WifiManager
hinzu. - Aktivieren Sie das Netzwerk. WifiManager speichert die Konfiguration automatisch während der Einrichtung.
In diesem Beispiel werden die Schritte zusammengefasst:
Kotlin
// Verify the server's identity val caCert0 = getCaCert("cert0.crt") val caCert1 = getCaCert("cert1.crt") val clientKey = getClientKey() val clientCert = getClientCert() // Create Wi-Fi configuration val wifiConfig = WifiConfiguration().apply { SSID = "mynetwork" allowedKeyManagement.set(KeyMgmt.WPA_EAP) allowedKeyManagement.set(KeyMgmt.IEEE8021X) // Set up Wi-Fi enterprise configuration enterpriseConfig.setCaCertificates(arrayOf<X509Certificate>(caCert0, caCert1)) enterpriseConfig.setClientKeyEntry(clientKey, clientCert) enterpriseConfig.setIdentity("myusername") enterpriseConfig.setEapMethod(Eap.TLS) enterpriseConfig.setPhase2Method(Phase2.NONE) } // Add network val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager val netId = wifiManager.addNetwork(wifiConfig) // Enable network if (netId < 0) { // Error creating new network } else { wifiManager.enableNetwork(netId, true) }
Java
// Verify the server's identity X509Certificate caCert0 = getCaCert("cert0.crt"); X509Certificate caCert1 = getCaCert("cert1.crt"); PrivateKey clientKey = getClientKey(); X509Certificate clientCert = getClientCert(); // Create Wi-Fi configuration WifiConfiguration wifiConfig = new WifiConfiguration(); wifiConfig.SSID = "mynetwork"; wifiConfig.allowedKeyManagement.set(KeyMgmt.WPA_EAP); wifiConfig.allowedKeyManagement.set(KeyMgmt.IEEE8021X); // Set up Wi-Fi enterprise configuration wifiConfig.enterpriseConfig.setCaCertificates(new X509Certificate[] {caCert0, caCert1}); wifiConfig.enterpriseConfig.setClientKeyEntry(clientKey, clientCert); wifiConfig.enterpriseConfig.setIdentity("myusername"); wifiConfig.enterpriseConfig.setEapMethod(Eap.TLS); wifiConfig.enterpriseConfig.setPhase2Method(Phase2.NONE); // Add network WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); int netId = wifiManager.addNetwork(wifiConfig); // Enable network if (netId < 0) { // Error creating new network } else { wifiManager.enableNetwork(netId, true); }
Separate Telefon App für das Arbeitsprofil angeben
Sie können eine separate Telefon-App für die Verwendung in einem Arbeitsprofil auf die Zulassungsliste setzen.
Das kann das Telefon selbst oder eine VoIP-App (Voice over IP) sein, in der die ConnectionService
API für das aufrufende Back-End implementiert ist. Dies bietet die gleiche integrierte System-UI-Anruffunktionen für VoIP-Anwendungen im Arbeitsprofil, wodurch der Arbeits-Dialer effektiv zu einer Kernfunktion wird. Eingehende Anrufe an die geschäftlichen Anrufkonten werden von eingehenden Anrufen an die privaten Anrufkonten unterschieden.
Der Nutzer kann über ein Telefonkonto über die Zulassungsliste für Arbeitsprofile Anrufe starten und annehmen. Alle Anrufe über diese Telefon App oder eingehende Anrufe über das geschäftliche Telefonkonto werden beim Anbieter CallLog
des Arbeitsprofils aufgezeichnet. Die Telefon App führt eine reine geschäftliche Anrufliste, die ausschließlich auf geschäftliche Kontakte zugreifen kann. Eingehende Anrufe mit Netzwerkwechsel werden vom Haupt-Telefon bearbeitet und in einer persönlichen Anrufliste gespeichert. Wenn ein Arbeitsprofil gelöscht wird, werden auch die damit verknüpften Anruflisten und alle Arbeitsprofildaten gelöscht.
Drittanbieter-Apps müssen ConnectionService implementieren
VoIP-Apps von Drittanbietern, die Anrufe tätigen müssen und bei denen diese Anrufe in die integrierte Telefon-App integriert sind, können die ConnectionService
API implementieren. Dies ist für jeden VoIP-Dienst erforderlich, der für geschäftliche Anrufe verwendet wird. Bei diesen Apps werden Anrufe wie herkömmliche Mobilfunkanrufe behandelt. Sie werden beispielsweise in der integrierten Telefonfunktion des Systems und in der Anrufliste angezeigt. Wenn die App, die ConnectionService
implementiert, im Arbeitsprofil installiert ist, ist sie nur über eine Telefon App zugänglich, die ebenfalls in diesem Arbeitsprofil installiert ist.
Sobald der Entwickler ConnectionService
implementiert hat, sollte er es der Manifestdatei der App hinzufügen und ein PhoneAccount
mit der TelecomManager
registrieren.
Ein Telefonkonto stellt eine separate Methode zum Tätigen oder Empfangen von Anrufen dar. Für jede ConnectionService
können mehrere PhoneAccounts
vorhanden sein. Nach der Registrierung des Telefonkontos kann der Nutzer es über die Telefoneinstellungen aktivieren.
Integration der System-UI und Benachrichtigungen
Die System-UI bietet Nutzern eine konsistente und integrierte Anruffunktion für Drittanbieter-Apps, die die ConnectionService
API als Back-End für Anrufe verwenden. Wenn Sie die App in einem Arbeitsprofil verwenden, wird bei eingehenden Anrufen und in der Statusleiste ein Aktentaschensymbol angezeigt. Eine Anwendung, die ConnectionService
implementiert, die im Arbeitsprofil installiert ist, kann den System-Dialer verwenden oder einen separaten Work-Dialer erstellen. Dabei kann es sich um eine einzelne App
oder unterschiedliche Apps handeln.
Die Telefonanwendung prüft anhand des Flags android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL
, ob ein geschäftlicher Anruf getätigt oder empfangen wird.
Wenn es sich um einen geschäftlichen Anruf handelt, zeigt das Telefon dies dem Nutzer durch Hinzufügen eines Arbeitskennzeichens (Aktentaschensymbol) an:
Kotlin
// Call placed through a work phone account. getCurrentCall() is defined by the // dialer. val call = getCurrentCall() if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) { // Set briefcase icon }
Java
// Call placed through a work phone account. getCurrentCall() is defined by the // dialer. Call call = getCurrentCall(); if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) { // Set briefcase icon }