Ringkasan Bluetooth

Platform Android menyertakan dukungan untuk tumpukan jaringan Bluetooth, sehingga perangkat bisa bertukar data secara nirkabel dengan perangkat Bluetooth lainnya. Framework aplikasi menyediakan akses ke fungsionalitas Bluetooth melalui Android Bluetooth API. API-API ini mengizinkan aplikasi secara nirkabel terhubung ke perangkat Bluetooth lainnya, mengaktifkan fitur nirkabel point-to-point dan multipoint.

Dengan menggunakan Bluetooth API, aplikasi Android bisa melakukan hal berikut:

  • Memindai perangkat Bluetooth lain
  • Melakukan kueri adaptor Bluetooth lokal untuk perangkat Bluetooth yang disandingkan
  • Membangun saluran RFCOMM
  • Terhubung ke perangkat lain melalui pencarian layanan
  • Mentransfer data ke dan dari perangkat lain
  • Mengelola beberapa koneksi

Halaman ini berfokus pada Bluetooth Klasik. Bluetooth Klasik adalah pilihan yang tepat untuk operasi yang menggunakan baterai lebih intensif seperti streaming dan komunikasi antar perangkat Android. Untuk perangkat Bluetooth dengan kebutuhan daya yang rendah, Android 4.3 (API Level 18) memperkenalkan dukungan API untuk Bluetooth Low Energy. Untuk mengetahui selengkapnya, lihat Bluetooth Low Energy.

Dokumen ini menjelaskan profil Bluetooth yang berbeda, termasuk Health Device Profile. Dokumen ini menjelaskan cara menggunakan Android Bluetooth API untuk menyelesaikan empat tugas utama yang diperlukan untuk berkomunikasi menggunakan Bluetooth: setelan Bluetooth, menemukan perangkat yang akan disandingkan atau tersedia dalam area lokal, menghubungkan perangkat, dan mentransfer data antar perangkat.

Dasar-dasar

Agar perangkat Bluetooth-aktif mengirimkan data antara satu sama lain, perangkat tersebut harus membentuk saluran komunikasi menggunakan proses penyambungan terlebih dahulu. Satu perangkat, perangkat yang dapat ditemukan, membuatnya tersedia untuk permintaan koneksi yang masuk. Perangkat lain menemukan perangkat yang dapat ditemukan menggunakan proses pencarian layanan. Setelah perangkat yang dapat ditemukan menerima permintaan penyambungan, dua perangkat tersebut menyelesaikan proses ikatan yang mereka tukar kunci keamanannya. Perangkat melakukan cache pada kunci ini untuk digunakan nanti. Setelah proses penyambungan dan ikatan selesai, dua perangkat tersebut bertukar informasi. Bila sesi ini selesai, perangkat yang memulai permintaan penyambungan melepaskan saluran yang telah menautkannya ke perangkat yang dapat ditemukan. Namun, dua perangkat tersebut tetap terikat, sehingga mereka dapat terhubung kembali secara otomatis selama sesi selanjutnya selama berada dalam jangkauan satu sama lain dan tidak ada perangkat yang melepaskan ikatannya.

Izin Bluetooth

Untuk menggunakan fitur Bluetooth dalam aplikasi Anda, Anda harus mendeklarasikan dua izin. Yang pertama adalah BLUETOOTH. Anda memerlukan izin ini untuk melakukan komunikasi Bluetooth, seperti meminta koneksi, menerima koneksi, dan mentransfer data.

Izin lain yang harus Anda deklarasikan adalah ACCESS_FINE_LOCATION. Aplikasi Anda memerlukan izin ini karena pemindaian Bluetooth dapat digunakan untuk mengumpulkan informasi tentang lokasi pengguna. Informasi ini bisa didapatkan dari perangkat pengguna sendiri, serta beacon Bluetooth yang digunakan di lokasi seperti toko dan fasilitas transit.

Catatan: Jika aplikasi Anda menargetkan Android 9 (API level 28) atau yang lebih rendah, Anda dapat mendeklarasikan izin ACCESS_COARSE_LOCATION alih-alih izin ACCESS_FINE_LOCATION.

Jika Anda ingin aplikasi memulai pencarian perangkat atau memanipulasi setelan Bluetooth, Anda juga harus mendeklarasikan izin BLUETOOTH_ADMIN selain izin BLUETOOTH. Sebagian besar aplikasi membutuhkan izin ini agar memiliki kemampuan untuk menemukan perangkat Bluetooth lokal. Kemampuan lain yang diberikan oleh izin ini sebaiknya tidak digunakan, kecuali aplikasi tersebut adalah "power manager" yang akan mengubah setelan Bluetooth atas permintaan pengguna.

Mendeklarasikan izin Bluetooth dalam file manifes aplikasi Anda. Sebagai contoh:

<manifest ... >
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

  <!-- If your app targets Android 9 or lower, you can declare
       ACCESS_COARSE_LOCATION instead. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  ...
</manifest>

Lihat referensi <uses-permission> untuk informasi selengkapnya tentang mendeklarasikan izin aplikasi.

Berkeja dengan profil

Mulai dari Android 3.0, Bluetooth API menyertakan dukungan untuk bekerja dengan profil Bluetooth. Profil Bluetooth adalah spesifikasi antarmuka nirkabel untuk komunikasi berbasis-Bluetooth antar perangkat. Contohnya adalah profil Hands-Free. Agar ponsel bisa terhubung ke headset nirkabel, kedua perangkat harus mendukung profil Hands-Free.

Android Bluetooth API menyediakan implementasi untuk profil Bluetooth berikut:

  • Headset. Profil Headset menyediakan dukungan untuk headset Bluetooth yang akan digunakan dengan ponsel. Android menyediakan class BluetoothHeadset, yang merupakan proxy untuk mengontrol Layanan Bluetooth Headset. Ini berisi profil Bluetooth Headset dan Hands-Free (v1.5). Class BluetoothHeadset menyertakan dukungan untuk perintah AT. Untuk pembahasan selengkapnya tentang topik ini, lihat Perintah AT khusus-Vendor
  • A2DP. Advanced Audio Distribution Profile (A2DP) mendefinisikan bagaimana audio berkualitas tinggi bisa dialirkan dari satu perangkat ke perangkat lainnya melalui koneksi Bluetooth. Android menyediakan class BluetoothA2dp, yang merupakan proxy untuk mengontrol Layanan Bluetooth A2DP.
  • Health Device. Android 4.0 (API level 14) memperkenalkan dukungan untuk Bluetooth Health Device Profile (HDP). Ini memungkinkan Anda membuat aplikasi yang menggunakan Bluetooth untuk berkomunikasi dengan perangkat kesehatan yang mendukung Bluetooth, seperti pemantau denyut jantung, tekanan darah, termometer, timbangan, dan sebagainya. Untuk daftar perangkat yang didukung dan kode khusus data perangkat yang sesuai, silakan lihat Spesialisasi Data Perangkat HDP Bluetooth. Perhatikan bahwa nilai-nilai ini juga direferensikan pada spesifikasi ISO/IEEE 11073-20601 [7] seperti MDC_DEV_SPEC_PROFILE_* dalam Nomenclature Codes Annex. Untuk pembahasan selengkapnya tentang HDP, lihat Health Device Profile.

