Save the date! Android Dev Summit is coming to Mountain View, CA on November 7-8, 2018.

Bluetooth

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

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

Dokumen ini menjelaskan cara menggunakan 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.

Dasar-Dasar

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.

Semua Bluetooth API tersedia dalam paket android.bluetooth . Berikut adalah ringkasan dari kelas 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 (disandingkan), 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, kelas, 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 melalui 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 kelas ini. Ketika perangkat Bluetooth jarak jauh membuat permintaan koneksi ke perangkat ini, BluetoothServerSocketakan mengembalikan BluetoothSocket yang terhubung saat koneksi diterima.
BluetoothClass
Menguraikan karakteristik umum dan kemampuan dari perangkat Bluetooth. Ini adalah set properti hanya-baca yang mendefinisikan kelas-kelas perangkat dan layanannya dari perangkat besar dan kecil. Akan tetapi, ini tidak Andal dalam menjelaskan semua profil dan layanan Bluetooth yang didukung perangkat, namun berguna sebagai petunjuk tipe perangkat.
BluetoothProfile
Antarmuka yang mewakili profil Bluetooth. Profil Bluetooth adalah spesifikasi antarmuka nirkabel untuk komunikasi berbasis-Bluetooth antar perangkat. Contohnya adalah profil Hands-Free. Untuk pembahasan lebih banyak tentang profil, lihat Bekerja dengan Profil
BluetoothHeadset
Menyediakan dukungan untuk headset Bluetooth yang akan digunakan pada ponsel. Ini termasuk profil Bluetooth Headset dan Hands-Free (v1.5).
BluetoothA2dp
Mendefinisikan bagaimana audio berkualitas tinggi bisa dialirkan dari satu perangkat ke perangkat lainnya melalui koneksi Bluetooth. "A2DP" adalah singkatan dari Advanced Audio Distribution Profile.
BluetoothHealth
Merepresentasikan proxy Health Device Profile yang mengontrol layanan Bluetooth.
BluetoothHealthCallback
Kelas abstrak yang Anda gunakan untuk mengimplementasikan callback BluetoothHealth. Anda harus memperluas kelas ini dan mengimplementasikan metode callback untuk menerima pembaruan tentang perubahan dalam status registrasi aplikasi dan status saluran Bluetooth.
BluetoothHealthAppConfiguration
Merepresentasikan konfigurasi aplikasi yang didaftar aplikasi Bluetooth Health pihak ketiga untuk berkomunikasi dengan perangkat kesehatan Bluetooth jarak jauh.
BluetoothProfile.ServiceListener
Antarmuka yang memberi tahu klien BluetoothProfile IPC ketika mereka telah tersambung atau terputus dari layanan (yaitu , layanan internal yang menjalankan profil tertentu).

Izin Bluetooth

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

Jika Anda ingin aplikasi memulai pencarian perangkat atau memanipulasi setelan Bluetooth, Anda juga harus mendeklarasikan izin BLUETOOTH_ADMIN . 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. Catatan: Jika Anda menggunakan izin BLUETOOTH_ADMIN, maka Anda juga harus memiliki izin BLUETOOTH.

Mendeklarasikan izin Bluetooth dalam file manifes aplikasi Anda. Misalnya :

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

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

Menyiapkan Bluetooth

Gambar 1: Mengaktifkan dialog 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() mengembalikan null, maka perangkat tidak mendukung Bluetooth dan cerita berakhir di sini. Misalnya:

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
        // Device does not support Bluetooth
    }
    
  2. Mengaktifkan Bluetooth

    Berikutnya, Anda harus memastikan bahwa Bluetooth diaktifkan. Panggil isEnabled() untuk memeriksa apakah Bluetooth saat ini diaktifkan. Jika metode ini mengembalikan false, maka Bluetooth dinonaktifkan. Untuk meminta agar Bluetooth diaktifkan, panggil startActivityForResult() dengan Maksud aksi ACTION_REQUEST_ENABLE. Ini akan mengeluarkan permintaan untuk mengaktifkan Bluetooth melalui setelan sistem (tanpa menghentikan aplikasi Anda). Misalnya:

    if (!mBluetoothAdapter.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).

    Konstanta REQUEST_ENABLE_BT yang diteruskan ke startActivityForResult() adalah integer yang didefinisikan secara lokal (harus lebih besar dari 0), yang dikembalikan sistem 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 maksud 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 berguna untuk mendeteksi perubahan yang dibuat untuk status Bluetooth ketika aplikasi Anda berjalan.

