Menghubungkan perangkat Bluetooth

Untuk membuat koneksi antara dua perangkat, Anda harus mengimplementasikan kedua metode mekanisme sisi server dan sisi klien karena satu perangkat harus membuka server dan satu lagi harus memulai koneksi menggunakan Alamat MAC. Perangkat server dan perangkat klien masing-masing mendapatkan BluetoothSocket dalam cara. Server menerima informasi soket ketika koneksi 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 terhubung di saluran RFCOMM yang sama. Pada tahap ini, masing-masing perangkat dapat memperoleh aliran input dan {i>output<i}, dan transfer data dapat dimulai, yang akan dibahas di bagian tentang mentransfer Bluetooth data Anda. Bagian ini menjelaskan cara memulai koneksi antara dua perangkat.

Pastikan Anda memiliki Izin Bluetooth dan menyiapkan aplikasi Anda untuk Bluetooth sebelum mencoba menemukan perangkat Bluetooth.

Teknik koneksi

Salah satu teknik implementasinya adalah dengan secara otomatis mempersiapkan setiap perangkat sebagai server sehingga setiap perangkat memiliki soket server yang terbuka dan mendengarkan koneksi. Di beberapa dalam hal ini, salah satu perangkat dapat memulai koneksi satu sama lain dan menjadi dengan klien besar. Atau, satu perangkat dapat secara eksplisit menghosting koneksi dan membuka soket server sesuai permintaan, dan perangkat lainnya memulai koneksi.


Gambar 1. Dialog penyambungan Bluetooth.

Menghubungkan sebagai server

Bila Anda ingin menghubungkan dua perangkat, salah satunya harus bertindak sebagai server dengan memegang {i>open<i} BluetoothServerSocket Tujuan dari soket server adalah untuk mendengarkan permintaan koneksi yang masuk dan memberikan BluetoothSocket yang terhubung setelah permintaan diterima. Jika BluetoothSocket diperoleh dari BluetoothServerSocket, yaitu BluetoothServerSocket dapat—dan harus—dihapus, kecuali jika Anda ingin perangkat untuk menerima lebih banyak koneksi.

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

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

    String ini adalah nama layanan yang dapat diidentifikasi, yang kemudian secara otomatis menulis ke entri database Service Discovery Protocol (SDP) baru di perangkat. Nama ini bersifat tidak tentu dan dapat berupa nama aplikasi. ID Unik Universal (UUID) juga disertakan dalam entri SDP dan membentuk dasar untuk perjanjian koneksi dengan perangkat klien. Bahwa adalah, ketika klien mencoba terhubung dengan perangkat ini, ia menggunakan UUID yang secara unik mengidentifikasi layanan yang ingin terhubung dengannya. Ini UUID harus cocok agar koneksi dapat diterima.

    UUID adalah format 128-bit standar untuk ID {i>string<i} yang digunakan untuk mengidentifikasi informasi. UUID digunakan untuk mengidentifikasi informasi yang perlu unik di dalam sistem atau jaringan karena probabilitas UUID yang berulang adalah nol. Kode ini dibuat secara independen, tanpa menggunakan otoritas terpusat. Dalam hal ini, ID digunakan untuk mengidentifikasi layanan Bluetooth aplikasi. Untuk mendapatkan UUID untuk digunakan dengan aplikasi, Anda dapat menggunakan salah satunya dari sekian banyak UUID generator di web, lalu inisialisasi UUID dengan fromString(String).

  2. Mulai memproses permintaan koneksi dengan memanggil accept()

    Ini adalah panggilan pemblokir. Server kembali ketika salah satu koneksi telah diterima atau terjadi pengecualian. Koneksi hanya diterima ketika perangkat jarak jauh telah mengirim permintaan koneksi berisi UUID yang cocok yang terdaftar dengan soket server yang mendengarkannya ini. Jika berhasil, accept() menampilkan BluetoothSocket yang terhubung.

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

    Panggilan metode ini melepaskan soket server dan semua sumber dayanya, tetapi tidak menutup BluetoothSocket yang terhubung yang ditampilkan oleh accept(). Tidak seperti TCP/IP, RFCOMM hanya mengizinkan satu klien yang terhubung setiap saluran pada satu waktu, jadi dalam sebagian besar kasus, akan lebih masuk akal untuk memanggil close() di BluetoothServerSocket segera setelah menerima soket yang terhubung.