Berikut adalah langkah-langkah dasar untuk bekerja dengan profil:

  1. Dapatkan adaptor default, seperti yang dijelaskan dalam Menyiapkan Bluetooth.
  2. Menyiapkan BluetoothProfile.ServiceListener. Listener ini memberi tahu klien BluetoothProfile ketika mereka telah terhubung atau terputus dari layanan.
  3. Gunakan getProfileProxy() untuk membuat sambungan ke objek proxy profil yang terkait dengan profil. Pada contoh di bawah ini, objek proxy profil merupakan instance dari BluetoothHeadset.
  4. Dalam onServiceConnected(), dapatkan penanganan untuk objek proxy profil.
  5. Setelah Anda memiliki objek proxy profil, Anda bisa menggunakannya untuk memantau status koneksi dan melakukan operasi lain yang relevan dengan profil tersebut.

Misalnya, cuplikan kode ini menunjukkan cara melakukan koneksi ke objek proxy BluetoothHeadset sehingga Anda bisa mengontrol profil Headset:

Kotlin

var bluetoothHeadset: BluetoothHeadset? = null

// Get the default adapter
val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()

private val profileListener = object : BluetoothProfile.ServiceListener {

    override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = proxy as BluetoothHeadset
        }
    }

    override fun onServiceDisconnected(profile: Int) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = null
        }
    }
}

// Establish connection to the proxy.
bluetoothAdapter?.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET)

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter?.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset)

Java

BluetoothHeadset bluetoothHeadset;

// Get the default adapter
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

private BluetoothProfile.ServiceListener profileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            bluetoothHeadset = null;
        }
    }
};

// Establish connection to the proxy.
bluetoothAdapter.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET);

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter.closeProfileProxy(bluetoothHeadset);

Perintah AT khusus-vendor

Mulai Android 3.0 (API level 11), aplikasi bisa mendaftar untuk menerima siaran sistem dari perintah AT khusus-vendor yang telah didefinisikan yang dikirimkan oleh headset (seperti perintah Plantronics +XEVENT). Misalnya, sebuah aplikasi bisa menerima siaran yang menunjukkan tingkat baterai perangkat yang terhubung dan dapat memberi tahu pengguna atau melakukan aksi lain bila perlu. Membuat penerima siaran bagi intent ACTION_VENDOR_SPECIFIC_HEADSET_EVENT untuk menangani perintah AT khusus-vendor untuk headset.

Profil perangkat kesehatan

Android 4.0 (API level 14) memperkenalkan dukungan untuk Bluetooth Health Device Profile (HDP). Ini memungkinkan Anda membuat aplikasi yang menggunakan Bluetooth untuk berkomunikasi dengan perangkat kesehatan yang mendukung Bluetooth, seperti pemantau denyut-jantung, tekanan darah, termometer, dan timbangan. Bluetooth Health API berisi class BluetoothHealth, BluetoothHealthCallback, dan BluetoothHealthAppConfiguration, yang dijelaskan dalam Antarmuka dan Class Utama.

Dalam menggunakan Bluetooth Health API, akan sangat membantu jika memahami konsep-konsep penting HDP:

Sumber
Perangkat kesehatan—seperti timbangan, pengukur glukosa, atau termometer—yang mentransmisi data medis ke perangkat cerdas, seperti ponsel atau tablet Android.
Sink
Perangkat cerdas yang menerima data medis. Dalam aplikasi HDP Android, sink dinyatakan oleh objek BluetoothHealthAppConfiguration.
Pendaftaran
Proses yang digunakan untuk mendaftarkan sink untuk berkomunikasi dengan perangkat kesehatan tertentu.
Koneksi
Proses yang digunakan untuk membuka saluran antara perangkat kesehatan (sumber) dan perangkat cerdas (sink).

Membuat aplikasi HDP

Berikut adalah langkah-langkah dasar yang harus dilakukan untuk membuat aplikasi HDP Android:

  1. Dapatkan referensi ke objek proxy BluetoothHealth.

    Sama seperti headset biasa dan perangkat profil A2DP, Anda harus memanggil getProfileProxy() dengan BluetoothProfile.ServiceListener dan tipe profil HEALTH untuk membangun koneksi dengan objek proxy profil.

  2. Buat BluetoothHealthCallback dan daftarkan konfigurasi aplikasi(BluetoothHealthAppConfiguration) yang bertindak sebagai sink kesehatan.
  3. Membangun koneksi ke perangkat kesehatan.

    Catatan: Beberapa perangkat memulai koneksi secara otomatis. Tidak diperlukan menjalankan langkah ini untuk perangkat tersebut.

  4. Ketika berhasil tersambung ke perangkat kesehatan, baca/tulis ke perangkat kesehatan menggunakan deskriptor file. Data yang diterima perlu diinterpretasikan menggunakan pengelola kesehatan yang mengimplementasikan spesifikasi IEEE 11073.
  5. Setelah selesai, tutup saluran kesehatan dan cabut pendaftaran aplikasi. Saluran ini juga ditutup ketika tidak ada aktivitas dalam waktu lama.

Menyiapkan bluetooth

Sebelum aplikasi Anda bisa berkomunikasi melalui Bluetooth, Anda harus memastikan bahwa Bluetooth didukung pada perangkat, dan jika memang demikian, pastikan bahwa itu diaktifkan.

