Auf Geräten mit Android 8.0 (API-Ebene 26) und höher wird beim Koppeln von Companion-Geräten im Namen Ihrer App ein Bluetooth- oder WLAN-Scan der Geräte in der Nähe durchgeführt, ohne dass die Berechtigung ACCESS_FINE_LOCATION
erforderlich ist. So wird der Datenschutz für Nutzer maximiert. Verwenden Sie diese Methode, um das zugehörige Gerät wie eine BLE-fähige Smartwatch zu konfigurieren. Außerdem müssen die Standortdienste für das Koppeln mit einem Companion-Gerät aktiviert sein.
Die Kopplung mit einem Companion-Gerät stellt keine Verbindungen von selbst her und aktiviert auch nicht das kontinuierliche Scannen. Apps können Bluetooth- oder WLAN-Verbindungs-APIs verwenden, um Verbindungen herzustellen.
Nach dem Koppeln kann das Gerät die Berechtigungen REQUEST_COMPANION_RUN_IN_BACKGROUND
und REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
verwenden, um die App im Hintergrund zu starten. Apps können auch die Berechtigung REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND
verwenden, um einen Dienst im Vordergrund aus dem Hintergrund zu starten.
Ein Nutzer kann ein Gerät aus einer Liste auswählen und der App Berechtigungen zum Zugriff auf das Gerät gewähren. Diese Berechtigungen werden widerrufen, wenn Sie die App deinstallieren oder disassociate()
anrufen.
Die Companion-App ist dafür verantwortlich, ihre eigenen Verknüpfungen aufzuheben, wenn der Nutzer sie nicht mehr benötigt, z. B. wenn er sich abmeldet oder verknüpfte Geräte entfernt.
Kopplung mit einem Begleitgerät implementieren
In diesem Abschnitt wird beschrieben, wie Sie mit CompanionDeviceManager
Ihre App über Bluetooth, BLE und WLAN mit Companion-Geräten koppeln.
Begleitgeräte angeben
Das folgende Codebeispiel zeigt, wie Sie das Flag <uses-feature>
in eine Manifestdatei einfügen. Dadurch wird dem System mitgeteilt, dass Ihre App Companion-Geräte einrichten soll.
<uses-feature android:name="android.software.companion_device_setup"/>
Geräte nach DeviceFilter
auflisten
Sie können alle in Reichweite befindlichen Companion-Geräte anzeigen lassen, die mit der von Ihnen angegebenen DeviceFilter
übereinstimmen (siehe Abbildung 1). Wenn Sie das Scannen auf ein einziges Gerät beschränken möchten, können Sie für setSingleDevice()
den Wert true
festlegen (siehe Abbildung 2).
Die folgenden untergeordneten Klassen von DeviceFilter
können in AssociationRequest
angegeben werden:
Alle drei Unterklassen haben Builder, die die Konfiguration von Filtern optimieren.
Im folgenden Beispiel sucht ein Gerät nach einem Bluetooth-Gerät mit einer BluetoothDeviceFilter
.
Kotlin
val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() // Match only Bluetooth devices whose name matches the pattern. .setNamePattern(Pattern.compile("My device")) // Match only Bluetooth devices whose service UUID matches this pattern. .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null) .build()
Java
BluetoothDeviceFilter deviceFilter = new BluetoothDeviceFilter.Builder() // Match only Bluetooth devices whose name matches the pattern. .setNamePattern(Pattern.compile("My device")) // Match only Bluetooth devices whose service UUID matches this pattern. .addServiceUuid(new ParcelUuid(new UUID(0x123abcL, -1L)), null) .build();
Legen Sie ein DeviceFilter
auf ein AssociationRequest
fest, damit CompanionDeviceManager
bestimmen kann, nach welcher Art von Geräten gesucht werden soll.
Kotlin
val pairingRequest: AssociationRequest = AssociationRequest.Builder() // Find only devices that match this request filter. .addDeviceFilter(deviceFilter) // Stop scanning as soon as one device matching the filter is found. .setSingleDevice(true) .build()
Java
AssociationRequest pairingRequest = new AssociationRequest.Builder() // Find only devices that match this request filter. .addDeviceFilter(deviceFilter) // Stop scanning as soon as one device matching the filter is found. .setSingleDevice(true) .build();
Nachdem deine App eine AssociationRequest
initialisiert hat, führe die Funktion associate()
auf der CompanionDeviceManager
aus. Die Funktion associate()
verwendet ein AssociationRequest
- und ein Callback
-Element.
Die Callback
gibt eine IntentSender
in der onAssociationPending
zurück, wenn CompanionDeviceManager
ein Gerät gefunden hat und ein Dialogfeld zur Nutzereinwilligung geöffnet werden kann.
Nachdem der Nutzer das Gerät bestätigt hat, wird in onAssociationCreated
ein AssociationInfo
des Geräts zurückgegeben.
Wenn Ihre App keine Geräte findet, gibt der Rückruf onFailure
mit einer Fehlermeldung zurück.
Auf Geräten mit Android 13 (API-Level 33) und höher:
Kotlin
val deviceManager = requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE) val executor: Executor = Executor { it.run() } deviceManager.associate(pairingRequest, executor, object : CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user // can select the device they want to pair with. override fun onAssociationPending(intentSender: IntentSender) { intentSender?.let { startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) } } override fun onAssociationCreated(associationInfo: AssociationInfo) { // An association is created. } override fun onFailure(errorMessage: CharSequence?) { // To handle the failure. } })
Java
CompanionDeviceManager deviceManager = (CompanionDeviceManager) getSystemService(Context.COMPANION_DEVICE_SERVICE); Executor executor = new Executor() { @Override public void execute(Runnable runnable) { runnable.run(); } }; deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() { executor, // Called when a device is found. Launch the IntentSender so the user can // select the device they want to pair with. @Override public void onDeviceFound(IntentSender chooserLauncher) { try { startIntentSenderForResult( chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0 ); } catch (IntentSender.SendIntentException e) { Log.e("MainActivity", "Failed to send intent"); } } @Override public void onAssociationCreated(AssociationInfo associationInfo) { // An association is created. } @Override public void onFailure(CharSequence errorMessage) { // To handle the failure. });
Auf Geräten mit Android 12L (API-Level 32) oder niedriger (veraltet):
Kotlin
val deviceManager = requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE) deviceManager.associate(pairingRequest, object : CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user // can select the device they want to pair with. override fun onDeviceFound(chooserLauncher: IntentSender) { startIntentSenderForResult(chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) } override fun onFailure(error: CharSequence?) { // To handle the failure. } }, null)
Java
CompanionDeviceManager deviceManager = (CompanionDeviceManager) getSystemService(Context.COMPANION_DEVICE_SERVICE); deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user can // select the device they want to pair with. @Override public void onDeviceFound(IntentSender chooserLauncher) { try { startIntentSenderForResult( chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0 ); } catch (IntentSender.SendIntentException e) { Log.e("MainActivity", "Failed to send intent"); } } @Override public void onFailure(CharSequence error) { // To handle the failure. } }, null);
Das Ergebnis der Nutzerauswahl wird an das Fragment im onActivityResult()
Ihrer Aktivität zurückgesendet. Sie können dann auf das ausgewählte Gerät zugreifen.
Wenn der Nutzer ein Bluetooth-Gerät auswählt, wird ein BluetoothDevice
angezeigt.
Wenn der Nutzer ein Bluetooth LE-Gerät auswählt, wird android.bluetooth.le.ScanResult
angezeigt.
Wenn der Nutzer ein WLAN-Gerät auswählt, wird eine android.net.wifi.ScanResult
angezeigt.
Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { SELECT_DEVICE_REQUEST_CODE -> when(resultCode) { Activity.RESULT_OK -> { // The user chose to pair the app with a Bluetooth device. val deviceToPair: BluetoothDevice? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) deviceToPair?.let { device -> device.createBond() // Continue to interact with the paired device. } } } else -> super.onActivityResult(requestCode, resultCode, data) } }
Java
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (resultCode != Activity.RESULT_OK) { return; } if (requestCode == SELECT_DEVICE_REQUEST_CODE && data != null) { BluetoothDevice deviceToPair = data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE); if (deviceToPair != null) { deviceToPair.createBond(); // Continue to interact with the paired device. } } else { super.onActivityResult(requestCode, resultCode, data); } }
Sehen Sie sich das vollständige Beispiel an:
Auf Geräten mit Android 13 (API-Level 33) und höher:
Kotlin
private const val SELECT_DEVICE_REQUEST_CODE = 0 class MainActivity : AppCompatActivity() { private val deviceManager: CompanionDeviceManager by lazy { getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager } val mBluetoothAdapter: BluetoothAdapter by lazy { val java = BluetoothManager::class.java getSystemService(java)!!.adapter } val executor: Executor = Executor { it.run() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // To skip filters based on names and supported feature flags (UUIDs), // omit calls to setNamePattern() and addServiceUuid() // respectively, as shown in the following Bluetooth example. val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() .setNamePattern(Pattern.compile("My device")) .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null) .build() // The argument provided in setSingleDevice() determines whether a single // device name or a list of them appears. val pairingRequest: AssociationRequest = AssociationRequest.Builder() .addDeviceFilter(deviceFilter) .setSingleDevice(true) .build() // When the app tries to pair with a Bluetooth device, show the // corresponding dialog box to the user. deviceManager.associate(pairingRequest, executor, object : CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user // can select the device they want to pair with. override fun onAssociationPending(intentSender: IntentSender) { intentSender?.let { startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) } } override fun onAssociationCreated(associationInfo: AssociationInfo) { // AssociationInfo object is created and get association id and the // macAddress. var associationId: int = associationInfo.id var macAddress: MacAddress = associationInfo.deviceMacAddress } override fun onFailure(errorMessage: CharSequence?) { // Handle the failure. } ) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { SELECT_DEVICE_REQUEST_CODE -> when(resultCode) { Activity.RESULT_OK -> { // The user chose to pair the app with a Bluetooth device. val deviceToPair: BluetoothDevice? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) deviceToPair?.let { device -> device.createBond() // Maintain continuous interaction with a paired device. } } } else -> super.onActivityResult(requestCode, resultCode, data) } } }
Java
class MainActivityJava extends AppCompatActivity { private static final int SELECT_DEVICE_REQUEST_CODE = 0; Executor executor = new Executor() { @Override public void execute(Runnable runnable) { runnable.run(); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CompanionDeviceManager deviceManager = (CompanionDeviceManager) getSystemService( Context.COMPANION_DEVICE_SERVICE ); // To skip filtering based on name and supported feature flags, // do not include calls to setNamePattern() and addServiceUuid(), // respectively. This example uses Bluetooth. BluetoothDeviceFilter deviceFilter = new BluetoothDeviceFilter.Builder() .setNamePattern(Pattern.compile("My device")) .addServiceUuid( new ParcelUuid(new UUID(0x123abcL, -1L)), null ) .build(); // The argument provided in setSingleDevice() determines whether a single // device name or a list of device names is presented to the user as // pairing options. AssociationRequest pairingRequest = new AssociationRequest.Builder() .addDeviceFilter(deviceFilter) .setSingleDevice(true) .build(); // When the app tries to pair with the Bluetooth device, show the // appropriate pairing request dialog to the user. deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() { executor, // Called when a device is found. Launch the IntentSender so the user can // select the device they want to pair with. @Override public void onDeviceFound(IntentSender chooserLauncher) { try { startIntentSenderForResult( chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0 ); } catch (IntentSender.SendIntentException e) { Log.e("MainActivity", "Failed to send intent"); } } @Override public void onAssociationCreated(AssociationInfo associationInfo) { // AssociationInfo object is created and get association id and the // macAddress. int associationId = associationInfo.getId(); MacAddress macAddress = associationInfo.getDeviceMacAddress(); } @Override public void onFailure(CharSequence errorMessage) { // Handle the failure. }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (resultCode != Activity.RESULT_OK) { return; } if (requestCode == SELECT_DEVICE_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK && data != null) { BluetoothDevice deviceToPair = data.getParcelableExtra( CompanionDeviceManager.EXTRA_DEVICE ); if (deviceToPair != null) { deviceToPair.createBond(); // ... Continue interacting with the paired device. } } } else { super.onActivityResult(requestCode, resultCode, data); } } }
Auf Geräten mit Android 12L (API-Level 32) oder niedriger (veraltet):
Kotlin
private const val SELECT_DEVICE_REQUEST_CODE = 0 class MainActivity : AppCompatActivity() { private val deviceManager: CompanionDeviceManager by lazy { getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // To skip filters based on names and supported feature flags (UUIDs), // omit calls to setNamePattern() and addServiceUuid() // respectively, as shown in the following Bluetooth example. val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() .setNamePattern(Pattern.compile("My device")) .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null) .build() // The argument provided in setSingleDevice() determines whether a single // device name or a list of them appears. val pairingRequest: AssociationRequest = AssociationRequest.Builder() .addDeviceFilter(deviceFilter) .setSingleDevice(true) .build() // When the app tries to pair with a Bluetooth device, show the // corresponding dialog box to the user. deviceManager.associate(pairingRequest, object : CompanionDeviceManager.Callback() { override fun onDeviceFound(chooserLauncher: IntentSender) { startIntentSenderForResult(chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) } override fun onFailure(error: CharSequence?) { // Handle the failure. } }, null) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { SELECT_DEVICE_REQUEST_CODE -> when(resultCode) { Activity.RESULT_OK -> { // The user chose to pair the app with a Bluetooth device. val deviceToPair: BluetoothDevice? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) deviceToPair?.let { device -> device.createBond() // Maintain continuous interaction with a paired device. } } } else -> super.onActivityResult(requestCode, resultCode, data) } } }
Java
class MainActivityJava extends AppCompatActivity { private static final int SELECT_DEVICE_REQUEST_CODE = 0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CompanionDeviceManager deviceManager = (CompanionDeviceManager) getSystemService( Context.COMPANION_DEVICE_SERVICE ); // To skip filtering based on name and supported feature flags, // don't include calls to setNamePattern() and addServiceUuid(), // respectively. This example uses Bluetooth. BluetoothDeviceFilter deviceFilter = new BluetoothDeviceFilter.Builder() .setNamePattern(Pattern.compile("My device")) .addServiceUuid( new ParcelUuid(new UUID(0x123abcL, -1L)), null ) .build(); // The argument provided in setSingleDevice() determines whether a single // device name or a list of device names is presented to the user as // pairing options. AssociationRequest pairingRequest = new AssociationRequest.Builder() .addDeviceFilter(deviceFilter) .setSingleDevice(true) .build(); // When the app tries to pair with the Bluetooth device, show the // appropriate pairing request dialog to the user. deviceManager.associate(pairingRequest, new CompanionDeviceManager.Callback() { @Override public void onDeviceFound(IntentSender chooserLauncher) { try { startIntentSenderForResult(chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { // failed to send the intent } } @Override public void onFailure(CharSequence error) { // handle failure to find the companion device } }, null); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == SELECT_DEVICE_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK && data != null) { BluetoothDevice deviceToPair = data.getParcelableExtra( CompanionDeviceManager.EXTRA_DEVICE ); if (deviceToPair != null) { deviceToPair.createBond(); // ... Continue interacting with the paired device. } } } else { super.onActivityResult(requestCode, resultCode, data); } } }
Begleitgeräteprofile
Unter Android 12 (API-Level 31) und höher können Companion-Apps, die Geräte wie Smartwatches verwalten, Companion-Geräteprofile verwenden, um den Einrichtungsprozess zu vereinfachen, indem beim Koppeln die erforderlichen Berechtigungen gewährt werden. Weitere Informationen finden Sie unter Profile für Companion-Geräte.
Companion-Apps aktiv halten
Unter Android 12 (API-Level 31) und höher können Sie zusätzliche APIs verwenden, damit Ihre Companion-App weiter ausgeführt wird, solange sich ein Companion-Gerät in Reichweite befindet. Mit diesen APIs haben Sie folgende Möglichkeiten:
Ihre App wird aktiviert, wenn sich ein Companion-Gerät in Reichweite befindet.
Weitere Informationen finden Sie unter
CompanionDeviceManager.startObservingDevicePresence()
.Sorgen dafür, dass ein App-Prozess so lange ausgeführt wird, wie sich das Companion-Gerät in Reichweite befindet.
Weitere Informationen finden Sie unter
CompanionDeviceService.onDeviceAppeared()
.