Tip: Mengaktifkan kemampuan untuk dapat ditemukan akan secara otomatis mengaktifkan Bluetooth. Jika Anda berencana untuk selalu mengaktifkan kemampuan untuk dapat ditemukan perangkat sebelum melakukan aktivitas Bluetooth, Anda bisa melewati langkah 2 di atas. Baca tentang mengaktifkan kemampuan untuk dapat ditemukan, di bawah ini.

Mencari Perangkat

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

Pencarian perangkat adalah prosedur pemindaian yang menelusuri area lokal untuk perangkat yang mengaktifkan Bluetooth dan kemudian meminta beberapa informasi tentang setiap perangkat tersebut (ini kadang-kadang disebut dengan "menemukan", "menanyakan" atau "memindai"). Namun, perangkat Bluetooth dalam area lokal akan merespons permintaan penemuan hanya jika Bluetooth diaktifkan agar dapat ditemukan. Jika dapat ditemukan, perangkat tersebut akan merespons permintaan penemuan dengan berbagi beberapa informasi, seperti nama perangkat, kelas, 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 penyandingan secara otomatis ditampilkan ke pengguna. Ketika perangkat disandingkan, informasi dasar tentang perangkat tersebut (seperti nama perangkat, kelas, 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 disandingkan dan yang dihubungkan. Disandingkan 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 sekarang membutuhkan perangkat untuk disandingkan sebelum koneksi RFCOMM dapat dibuat. (Penyandingan secara otomatis dilakukan ketika Anda memulai koneksi terenkripsi dengan Bluetooth API.)

Bagian berikut menjelaskan cara menemukan perangkat yang telah disandingkan, 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. Cara mengaktifkan kemampuan untuk dapat ditemukan dibahas di bawah ini.

Melakukan kueri perangkat yang disandingkan

Sebelum melakukan pencarian perangkat, ada baiknya melakukan kueri kumpulan perangkat yang disandingkan untuk melihat jika perangkat yang diinginkan sudah dikenal. Untuk melakukannya, panggil getBondedDevices(). Ini akan mengembalikan Set BluetoothDevice yang mewakili perangkat yang disandingkan. Misalnya, Anda bisa melakukan kueri semua perangkat yang disandingkan dan kemudian menampilkan nama masing-masing perangkat kepada pengguna, menggunakan ArrayAdapter:

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
}

Semua yang dibutuhkan dari objek BluetoothDevice agar bisa memulai koneksi adalah alamat MAC. Dalam contoh ini, itu disimpan sebagai bagian dari ArrayAdapter yang ditampilkan kepada pengguna. Alamat MAC nantinya bisa diambil agar dapat memulai koneksi. Anda bisa mempelajari selengkapnya tentang membuat koneksi dalam bagian tentang Menghubungkan Perangkat.

Menemukan perangkat

Untuk mulai menemukan perangkat, cukup panggil startDiscovery(). Proses ini asinkron dan metode ini akan langsung dikembalikan dengan boolean yang menunjukkan apakah penemuan telah berhasil dimulai. Proses penemuan 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 Maksud ACTION_FOUND agar bisa menerima informasi tentang setiap perangkat yang ditemukan. Untuk setiap perangkat, sistem akan menyiarkan Maksud ACTION_FOUND. Maksud ini membawa bidang tambahan EXTRA_DEVICE dan EXTRA_CLASS, berisi BluetoothDevice dan BluetoothClass. Misalnya, berikut ini adalah cara mendaftar untuk menangani siaran ketika perangkat ditemukan:

// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // When discovery finds a device
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // Add the name and address to an array adapter to show in a ListView
            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
        }
    }
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

Semua yang dibutuhkan dari objek BluetoothDevice agar bisa memulai koneksi adalah alamat MAC. Dalam contoh ini, itu disimpan sebagai bagian dari ArrayAdapter yang ditampilkan kepada pengguna. Alamat MAC nantinya bisa diambil agar dapat memulai koneksi. Anda bisa mempelajari selengkapnya tentang membuat koneksi dalam bagian tentang Menghubungkan Perangkat.

Perhatian: Melakukan pencarian perangkat adalah prosedur yang berat bagi adaptor Bluetooth dan mengonsumsi banyak sumber daya. Setelah menemukan perangkat yang akan dihubungkan, pastikan Anda selalu menghentikan pencarian dengan cancelDiscovery() sebelum melakukan koneksi. Juga, jika Anda sudah memiliki koneksi dengan suatu perangkat, maka melakukan pencarian bisa secara signifikan mengurangi bandwidth yang tersedia untuk koneksi, sehingga Anda sebaiknya tidak melakukan pencarian saat terhubung.