Jika Bluetooth tidak didukung, maka Anda harus dengan lapang dada menonaktifkan semua fitur Bluetooth. Jika Bluetooth didukung, tapi dinonaktifkan, maka Anda bisa meminta pengguna untuk mengaktifkan Bluetooth tanpa harus menutup aplikasi. Penyiapan ini dilakukan dalam dua langkah, menggunakan BluetoothAdapter.

  1. Dapatkan BluetoothAdapter

    Diperlukan BluetoothAdapter untuk setiap dan semua aktivitas Bluetooth. Untuk mendapatkan BluetoothAdapter, panggil metode statis getDefaultAdapter(). Ini akan mengembalikan BluetoothAdapter yang merepresentasikan adaptor Bluetooth milik perangkat (radio Bluetooth). Ada satu adaptor Bluetooth untuk seluruh sistem, dan aplikasi Anda bisa berinteraksi dengannya menggunakan objek ini. Jika getDefaultAdapter() kembali null, maka perangkat tersebut tidak mendukung Bluetooth. Sebagai contoh:

    Kotlin

    val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
    if (bluetoothAdapter == null) {
        // Device doesn't support Bluetooth
    }
    

    Java

    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        // Device doesn't support Bluetooth
    }
    
  2. Aktifkan Bluetooth.

    Berikutnya, Anda harus memastikan bahwa Bluetooth diaktifkan. Panggil isEnabled() untuk memeriksa apakah Bluetooth saat ini diaktifkan. Jika metode ini kembali ke false, maka Bluetooth dinonaktifkan. Untuk meminta agar Bluetooth diaktifkan, panggil startActivityForResult(), melewati aksi intent ACTION_REQUEST_ENABLE. Panggilan ini akan mengeluarkan permintaan untuk mengaktifkan Bluetooth melalui setelan sistem (tanpa menghentikan aplikasi Anda). Sebagai contoh:

    Kotlin

    if (bluetoothAdapter?.isEnabled == false) {
        val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
    }
    

    Java

    if (!bluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }
    

    Sebuah dialog akan muncul meminta izin pengguna untuk mengaktifkan Bluetooth, seperti ditunjukkan pada Gambar 1. Jika pengguna menjawab "Yes," sistem akan mulai mengaktifkan Bluetooth dan fokus akan kembali ke aplikasi Anda setelah proses selesai (atau gagal).

    Gambar 1: Mengaktifkan dialog Bluetooth.

    Konstanta REQUEST_ENABLE_BT yang diteruskan ke startActivityForResult() adalah integer yang didefinisikan secara lokal, yang harus lebih besar dari 0. Sistem mengembalikan konstanta ini kepada Anda dalam implementasi onActivityResult() sebagai parameter requestCode.

    Jika berhasil mengaktifkan Bluetooth, aktivitas Anda akan menerima kode hasil RESULT_OK dalam callback onActivityResult(). Jika Bluetooth tidak diaktifkan karena kesalahan (atau karena pengguna menjawab "No") maka kode hasilnya adalah RESULT_CANCELED.

Atau, aplikasi Anda juga bisa mendengarkan intent siaran ACTION_STATE_CHANGED, yang disiarkan sistem setiap kali status Bluetooth berubah. Siaran ini berisi bidang tambahan EXTRA_STATE dan EXTRA_PREVIOUS_STATE, yang berisi status Bluetooth baru dan lama. Kemungkinan nilai untuk bidang-bidang tambahan ini adalah STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, dan STATE_OFF. Mendengarkan siaran ini bisa bermanfaat jika aplikasi Anda perlu mendeteksi perubahan runtime yang dilakukan pada status Bluetooth.

Tips: Mengaktifkan kemampuan untuk dapat ditemukan secara otomatis aktifkan Bluetooth. Jika Anda berencana untuk selalu mengaktifkan kemampuan untuk dapat ditemukan perangkat sebelum melakukan aktivitas Bluetooth, Anda bisa melewati langkah 2 di atas. Untuk informasi selengkapnya, baca mengaktifkan visibilitas, bagian di halaman ini.

Mencari perangkat

Dengan menggunakan BluetoothAdapter, Anda bisa menemukan perangkat Bluetooth jarak jauh melalui pencarian perangkat atau dengan kueri daftar perangkat yang disambungkan (diikat).

Pencarian perangkat adalah prosedur pemindaian yang mencari area lokal untuk perangkat Bluetooth-aktif dan meminta beberapa informasi tentang setiap perangkat. Proses ini terkadang disebut sebagai menemukan, menanyakan, atau memindai. Akan tetapi, perangkat Bluetooth terdekat merespons permintaan penemuan hanya jika perangkat tersebut menerima permintaan informasi dengan menjadi dapat ditemukan. Jika dapat ditemukan, perangkat tersebut akan merespons permintaan penemuan dengan berbagi beberapa informasi, seperti nama perangkat, class, dan alamat MAC yang unik. Menggunakan informasi ini, perangkat yang menjalankan pencarian bisa memilih untuk memulai koneksi ke perangkat yang ditemukan.

Setelah koneksi dibuat dengan perangkat jauh untuk pertama kalinya, permintaan penyambungan secara otomatis ditampilkan ke pengguna. Ketika perangkat disambungkan, informasi dasar tentang perangkat tersebut—seperti nama perangkat, class, dan alamat MAC—akan disimpan dan bisa dibaca dengan menggunakan Bluetooth API. Menggunakan alamat MAC yang dikenal untuk perangkat jauh, koneksi bisa dimulai dengan perangkat tersebut setiap saat tanpa menjalankan pencarian, dengan asumsi perangkat berada dalam jangkauan.

Ingat bahwa ada perbedaan antara yang disambungkan dan yang dihubungkan:

  • Disambungkan artinya dua perangkat saling menyadari keberadaan masing-masing, memiliki kunci-tautan bersama yang bisa digunakan untuk autentikasi, dan dapat membangun koneksi terenkripsi satu sama lain.
  • Dihubungkan artinya perangkat saat ini berbagi saluran RFCOMM dan bisa saling berkiriman data. Android Bluetooth API saat ini membutuhkan perangkat untuk disambungkan sebelum koneksi RFCOMM dapat dibuat. Penyambungan secara otomatis dilakukan ketika Anda memulai koneksi terenkripsi dengan Bluetooth API.

Bagian berikut menjelaskan cara menemukan perangkat yang telah disambungkan, atau menemukan perangkat baru menggunakan pencarian perangkat.