Karena panggilan accept() merupakan panggilan pemblokir, jangan jalankan di bagian utama thread UI aktivitas. Mengeksekusinya di thread lain memastikan bahwa aplikasi Anda dapat masih menanggapi interaksi pengguna lain. Melakukan semua pekerjaan biasanya masuk akal yang melibatkan BluetoothServerSocket atau BluetoothSocket di thread baru dikelola oleh aplikasi Anda. Untuk membatalkan panggilan yang diblokir seperti accept(), panggil close() di BluetoothServerSocket atau BluetoothSocket dari thread lain. Catatan bahwa semua metode pada BluetoothServerSocket atau BluetoothSocket yang aman untuk thread.

Contoh

Berikut ini 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 diinginkan, jadi segera setelah koneksi diterima dan BluetoothSocket didapatkan, aplikasi akan meneruskan memperoleh BluetoothSocket ke thread terpisah, menutup BluetoothServerSocket, dan keluar dari loop.

Perlu diketahui bahwa saat accept() menampilkan BluetoothSocket, soket sudah terhubung. Oleh karena itu, Anda tidak boleh memanggil connect(), seperti yang Anda lakukan dari sisi klien.

Metode manageMyConnectedSocket() khusus aplikasi didesain untuk memulai untuk mentransfer data, yang akan dibahas dalam topik tentang mentransfer Bluetooth data.

Biasanya, Anda harus menutup BluetoothServerSocket begitu Anda selesai mendeteksi koneksi masuk. Dalam contoh ini, close() segera dipanggil setelah BluetoothSocket diperoleh. Anda mungkin juga ingin menyediakan di thread Anda yang dapat menutup BluetoothSocket pribadi dalam peristiwa Anda perlu berhenti mendengarkan pada soket server itu.

Menghubungkan sebagai klien

Untuk memulai koneksi dengan perangkat jarak jauh yang menerima pada soket server terbuka, Anda harus terlebih dahulu mendapatkan BluetoothDevice yang mewakili perangkat jarak jauh. Untuk mempelajari cara membuat BluetoothDevice, lihat Menemukan Bluetooth perangkat Anda. Anda harus lalu gunakan BluetoothDevice untuk mendapatkan BluetoothSocket dan memulai koneksi jarak jauh.

Prosedur dasarnya sebagai berikut:

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

    Metode ini melakukan inisialisasi objek BluetoothSocket yang memungkinkan klien untuk hubungkan ke BluetoothDevice. UUID yang diteruskan di sini harus cocok dengan UUID yang digunakan oleh perangkat server ketika memanggil listenUsingRfcommWithServiceRecord(String, UUID) untuk membuka BluetoothServerSocket-nya. Untuk menggunakan UUID yang sesuai, lakukan hard code pada string UUID ke aplikasi Anda, lalu referensikan dari kedua server dan kode klien.

  2. Mulai koneksi dengan memanggil connect(). Perhatikan bahwa metode ini adalah memblokir panggilan.

    Setelah klien memanggil metode ini, sistem melakukan pencarian SDP untuk menemukan perangkat jarak jauh dengan UUID yang sesuai. Jika pencarian berhasil dan perangkat jarak jauh menerima koneksi, perangkat tersebut berbagi saluran RFCOMM untuk digunakan selama koneksi, dan metode connect() akan ditampilkan. Jika koneksi gagal, atau jika waktu metode connect() habis (setelah sekitar 12 detik), maka metode ini akan menampilkan IOException.

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

Contoh

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

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?.let { 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);
       }
   }
}

Perhatikan bahwa dalam cuplikan ini, cancelDiscovery() dipanggil sebelum koneksi percobaan terjadi. Anda harus selalu memanggil cancelDiscovery() sebelum connect(), terutama karena cancelDiscovery() berhasil terlepas dari apakah perangkat penemuan sedang berlangsung. Jika aplikasi Anda perlu menentukan apakah penemuan perangkat sedang berlangsung, Anda dapat memeriksanya menggunakan isDiscovering()

Metode manageMyConnectedSocket() khusus aplikasi didesain untuk memulai untuk mentransfer data, yang akan dibahas di bagian tentang mentransfer data Bluetooth.

Setelah selesai menggunakan BluetoothSocket, selalu panggil close(). Tindakan ini segera menutup soket yang terhubung dan melepaskan semua Google Cloud Platform.