Mengaktifkan kemampuan untuk dapat ditemukan

Jika Anda menginginkan agar perangkat lokal dapat ditemukan oleh perangkat lain, panggil startActivityForResult(Intent, int) dengan Maksud aksi ACTION_REQUEST_DISCOVERABLE . Ini akan mengeluarkan permintaan untuk mengaktifkan mode dapat ditemukan melalui setelan sistem (tanpa menghentikan aplikasi Anda). Secara default, perangkat akan dapat ditemukan selama 120 detik. Anda bisa menetapkan durasi yang berbeda dengan menambahkan tambahan Maksud EXTRA_DISCOVERABLE_DURATION . Durasi maksimum yang bisa disetel aplikasi adalah 3600 detik, dan nilai 0 berarti perangkat selalu dapat ditemukan. Setiap nilai di bawah 0 atau di atas 3600 secara otomatis disetel ke 120 detik). Misalnya, cuplikan ini menetapkan durasi 300:

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

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 belum diaktifkan pada perangkat, maka mengaktifkan kemampuan untuk dapat ditemukan secara otomatis akan mengaktifkan Bluetooth.

Perangkat 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 Maksud ACTION_SCAN_MODE_CHANGED . Ini akan berisi bidang tambahan EXTRA_SCAN_MODE dan EXTRA_PREVIOUS_SCAN_MODE, yang memberi tahu Anda mode pemindaian baru dan lama. Kemungkinan nilainya adalah SCAN_MODE_CONNECTABLE_DISCOVERABLE, SCAN_MODE_CONNECTABLE, atau SCAN_MODE_NONE, menunjukkan bahwa perangkat dalam mode dapat ditemukan, tidak dalam mode dapat ditemukan tapi masih bisa menerima koneksi, atau tidak dalam mode dapat ditemukan dan tidak dapat menerima koneksi.

Anda tidak perlu mengaktifkan kemampuan untuk dapat ditemukan jika Anda akan memulai koneksi ke perangkat jauh. Mengaktifkan kemampuan untuk dapat ditemukan hanya diperlukan bila Anda menginginkan aplikasi Anda untuk menjadi host soket server yang akan menerima koneksi masuk, karena perangkat jauh harus dapat menemukan perangkat sebelum bisa memulai koneksi.

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 untuk memulai koneksi). 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.

Perangkat server dan perangkat klien masing-masing memperoleh BluetoothSocket yang diperlukan dengan cara berbeda. Server akan menerimanya ketika koneksi masuk diterima. Klien akan menerimanya ketika membuka saluran RFCOMM ke server.

Gambar 3: Dialog penyandingan Bluetooth.

Salah satu teknik implementasi adalah dengan secara otomatis mempersiapkan setiap perangkat sebagai server, sehingga masing-masing memiliki soket server yang terbuka dan mendengarkan koneksi. Maka tiap-tiap 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 dengan mudah memulai koneksi.

Catatan: Jika dua perangkat belum disandingkan sebelumnya, maka kerangka kerja Android secara otomatis akan menampilkan notifikasi permintaan penyandingan 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 disandingkan atau tidak. Percobaan koneksi RFCOMM Anda akan diblokir hingga pengguna telah berhasil disandingkan, atau akan gagal jika pengguna menolak penyandingan, atau jika penyandingan gagal atau waktu habis.

Menghubungkan sebagai server

Bila Anda ingin menghubungkan dua perangkat, salah satunya harus bertindak sebagai server dengan memegang 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.

Berikut ini adalah prosedur dasar menyiapkan sebuah soket server dan menerima koneksi:

  1. Dapatkan BluetoothServerSocket dengan memanggil listenUsingRfcommWithServiceRecord(String, UUID).

    String adalah nama yang bisa diidentifikasi 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 Anda). UUID ini 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 (pada langkah berikutnya).

  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. Bila berhasil, accept() akan mengembalikan BluetoothSocket yang terhubung.

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

    Ini melepaskan soket server dan semua sumber daya, 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.

Panggilan accept() sebaiknya tidak dijalankan dalam thread UI aktivitas utama karena merupakan panggilan pemblokir dan akan mencegah interaksi lain dengan aplikasi tersebut. 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 dan panggilan yang diblokir akan segera kembali. Perhatikan bahwa semua metode pada BluetoothServerSocket atau BluetoothSocket adalah thread-safe.