Catatan: Perangkat Android tidak dapat ditemukan secara default. Pengguna bisa membuat perangkat dapat ditemukan untuk jangka waktu terbatas melalui setelan sistem, atau aplikasi bisa meminta pengguna mengaktifkan kemampuan untuk dapat ditemukan tanpa meninggalkan aplikasi. Untuk informasi selengkapnya, lihat bagian aktifkan visibilitas di halaman ini.

Melakukan kueri perangkat yang disambungkan

Sebelum melakukan pencarian perangkat, ada baiknya melakukan kueri kumpulan perangkat yang disambungkan untuk melihat jika perangkat yang diinginkan sudah dikenal. Untuk melakukannya, panggil getBondedDevices(). Hal ini mengembalikan set objek BluetoothDevice yang mewakili perangkat yang disambungkan. Misalnya, Anda bisa melakukan kueri pada semua perangkat yang disambungkan dan mendapatkan nama dan alamat MAC setiap perangkat, seperti yang ditunjukkan cuplikan kode berikut:

Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
    val deviceName = device.name
    val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
    // There are paired devices. Get the name and address of each paired device.
    for (BluetoothDevice device : pairedDevices) {
        String deviceName = device.getName();
        String deviceHardwareAddress = device.getAddress(); // MAC address
    }
}

Untuk memulai koneksi dengan perangkat Bluetooth, yang dibutuhkan dari objek BluetoothDevice terkait adalah alamat MAC, yang Anda dapatkan dengan memanggil getAddress(). Anda bisa mempelajari selengkapnya tentang membuat koneksi dalam bagian tentang Menghubungkan Perangkat.

Perhatian: Melakukan pencarian perangkat memakai banyak resource adaptor Bluetooth. Setelah menemukan perangkat yang akan dihubungkan, pastikan Anda selalu menghentikan pencarian dengan cancelDiscovery() sebelum melakukan koneksi. Selain itu, Anda tidak boleh melakukan pencarian saat terhubung dengan suatu perangkat karena proses pencarian secara signifikan mengurangi bandwidth yang tersedia untuk koneksi yang ada.

Menemukan perangkat

Untuk mulai menemukan perangkat, cukup panggil startDiscovery(). Proses tersebut tidak bersamaan dan mengembalikan nilai boolean yang mengindikasikan apakah pencarian berhasil dimulai. Proses pencarian biasanya melibatkan pemindaian pemeriksaan sekitar 12 detik, diikuti dengan pemindaian laman dari setiap perangkat yang ditemukan untuk mengambil nama Bluetooth-nya.

Aplikasi Anda harus mendaftar BroadcastReceiver untuk intent ACTION_FOUND agar bisa menerima informasi tentang setiap perangkat yang ditemukan. Sistem menyiarkan intent ini untuk setiap perangkat. Intent berisi bidang tambahan EXTRA_DEVICE dan EXTRA_CLASS, yang selanjutnya berisi BluetoothDevice dan BluetoothClass, masing-masing. Cuplikan kode berikut menunjukkan bagaimana Anda mendaftar untuk menangani siaran ketika perangkat ditemukan:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    // Register for broadcasts when a device is discovered.
    val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
    registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val action: String = intent.action
        when(action) {
            BluetoothDevice.ACTION_FOUND -> {
                // Discovery has found a device. Get the BluetoothDevice
                // object and its info from the Intent.
                val device: BluetoothDevice =
                        intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                val deviceName = device.name
                val deviceHardwareAddress = device.address // MAC address
            }
        }
    }
}

override fun onDestroy() {
    super.onDestroy()
    ...

    // Don't forget to unregister the ACTION_FOUND receiver.
    unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    // Register for broadcasts when a device is discovered.
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Discovery has found a device. Get the BluetoothDevice
            // object and its info from the Intent.
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String deviceName = device.getName();
            String deviceHardwareAddress = device.getAddress(); // MAC address
        }
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    ...

    // Don't forget to unregister the ACTION_FOUND receiver.
    unregisterReceiver(receiver);
}

Untuk memulai koneksi dengan perangkat Bluetooth, yang dibutuhkan dari objek BluetoothDevice terkait adalah alamat MAC, yang Anda dapatkan dengan memanggil getAddress(). Anda bisa mempelajari selengkapnya tentang membuat koneksi dalam bagian tentang Menghubungkan Perangkat.

Perhatian: Melakukan pencarian perangkat memakai banyak resource adaptor Bluetooth. Setelah menemukan perangkat yang akan dihubungkan, pastikan Anda selalu menghentikan pencarian dengan cancelDiscovery() sebelum melakukan koneksi. Selain itu, Anda tidak boleh melakukan pencarian saat terhubung dengan suatu perangkat karena proses pencarian secara signifikan mengurangi bandwidth yang tersedia untuk koneksi yang ada.

Aktifkan visibilitas

Jika Anda menginginkan agar perangkat lokal dapat ditemukan oleh perangkat lain, panggil startActivityForResult(Intent, int) dengan intent ACTION_REQUEST_DISCOVERABLE. Hal ini memunculkan permintaan untuk mengaktifkan mode dapat ditemukan pada sistem tanpa harus membuka aplikasi Setelan, yang akan menghentikan aplikasi Anda. Secara default, perangkat menjadi dapat ditemukan selama 120 detik, atau 2 menit. Anda bisa menetapkan durasi yang berbeda, hingga 3600 detik (1 jam), dengan menambahkan EXTRA_DISCOVERABLE_DURATION tambahan.

Perhatian: Jika Anda menyetel nilai tambahan EXTRA_DISCOVERABLE_DURATION menjadi 0, perangkat tersebut akan selalu dapat ditemukan. Konfigurasi ini tidak aman dan oleh karena itu tidak dianjurkan.

Cuplikan kode berikut menyetel perangkat agar dapat ditemukan selama 5 menit (300 detik):

Kotlin

val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
    putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivity(discoverableIntent)

Java

Intent discoverableIntent =
        new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
Gambar 2: Mengaktifkan dialog visibilitas.

Sebuah dialog akan ditampilkan, meminta izin pengguna agar perangkat dapat ditemukan, seperti ditunjukkan pada Gambar 2. Jika pengguna menjawab "Yes," maka perangkat menjadi dapat ditemukan untuk jangka waktu tertentu. Aktivitas Anda kemudian akan menerima panggilan ke callback onActivityResult(), dengan kode hasil yang sama dengan durasi perangkat dapat ditemukan. Jika pengguna menjawab "No" atau terjadi kesalahan, kode hasil akan menjadi RESULT_CANCELED.

