Di perangkat yang menjalankan Android 8.0 (API level 26) dan yang lebih tinggi, penyambungan
perangkat pendamping melakukan pemindaian Bluetooth atau Wi-Fi perangkat di sekitar atas nama
aplikasi Anda tanpa memerlukan
izin
ACCESS_FINE_LOCATION
. Hal ini membantu memaksimalkan perlindungan privasi pengguna. Setelah perangkat
disambungkan, perangkat dapat memanfaatkan izin
REQUEST_COMPANION_RUN_IN_BACKGROUND
dan
REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
untuk memulai aplikasi dari latar belakang. Gunakan metode ini untuk melakukan
konfigurasi awal perangkat pendamping, seperti smartwatch
yang mendukung BLE. Selain itu, penyambungan perangkat pendamping mengharuskan Layanan Lokasi
diaktifkan.
Penyambungan perangkat pendamping tidak membuat koneksi dengan sendirinya. API konektivitas Bluetooth dan Wi-Fi membuat koneksi. Penyambungan perangkat pendamping juga tidak memungkinkan pemindaian berkelanjutan.
Pengguna dapat memilih perangkat dari daftar dan memberikan izin untuk mengakses aplikasi.
Izin ini akan dicabut jika Anda meng-uninstal aplikasi atau memanggil
disassociate()
.
Aplikasi bertanggung jawab untuk menghapus asosiasinya sendiri jika pengguna tidak lagi
memerlukannya, seperti saat mereka logout atau menghapus perangkat terikat.
Mengimplementasikan penyambungan perangkat pendamping
Untuk membuat dan mengelola koneksi ke perangkat pendamping, gunakan
CompanionDeviceManager
.
Bagian ini menjelaskan cara menyesuaikan dialog permintaan penyambungan saat Anda menyambungkan
aplikasi dengan perangkat pendamping melalui Bluetooth, BLE, dan Wi-Fi.
Menentukan perangkat pendamping
Contoh kode berikut menunjukkan cara menambahkan
flag <uses-feature>
ke
file manifes. Kode ini memberi tahu sistem bahwa aplikasi Anda bermaksud menyiapkan perangkat
pendamping.
<uses-feature android:name="android.software.companion_device_setup"/>
Membuat daftar perangkat berdasarkan jenis
Anda dapat menampilkan semua kemungkinan perangkat pendamping yang tersedia dan cocok dengan filter
yang Anda berikan, atau membatasi tampilan ke satu opsi (ditunjukkan pada gambar 1). Anda
mengonfigurasinya dengan membuat filter yang menentukan jenis perangkat yang
dicari aplikasi Anda atau dengan menyetel
setSingleDevice()
ke true
(ditunjukkan pada gambar 2).
Untuk menerapkan filter ke daftar perangkat pendamping yang muncul dalam dialog
permintaan, periksa apakah Bluetooth aktif
atau periksa apakah Wi-Fi
aktif.
Setelah koneksi diaktifkan, Anda dapat menambahkan
DeviceFilter
. Subclass DeviceFilter
berikut menentukan jenis perangkat yang dapat dikaitkan dengan aplikasi Anda berdasarkan jenis koneksi:
Ketiga subclass memiliki builder yang menyederhanakan konfigurasi filter.
Pada contoh berikut, perangkat memindai perangkat Bluetooth dengan
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();
Setel DeviceFilter
ke
AssociationRequest
sehingga
pengelola perangkat dapat menentukan jenis perangkat yang akan dicari.
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();
Setelah Anda melakukan inisialisasi AssociationRequest
, jalankan
fungsi associate()
di CompanionDeviceManager
. Fungsi associate()
menggunakan callback dan objek permintaan penyambungan. Callback menunjukkan saat aplikasi menemukan
perangkat dan siap meluncurkan kotak dialog bagi pengguna untuk memasukkan pilihan mereka.
Jika aplikasi tidak menemukan perangkat, callback akan menampilkan pesan error.
Di perangkat yang menjalankan Android 13 (level API 33) dan yang lebih baru:
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) { // The association is created. } override fun onFailure(errorMessage: CharSequence?) { // 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) { // The association is created. } @Override public void onFailure(CharSequence errorMessage) { // Handle the failure. });
Di perangkat yang menjalankan Android 12L (API level 32) dan yang lebih lama (tidak digunakan lagi):
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?) { // 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) { // Handle the failure. } }, null);
Untuk memungkinkan pengguna memilih jenis perangkat yang ingin mereka hubungkan, mulai
aktivitas preferensi dengan parameter intentSender
dalam fungsi onAssociationPending()
. Hasil tindakan ini akan dikirim kembali ke fragmen dalam
fungsi onActivityResult()
aktivitas preferensi Anda. Ini akan memberi tahu Anda saat pengguna membuat
pemilihan berdasarkan hasil. Kemudian Anda dapat mengakses perangkat yang dipilih. Saat
pengguna memilih perangkat Bluetooth, hasil yang dikirim adalah
objek BluetoothDevice
.
Demikian pula, saat fungsi onAssociationPending()
mendeteksi bahwa pengguna memilih
perangkat Bluetooth LE, terima
objek
android.bluetooth.le.ScanResult
. Untuk perangkat Wi-Fi, terima
objek android.net.wifi.ScanResult
.
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); } }
Untuk menerapkan penyambungan perangkat pendamping dengan filter yang dapat menentukan perangkat dan mencantumkannya berdasarkan jenis, lihat contoh berikut:
Di perangkat yang menjalankan Android 13 (level API 33) dan yang lebih baru:
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); } } }
Di perangkat yang menjalankan Android 12L (API level 32) dan yang lebih lama (tidak digunakan lagi):
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); } } }
Profil perangkat pendamping
Aplikasi partner di Android 12 (API level 31) dan yang lebih baru dapat menggunakan profil perangkat pendamping saat terhubung ke smartwatch. Untuk mengetahui informasi selengkapnya, lihat panduan untuk meminta izin di Wear OS.
Menjaga aplikasi pendamping tetap aktif
Di Android 12 (level API 31) dan yang lebih tinggi, Anda dapat menggunakan API tambahan yang membantu aplikasi pendamping tetap berjalan saat perangkat pendamping berada dalam jangkauan. API ini memungkinkan Anda melakukan hal berikut:
Mengaktifkan aplikasi saat perangkat pendamping berada dalam jangkauan.
Untuk detailnya, lihat
CompanionDeviceManager.startObservingDevicePresence()
.Menjamin bahwa proses aplikasi akan terus berjalan selama perangkat pendamping tetap dalam jangkauan.
Untuk detailnya, lihat
CompanionDeviceService.onDeviceAppeared()
.