Contoh

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

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 = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException 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) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                manageConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }

    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException 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 ketika accept() mengembalikan BluetoothSocket, soket sudah terhubung, sehingga Anda sebaiknya tidak memanggil connect() (seperti yang Anda lakukan dari sisi-klien).

manageConnectedSocket() adalah metode fiksi dalam aplikasi yang akan memulai thread untuk mentransfer data, yang dibahas pada 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 ketika Anda harus berhenti mendengarkan soket server.

Menghubungkan sebagai klien

Agar bisa memulai koneksi dengan perangkat jauh (perangkat yang memegang soket server terbuka), Anda harus terlebih dahulu memperoleh objek BluetoothDevice yang merepresentasikan perangkat jauh. (Memperoleh sebuah BluetoothDevice dibahas pada bagian di atas tentang Mencari Perangkat.) Anda kemudian harus menggunakan BluetoothDevice untuk memperoleh BluetoothSocket dan memulai koneksi.

Berikut adalah prosedur dasarnya:

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

    Ini akan melakukan inisialiasi BluetoothSocket yang akan terhubung ke BluetoothDevice. UUID yang diberikan di sini harus cocok dengan UUID yang digunakan oleh perangkat server ketika membuka BluetoothServerSocket (dengan listenUsingRfcommWithServiceRecord(String, UUID)). Menggunakan UUID yang sama hanya merupakan masalah hard-coding string UUID ke dalam aplikasi Anda dan kemudian mereferensikannya dari kode server dan kode klien.

  2. Memulai koneksi dengan memanggil connect().

    Setelah panggilan ini, sistem akan melakukan pencarian SDP pada perangkat jauh untuk mencocokkan UUID. Jika pencarian tersebut berhasil dan perangkat jauh menerima koneksi, itu akan berbagi saluran RFCOMM yang akan digunakan selama koneksi dan connect() akan kembali. Metode ini adalah panggilan pemblokir. Jika, karena suatu alasan, koneksi gagal atau metode connect() waktunya habis (setelah sekitar 12 detik), maka itu akan mengeluarkan pengecualian.

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

    Catatan: Anda harus selalu memastikan bahwa perangkat tidak melakukan pencarian perangkat ketika 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 yang memulai koneksi Bluetooth:

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;

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

    public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

Perhatikan bahwa cancelDiscovery() dipanggil sebelum koneksi dilakukan. Anda sebaiknya selalu melakukan hal ini sebelum menghubungkan dan aman untuk memanggil tanpa benar-benar memeriksa apakah itu berjalan atau tidak (namun jika Anda ingin memeriksa, panggil isDiscovering()).

manageConnectedSocket() adalah metode fiksi dalam aplikasi yang akan memulai thread untuk mentransfer data, yang dibahas pada bagian tentang Mengelola Koneksi.

Setelah Anda selesai dengan BluetoothSocket, selalu panggil close() untuk membersihkannya. Melakukan hal ini akan langsung menutup soket yang terhubung dan membersihkan semua sumber daya internal.

Mengelola Koneksi

Ketika Anda berhasil menghubungkan dua perangkat (atau lebih), masing-masing akan 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 bebas cukup sederhana:

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

Demikian saja.

Tentu saja, ada detail implementasi yang harus dipertimbangkan. Pertama dan terpenting, Anda harus menggunakan thread khusus untuk semua aliran membaca dan menulis. Hal ini penting karena kedua metode read(byte[]) dan write(byte[]) memblokir panggilan. read(byte[]) akan memblokir sampai ada sesuatu yang bisa dibaca dari aliran. write(byte[]) biasanya tidak memblokir, namun dapat memblokir untuk kontrol alur jika perangkat jauh tidak memanggil read(byte[]) dengan cukup cepat dan buffer perantara penuh. Jadi, loop utama Anda dalam thread harus didedikasikan untuk membaca dari InputStream. Sebuah metode publik yang terpisah dalam thread bisa digunakan untuk memulai penulisan ke OutputStream.

Contoh