Catatan: Jika Bluetooth tidak diaktifkan di perangkat, maka membuat perangkat dapat ditemukan secara otomatis mengaktifkan Bluetooth.

Perangkat tersebut diam-diam akan tetap dalam mode dapat ditemukan untuk waktu yang telah ditentukan. Jika Anda ingin diberi tahu ketika mode dapat ditemukan telah berubah, Anda bisa mendaftarkan BroadcastReceiver ke intent ACTION_SCAN_MODE_CHANGED. Intent ini berisi bidang tambahan EXTRA_SCAN_MODE dan EXTRA_PREVIOUS_SCAN_MODE, yang menyediakan mode pemindaian baru dan lama. Nilai-nilai yang memungkinkan untuk setiap tambahan sebagai berikut:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
Perangkat dalam mode dapat ditemukan.
SCAN_MODE_CONNECTABLE
Perangkat tidak dalam mode dapat ditemukan tapi masih bisa menerima koneksi.
SCAN_MODE_NONE
Perangkat tidak dalam mode dapat ditemukan dan tidak dapat menerima koneksi.

Jika Anda memulai koneksi ke perangkat jarak jauh, Anda tidak perlu mengaktifkan visibilitas perangkat. Mengaktifkan visibilitas hanya diperlukan jika Anda ingin aplikasi Anda menjadi host soket server yang menerima koneksi masuk, karena perangkat jarak jauh harus bisa menemukan perangkat lain sebelum memulai koneksi ke perangkat lain.

Menghubungkan perangkat

Agar bisa membuat koneksi antar aplikasi pada dua perangkat, Anda harus mengimplementasikan mekanisme sisi-server dan sisi-klien, karena salah satu perangkat harus membuka soket server dan yang lainnya harus memulai koneksi menggunakan alamat MAC perangkat server. Perangkat server dan perangkat klien masing-masing memperoleh BluetoothSocket yang diperlukan dengan cara berbeda. Server menerima informasi soket saat koneksi yang masuk diterima. Klien memberikan informasi soket saat membuka saluran RFCOMM ke server.

Server dan klien dianggap terhubung satu sama lain ketika mereka masing-masing memiliki BluetoothSocket yang telah terhubung pada saluran RFCOMM yang sama. Pada tahap ini, setiap perangkat bisa memperoleh aliran masukan dan keluaran serta transfer data dapat dimulai, yang dibahas dalam bagian mengenai Mengelola Koneksi. Bagian ini menjelaskan cara memulai koneksi antara dua perangkat.

Teknik koneksi

Salah satu teknik implementasi adalah dengan secara otomatis mempersiapkan setiap perangkat sebagai server, sehingga masing-masing memiliki soket server yang terbuka dan mendengarkan koneksi. Dalam hal ini, perangkat bisa memulai koneksi dengan yang lainnya dan menjadi klien. Atau, salah satu perangkat bisa secara eksplisit menjadi host koneksi dan membuka soket server sesuai permintaan, dan perangkat lain bisa memulai koneksi.

Gambar 3: Dialog penyambungan Bluetooth.

Catatan: Jika dua perangkat belum disambungkan sebelumnya, maka framework Android secara otomatis akan menampilkan notifikasi permintaan penyambungan atau dialog ke pengguna selama prosedur koneksi, seperti yang ditunjukkan pada Gambar 3. Jadi ketika mencoba untuk menghubungkan perangkat, aplikasi Anda tidak perlu khawatir mengenai apakah perangkat disambungkan atau tidak. Upaya koneksi RFCOMM diblokir hingga pengguna berhasil menyambungkan dua perangkat, dan upaya akan gagal jika pengguna menolak penyambungan, atau jika proses penyambungan gagal atau waktu habis.

Menghubungkan sebagai server

Bila Anda ingin menghubungkan dua perangkat, salah satunya harus bertindak sebagai server dengan menyimpan BluetoothServerSocket terbuka. Tujuan dari soket server adalah untuk mendengarkan permintaan koneksi masuk dan ketika ada yang diterima, menyediakan BluetoothSocket yang terhubung. Ketika BluetoothSocket diperoleh dari BluetoothServerSocket, BluetoothServerSocket bisa—dan sebaiknya— dibuang, kecuali jika Anda ingin menerima lebih banyak koneksi.

Untuk menyiapkan soket server dan menerima koneksi, selesaikan urutan langkah berikut:

  1. Dapatkan BluetoothServerSocket dengan memanggil listenUsingRfcommWithServiceRecord().

    String adalah nama yang bisa diidentifikasi dari layanan Anda, yang akan secara otomatis ditulis sistem ke entri database Service Discovery Protocol (SDP) baru pada perangkat. Namanya bebas dan dapat berupa nama aplikasi. Universally Unique Identifier (UUID) juga dimasukkan dalam entri SDP dan akan menjadi dasar untuk perjanjian koneksi dengan perangkat klien. Artinya, ketika klien mencoba untuk terhubung dengan perangkat ini, itu akan membawa UUID yang secara unik mengidentifikasi layanan dengan yang hendak dihubungkan olehnya. UUID ini harus cocok agar koneksi bisa diterima.

    UUID adalah format 128-bit terstandardisasi untuk ID string yang digunakan untuk mengidentifikasi informasi secara unik. Inti dari UUID adalah bahwa itu cukup besar sehingga Anda bisa memilih ID secara acak dan tidak akan berbenturan. Dalam hal ini, ID digunakan untuk mengidentifikasi secara unik layanan Bluetooth aplikasi Anda. Agar UUID bisa digunakan dengan aplikasi, Anda dapat menggunakan salah satu dari banyak pembuat UUID acak di web, kemudian melakukan inisialisasi UUID dengan fromString(String).

  2. Mulai dengarkan permintaan koneksi dengan memanggil accept().

    Ini adalah panggilan pemblokir. Itu akan dikembalikan bila koneksi sudah diterima atau telah terjadi sebuah pengecualian. Koneksi diterima hanya bila perangkat jauh telah mengirimkan permintaan koneksi dengan UUID yang cocok dengan yang terdaftar pada soket server pendengar. Jika berhasil, accept() mengembalikan BluetoothSocket yang terhubung.

  3. Kecuali Anda ingin menerima koneksi tambahan, panggil close().

    Panggilan metode ini melepaskan soket server dan semua resource, namun tidak menutup BluetoothSocket terhubung yang telah dikembalikan oleh accept(). Tidak seperti TCP/IP, RFCOMM hanya mengizinkan satu klien terhubung per saluran pada satu waktu, sehingga dalam banyak kasus, hal yang wajar memanggil close() pada BluetoothServerSocket langsung setelah menerima soket yang terhubung.

Karena panggilan accept() adalah panggilan pemblokir, panggilan tersebut tidak boleh dijalankan pada thread UI aktivitas utama sehingga aplikasi Anda masih bisa merespons interaksi pengguna lain. Hal yang bisa dimengerti untuk melakukan semua pekerjaan dengan BluetoothServerSocket atau BluetoothSocket di thread baru yang dikelola oleh aplikasi Anda. Untuk membatalkan panggilan yang diblokir seperti accept(), panggil close() pada BluetoothServerSocket atau BluetoothSocket) dari thread lain. Perhatikan bahwa semua metode pada BluetoothServerSocket atau BluetoothSocket adalah thread-safe.

Contoh

Berikut adalah thread yang disederhanakan untuk komponen server yang menerima koneksi masuk:

Kotlin

private inner class AcceptThread : Thread() {
    
    private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) {
        bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID)
    }

    override fun run() {
        // Keep listening until exception occurs or a socket is returned.
        var shouldLoop = true
        while (shouldLoop) {
            val socket: BluetoothSocket? = try {
                mmServerSocket?.accept()
            } catch (e: IOException) {
                Log.e(TAG, "Socket's accept() method failed", e)
                shouldLoop = false
                null
            }
            socket?.also {
                manageMyConnectedSocket(it)
                mmServerSocket?.close()
                shouldLoop = false
            }
        }
    }

    // Closes the connect socket and causes the thread to finish.
    fun cancel() {
        try {
            mmServerSocket?.close()
        } catch (e: IOException) {
            Log.e(TAG, "Could not close the connect socket", e)
        }
    }
}

Java

private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
        // Use a temporary object that is later assigned to mmServerSocket
        // because mmServerSocket is final.
        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code.
            tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's listen() method failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned.
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                Log.e(TAG, "Socket's accept() method failed", e);
                break;
            }

            if (socket != null) {
                // A connection was accepted. Perform work associated with
                // the connection in a separate thread.
                manageMyConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }

    // Closes the connect socket and causes the thread to finish.
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the connect socket", e);
        }
    }
}

Dalam contoh ini, hanya satu koneksi masuk yang dikehendaki, jadi segera setelah koneksi diterima dan BluetoothSocket diperoleh, aplikasi mengirimkan BluetoothSocket yang diperoleh ke thread terpisah, menutup BluetoothServerSocket, dan menghentikan loop.

Perhatikan bahwa saat accept() mengembalikan BluetoothSocket, soket sudah terhubung. Oleh karena itu, Anda seharusnya tidak memanggil connect(), seperti yang Anda lakukan dari sisi klien.

Metode manageMyConnectedSocket() khusus aplikasi didesain untuk memulai thread untuk mengirimkan data, yang dibahas di bagian tentang Mengelola Koneksi.

Anda biasanya harus segera menutup BluetoothServerSocket setelah Anda selesai mendengarkan koneksi masuk. Dalam contoh ini, close() dipanggil segera setelah BluetoothSocket diperoleh. Anda mungkin juga perlu menyediakan metode publik dalam thread yang bisa menutup BluetoothSocket pribadi ketika Anda harus berhenti mendengarkan soket server.

Menghubungkan sebagai klien

Untuk memulai koneksi dengan perangkat jarak jauh yang menerima koneksi pada soket server terbuka, Anda terlebih dahulu harus memperoleh objek BluetoothDevice yang merepresentasikan perangkat jarak jauh. Untuk mempelajari cara membuat BluetoothDevice, lihat Mencari Perangkat. Anda kemudian harus menggunakan BluetoothDevice untuk memperoleh BluetoothSocket dan memulai koneksi.

Prosedur dasarnya sebagai berikut:

  1. Dengan menggunakan BluetoothDevice, dapatkan BluetoothSocket dengan memanggil createRfcommSocketToServiceRecord(UUID).

    Metode memulai objek BluetoothSocket yang memungkinkan klien terhubung ke BluetoothDevice. UUID yang diberikan di sini harus cocok dengan UUID yang digunakan oleh perangkat server ketika memanggil listenUsingRfcommWithServiceRecord(String, UUID) untuk membuka BluetoothServerSocket. Untuk menggunakan UUID yang cocok, lakukan hardcode string UUID ke dalam aplikasi Anda, kemudian referensikan dari server dan kode klien.

  2. Memulai koneksi dengan memanggil connect(). Perlu diingat bahwa metode ini adalah panggilan pemblokir.

    Setelah klien memanggil metode ini, sistem akan melakukan pencarian SDP untuk mencari perangkat jarak jauh dengan UUID yang cocok. Jika pencarian tersebut berhasil dan perangkat jauh menerima koneksi, perangkat tersebut akan berbagi saluran RFCOMM yang akan digunakan selama koneksi dan metode connect() akan kembali. Jika koneksi gagal, atau jika metode connect() waktunya habis (setelah 12 detik), maka metode akan melontarkan IOException.

    Karena connect() adalah panggilan pemblokir, Anda harus selalu melakukan prosedur koneksi ini dalam thread yang terpisah dari thread (UI) aktivitas utama.

    Catatan: Anda harus selalu memanggil cancelDiscovery() untuk memastikan bahwa perangkat tidak melakukan pencarian perangkat sebelum Anda memanggil connect(). Jika pencarian sedang berlangsung, maka upaya koneksi akan jauh lebih lambat dan kemungkinan besar gagal.

Contoh

Berikut ini adalah contoh dasar dari thread klien yang memulai koneksi Bluetooth:

Kotlin

private inner class ConnectThread(device: BluetoothDevice) : Thread() {

    private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
        device.createRfcommSocketToServiceRecord(MY_UUID)
    }

    public override fun run() {
        // Cancel discovery because it otherwise slows down the connection.
        bluetoothAdapter?.cancelDiscovery()

        mmSocket?.use { socket ->
            // Connect to the remote device through the socket. This call blocks
            // until it succeeds or throws an exception.
            socket.connect()

            // The connection attempt succeeded. Perform work associated with
            // the connection in a separate thread.
            manageMyConnectedSocket(socket)
        }
    }

    // Closes the client socket and causes the thread to finish.
    fun cancel() {
        try {
            mmSocket?.close()
        } catch (e: IOException) {
            Log.e(TAG, "Could not close the client socket", e)
        }
    }
}