Berikut adalah contoh bagaimana hal ini akan terlihat:

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    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();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

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

    /* Call this from the main activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

Konstruktor mendapatkan aliran yang diperlukan dan setelah dieksekusi, thread akan menunggu data untuk datang melalui InputStream. Bila read(byte[]) dikembalikan dengan byte dari aliran, data akan dikirim ke aktivitas utama menggunakan Penangan anggota dari kelas induk. Kemudian itu kembali dan menunggu lebih banyak byte dari aliran.

Mengirim data keluar adalah semudah seperti memanggil metode write() thread dari aktivitas utama dan memberikan byte yang akan dikirim. Metode ini cukup memanggil write(byte[]) untuk mengirim data ke perangkat jauh.

Metode cancel() thread ini penting sehingga koneksi bisa dihentikan setiap saat dengan menutup BluetoothSocket. Ini harus selalu dipanggil bila Anda sudah selesai menggunakan koneksi Bluetooth.

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

Bekerja 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.

Anda bisa mengimplementasikan antarmuka BluetoothProfile untuk menulis kelas Anda sendiri untuk mendukung profil Bluetooth tertentu. Android Bluetooth API menyediakan implementasi untuk profil Bluetooth berikut:

  • Headset. Profil Headset menyediakan dukungan untuk headset Bluetooth yang akan digunakan dengan ponsel. Android menyediakan kelas BluetoothHeadset, yang merupakan proxy untuk mengontrol Layanan Bluetooth Headset melalui komunikasi antarproses (interprocess communication - IPC). Ini berisi profil Bluetooth Headset dan Hands-Free (v1.5). Kelas BluetoothHeadset menyertakan dukungan untuk perintah AT. Untuk pembahasan selengkapnya tentang topik ini, lihat Perintah AT khusus-Vendor
  • A2DP. Profil Advanced Audio Distribution Profile (A2DP) mendefinisikan bagaimana audio berkualitas tinggi bisa dialirkan dari satu perangkat ke perangkat lainnya melalui koneksi Bluetooth. Android menyediakan kelas BluetoothA2dp, yang merupakan proxy untuk mengontrol Layanan Bluetooth A2DP melalui IPC.
  • 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 Bluetooth Assigned Numbers pada www.bluetooth.org. 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 lebih banyak 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. Gunakan getProfileProxy() untuk membuat koneksi ke objek proxy profil yang terkait dengan profil. Pada contoh di bawah ini, objek proxy profil adalah instance dari BluetoothHeadset.
  3. Menyiapkan BluetoothProfile.ServiceListener. Listener ini memberi tahu klien IPC BluetoothProfile ketika mereka telah terhubung atau terputus dari layanan.
  4. Dalam onServiceConnected(), dapatkan penangan 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:

BluetoothHeadset mBluetoothHeadset;

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

// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);

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

// ... call functions on mBluetoothHeadset

// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);

Perintah AT khusus-vendor

Mulai Android 3.0, 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 maksud ACTION_VENDOR_SPECIFIC_HEADSET_EVENT untuk menangani perintah AT khusus-vendor untuk headset.

Health Device Profile

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 kelas-kelas BluetoothHealth, BluetoothHealthCallback, dan BluetoothHealthAppConfiguration, yang dijelaskan dalam Dasar-Dasar.

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

Konsep Keterangan
Source Peranan yang didefinisikan dalam HDP. Source adalah perangkat kesehatan yang mentransmisikan data medis (timbangan, pengukur glukosa, termometer, dll) ke perangkat cerdas seperti ponsel atau Tablet Android.
Sink Peranan yang didefinisikan dalam HDP. Dalam HDP, sink adalah perangkat cerdas yang menerima data medis. Dalam aplikasi HDP Android, sink dinyatakan oleh objek BluetoothHealthAppConfiguration .
Registration Mengacu pada pendaftaran sink untuk perangkat kesehatan tertentu.
Connection Mengacu pada pembukaan saluran antara perangkat kesehatan dan perangkat cerdas seperti ponsel atau Tablet Android.

Membuat Aplikasi HDP

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

  1. Dapatkan referensi ke objek proxy BluetoothHealth .

    Mirip dengan 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. Membuat koneksi ke perangkat kesehatan. Beberapa perangkat akan mengawali koneksi. 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 diterjemahkan menggunakan pengelola kesehatan yang mengimplementasikan spesifikasi IEEE 11073-xxxxx.

  5. Setelah selesai, tutup saluran kesehatan dan mencabut pendaftaran aplikasi. Saluran ini juga ditutup ketika tidak ada aktivitas dalam waktu lama.

Untuk contoh kode lengkap yang memperlihatkan langkah-langkah ini, lihat Bluetooth HDP (Health Device Profile).