Java

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket
        // because mmSocket is final.
        BluetoothSocket tmp = null;
        mmDevice = device;

        try {
            // Get a BluetoothSocket to connect with the given BluetoothDevice.
            // MY_UUID is the app's UUID string, also used in the server code.
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's create() method failed", e);
        }
        mmSocket = tmp;
    }

    public void run() {
        // Cancel discovery because it otherwise slows down the connection.
        bluetoothAdapter.cancelDiscovery();

        try {
            // Connect to the remote device through the socket. This call blocks
            // until it succeeds or throws an exception.
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and return.
            try {
                mmSocket.close();
            } catch (IOException closeException) {
                Log.e(TAG, "Could not close the client socket", closeException);
            }
            return;
        }

        // The connection attempt succeeded. Perform work associated with
        // the connection in a separate thread.
        manageMyConnectedSocket(mmSocket);
    }

    // Closes the client socket and causes the thread to finish.
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the client socket", e);
        }
    }
}

Perlu diperhatikan bahwa, dalam cuplikan ini, cancelDiscovery() dipanggil sebelum upaya koneksi dilakukan. Anda harus selalu memanggil cancelDiscovery() sebelum connect(), terutama karena cancelDiscovery() berhasil terlepas dari apakah pencarian perangkat saat ini sedang berlangsung. Namun, jika aplikasi Anda harus menentukan apakah pencarian perangkat sedang berlangsung, Anda bisa memeriksa menggunakan isDiscovering().

Metode manageMyConnectedSocket() khusus aplikasi didesain untuk memulai thread untuk mengirimkan data, yang dibahas di bagian tentang Mengelola Koneksi.

Saat Anda selesai dengan BluetoothSocket, selalu panggil close(). Melakukannya segera akan menutup soket yang terhubung dan melepaskan resource internal yang terkait.

Mengelola koneksi

Setelah Anda berhasil menghubungkan beberapa perangkat, setiap perangkat memiliki BluetoothSocket yang terhubung. Ini adalah awal dari semua kesenangan karena Anda bisa berbagi data antar perangkat. Dengan menggunakan BluetoothSocket, prosedur umum untuk mentransfer data sebagai berikut:

  1. Dapatkan InputStream dan OutputStream yang menangani transmisi lewat soket, menggunakan getInputStream() dan getOutputStream().
  2. Membaca dan menulis data ke aliran dengan menggunakan read(byte[]) dan write(byte[]).

Tentu saja, ada detail implementasi yang harus dipertimbangkan. Khususnya, Anda harus menggunakan thread yang dibuat khusus untuk membaca dari aliran dan menulis untuk itu. Hal ini penting karena metode read(byte[]) dan write(byte[]) adalah panggilan pemblokir. Metode read(byte[]) memblokir hingga ada sesuatu untuk dibaca dari aliran. Metode write(byte[]) biasanya tidak memblokir, namun metode tersebut bisa memblokir untuk kontrol alur jika perangkat jarak jauh tidak memanggil read(byte[]) cukup cepat dan buffer menengah menjadi penuh sebagai hasilnya. Jadi, loop utama Anda dalam thread harus dibuat khusus untuk membaca dari InputStream. Sebuah metode publik yang terpisah dalam thread bisa digunakan untuk memulai penulisan ke OutputStream.

Contoh

Berikut ini contoh bagaimana Anda bisa mentransfer data antara dua perangkat yang terhubung melalui Bluetooth:

Kotlin

private const val TAG = "MY_APP_DEBUG_TAG"

// Defines several constants used when transmitting messages between the
// service and the UI.
const val MESSAGE_READ: Int = 0
const val MESSAGE_WRITE: Int = 1
const val MESSAGE_TOAST: Int = 2
// ... (Add other message types here as needed.)

class MyBluetoothService(
        // handler that gets info from Bluetooth service
        private val handler: Handler) {

    private inner class ConnectedThread(private val mmSocket: BluetoothSocket) : Thread() {

        private val mmInStream: InputStream = mmSocket.inputStream
        private val mmOutStream: OutputStream = mmSocket.outputStream
        private val mmBuffer: ByteArray = ByteArray(1024) // mmBuffer store for the stream

        override fun run() {
            var numBytes: Int // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs.
            while (true) {
                // Read from the InputStream.
                numBytes = try {
                    mmInStream.read(mmBuffer)
                } catch (e: IOException) {
                    Log.d(TAG, "Input stream was disconnected", e)
                    break
                }

                // Send the obtained bytes to the UI activity.
                val readMsg = handler.obtainMessage(
                        MESSAGE_READ, numBytes, -1,
                        mmBuffer)
                readMsg.sendToTarget()
            }
        }

        // Call this from the main activity to send data to the remote device.
        fun write(bytes: ByteArray) {
            try {
                mmOutStream.write(bytes)
            } catch (e: IOException) {
                Log.e(TAG, "Error occurred when sending data", e)

                // Send a failure message back to the activity.
                val writeErrorMsg = handler.obtainMessage(MESSAGE_TOAST)
                val bundle = Bundle().apply {
                    putString("toast", "Couldn't send data to the other device")
                }
                writeErrorMsg.data = bundle
                handler.sendMessage(writeErrorMsg)
                return
            }

            // Share the sent message with the UI activity.
            val writtenMsg = handler.obtainMessage(
                    MESSAGE_WRITE, -1, -1, mmBuffer)
            writtenMsg.sendToTarget()
        }

        // Call this method from the main activity to shut down the connection.
        fun cancel() {
            try {
                mmSocket.close()
            } catch (e: IOException) {
                Log.e(TAG, "Could not close the connect socket", e)
            }
        }
    }
}

Java

public class MyBluetoothService {
    private static final String TAG = "MY_APP_DEBUG_TAG";
    private Handler handler; // handler that gets info from Bluetooth service

    // Defines several constants used when transmitting messages between the
    // service and the UI.
    private interface MessageConstants {
        public static final int MESSAGE_READ = 0;
        public static final int MESSAGE_WRITE = 1;
        public static final int MESSAGE_TOAST = 2;

        // ... (Add other message types here as needed.)
    }

    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        private byte[] mmBuffer; // mmBuffer store for the stream

        public ConnectedThread(BluetoothSocket socket) {
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the input and output streams; using temp objects because
            // member streams are final.
            try {
                tmpIn = socket.getInputStream();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when creating input stream", e);
            }
            try {
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when creating output stream", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            mmBuffer = new byte[1024];
            int numBytes; // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs.
            while (true) {
                try {
                    // Read from the InputStream.
                    numBytes = mmInStream.read(mmBuffer);
                    // Send the obtained bytes to the UI activity.
                    Message readMsg = handler.obtainMessage(
                            MessageConstants.MESSAGE_READ, numBytes, -1,
                            mmBuffer);
                    readMsg.sendToTarget();
                } catch (IOException e) {
                    Log.d(TAG, "Input stream was disconnected", e);
                    break;
                }
            }
        }

        // Call this from the main activity to send data to the remote device.
        public void write(byte[] bytes) {
            try {
                mmOutStream.write(bytes);

                // Share the sent message with the UI activity.
                Message writtenMsg = handler.obtainMessage(
                        MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
                writtenMsg.sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "Error occurred when sending data", e);

                // Send a failure message back to the activity.
                Message writeErrorMsg =
                        handler.obtainMessage(MessageConstants.MESSAGE_TOAST);
                Bundle bundle = new Bundle();
                bundle.putString("toast",
                        "Couldn't send data to the other device");
                writeErrorMsg.setData(bundle);
                handler.sendMessage(writeErrorMsg);
            }
        }

        // Call this method from the main activity to shut down the connection.
        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Could not close the connect socket", e);
            }
        }
    }
}

Setelah konstruktor mendapatkan aliran yang diperlukan, thread akan menunggu data untuk datang melalui InputStream. Bila read(byte[]) dikembalikan dengan data dari aliran, data akan dikirim ke aktivitas utama menggunakan Handler anggota dari class induk. Thread kemudian akan menunggu lebih banyak byte yang akan dibaca dari InputStream.

Mengirim data keluar adalah semudah seperti memanggil metode write() thread dari aktivitas utama dan memberikan byte yang akan dikirim. Metode ini memanggil write(byte[]) untuk mengirim data ke perangkat jauh. Jika IOException dilontarkan saat memanggil write(byte[]), thread mengirimkan toast ke aktivitas utama, menjelaskan kepada pengguna bahwa perangkat tidak bisa mengirimkan byte yang diberikan ke perangkat (yang terhubung) lain.

Metode cancel() thread memungkinkan koneksi dihentikan kapan saja dengan menutup BluetoothSocket. Metode harus selalu dipanggil ketika Anda selesai menggunakan koneksi Bluetooth.

Untuk mendemonstrasikan penggunaan Bluetooth API, lihat aplikasi contoh Bluetooth Chat.

Class dan antarmuka utama

Semua Bluetooth API tersedia dalam paket android.bluetooth. Berikut adalah ringkasan dari class dan antarmuka yang Anda perlukan untuk membuat koneksi Bluetooth:

BluetoothAdapter
Merepresentasikan adaptor Bluetooth lokal (radio Bluetooth). BluetoothAdapter adalah titik-masuk untuk semua interaksi Bluetooth. Dengan ini, Anda bisa menemukan perangkat Bluetooth lain, kueri daftar perangkat terikat (disambungkan), buat instance BluetoothDevice menggunakan alamat MAC yang dikenal, dan membuat BluetoothServerSocket untuk mendengarkan komunikasi dari perangkat lain.
BluetoothDevice
Merepresentasikan perangkat Bluetooth jarak jauh. Gunakan ini untuk meminta koneksi dengan perangkat jarak jauh melalui BluetoothSocket atau kueri informasi tentang perangkat seperti nama, alamat, class, dan status ikatan.
BluetoothSocket
Merepresentasikan antarmuka untuk soket Bluetooth (mirip dengan TCP Socket). Ini adalah titik koneksi yang memungkinkan sebuah aplikasi untuk bertukar data dengan perangkat Bluetooth lain menggunakan InputStream dan OutputStream.
BluetoothServerSocket
Merepresentasikan soket server yang terbuka yang mendengarkan permintaan masuk (mirip dengan TCP ServerSocket). Agar bisa menghubungkan dua perangkat Android, satu perangkat harus membuka soket server dengan class ini. Saat perangkat Bluetooth jarak jauh membuat permintaan koneksi ke perangkat ini, perangkat menerima koneksi, kemudian mengembalikan BluetoothSocket yang terhubung.
BluetoothClass
Menguraikan karakteristik umum dan kemampuan perangkat Bluetooth. Ini adalah set properti hanya-baca yang mendefinisikan class perangkat dan layanannya. Meskipun informasi ini memberikan petunjuk yang berguna mengenai tipe perangkat, atribut class ini tidak perlu menguraikan semua profil dan layanan Bluetooth yang didukung perangkat.
BluetoothProfile
Antarmuka yang merepresentasikan profil Bluetooth. Profil Bluetooth adalah spesifikasi antarmuka nirkabel untuk komunikasi berbasis-Bluetooth antar perangkat. Contohnya adalah profil Hands-Free. Untuk pembahasan selengkapnya tentang profil, lihat Bekerja dengan Profil
BluetoothHeadset
Menyediakan dukungan untuk headset Bluetooth yang akan digunakan pada ponsel. Ini mencakup profil Bluetooth Headset dan profil Hands-Free (v1.5).
BluetoothA2dp
Mendefinisikan bagaimana audio berkualitas tinggi bisa dialirkan dari satu perangkat ke perangkat lainnya melalui koneksi Bluetooth dengan menggunakan Advanced Audio Distribution Profile (A2DP).
BluetoothHealth
Merepresentasikan proxy Health Device Profile yang mengontrol layanan Bluetooth.
BluetoothHealthCallback
Class abstrak yang Anda gunakan untuk mengimplementasikan callback BluetoothHealth. Anda harus memperluas class ini dan mengimplementasikan metode callback untuk menerima pembaruan tentang perubahan dalam status registrasi aplikasi dan status saluran Bluetooth.
BluetoothHealthAppConfiguration
Merepresentasikan konfigurasi aplikasi yang didaftarkan aplikasi Bluetooth Health pihak ketiga untuk berkomunikasi dengan perangkat kesehatan Bluetooth jarak jauh.
BluetoothProfile.ServiceListener
Antarmuka yang memberi tahu klien BluetoothProfile komunikasi antarproses IPC ketika mereka telah tersambung atau terputus dari layanan internal yang menjalankan profil tertentu.