Il primo passaggio per interagire con un dispositivo BLE è la connessione al dispositivo. Altro
in particolare la connessione al server GATT sul dispositivo. Per connettersi a un GATT
su un dispositivo BLE, utilizza
connectGatt()
. Questo metodo richiede tre parametri:
Oggetto Context
, autoConnect
(un valore booleano
che indica se connettersi automaticamente al dispositivo BLE non appena
diventa disponibile) e un riferimento a un
BluetoothGattCallback
:
Kotlin
var bluetoothGatt: BluetoothGatt? = null ... bluetoothGatt = device.connectGatt(this, false, gattCallback)
Java
bluetoothGatt = device.connectGatt(this, false, gattCallback);
Questa operazione si connette al server GATT ospitato dal dispositivo BLE e restituisce un
BluetoothGatt
, che
per condurre le operazioni
del client GATT. Il chiamante (app per Android)
è il client GATT. La
BluetoothGattCallback
viene utilizzato per fornire risultati al cliente, ad esempio
stato della connessione ed eventuali altre operazioni
del client GATT.
configura un servizio associato
Nell'esempio seguente, l'app BLE fornisce un'attività
(DeviceControlActivity
) per connettersi a dispositivi Bluetooth, visualizzare i dati del dispositivo,
e mostrare i servizi e le caratteristiche del GATT supportati dal dispositivo. Sede
all'input dell'utente, questa attività comunica con un
Service
ha chiamato BluetoothLeService
, che
interagisce con il dispositivo BLE tramite l'API BLE. La comunicazione è
eseguita utilizzando un servizio associato che consente
l'attività per connettersi a BluetoothLeService
e chiamare le funzioni a
connettersi ai dispositivi. BluetoothLeService
richiede un
implementazione di Binder
che consente di accedere a
il servizio per l'attività.
Kotlin
class BluetoothLeService : Service() { private val binder = LocalBinder() override fun onBind(intent: Intent): IBinder? { return binder } inner class LocalBinder : Binder() { fun getService() : BluetoothLeService { return this@BluetoothLeService } } }
Java
class BluetoothLeService extends Service { private Binder binder = new LocalBinder(); @Nullable @Override public IBinder onBind(Intent intent) { return binder; } class LocalBinder extends Binder { public BluetoothLeService getService() { return BluetoothLeService.this; } } }
L'attività può avviare il servizio utilizzando
bindService()
,
passando un Intent
per avviare
un servizio ServiceConnection
implementazione per rimanere in ascolto degli eventi di connessione e disconnessione, oltre a un flag
per specificare ulteriori opzioni di connessione.
Kotlin
class DeviceControlActivity : AppCompatActivity() { private var bluetoothService : BluetoothLeService? = null // Code to manage Service lifecycle. private val serviceConnection: ServiceConnection = object : ServiceConnection { override fun onServiceConnected( componentName: ComponentName, service: IBinder ) { bluetoothService = (service as LocalBinder).getService() bluetoothService?.let { bluetooth -> // call functions on service to check connection and connect to devices } } override fun onServiceDisconnected(componentName: ComponentName) { bluetoothService = null } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.gatt_services_characteristics) val gattServiceIntent = Intent(this, BluetoothLeService::class.java) bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE) } }
Java
class DeviceControlActivity extends AppCompatActivity { private BluetoothLeService bluetoothService; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bluetoothService = ((LocalBinder) service).getService(); if (bluetoothService != null) { // call functions on service to check connection and connect to devices } } @Override public void onServiceDisconnected(ComponentName name) { bluetoothService = null; } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gatt_services_characteristics); Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); } }
Configurazione di BluetoothAdapter
Una volta associato, il servizio deve accedere
BluetoothAdapter
Dovrebbe
verifica che l'adattatore sia disponibile sul dispositivo. Leggi l'articolo sulla configurazione
Bluetooth per ulteriori informazioni su
BluetoothAdapter
. L'esempio seguente racchiude questo codice di configurazione in una
Funzione initialize()
che restituisce un valore Boolean
che indica l'esito positivo.
Kotlin
private const val TAG = "BluetoothLeService" class BluetoothLeService : Service() { private var bluetoothAdapter: BluetoothAdapter? = null fun initialize(): Boolean { bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() if (bluetoothAdapter == null) { Log.e(TAG, "Unable to obtain a BluetoothAdapter.") return false } return true } ... }
Java
class BluetoothLeService extends Service { public static final String TAG = "BluetoothLeService"; private BluetoothAdapter bluetoothAdapter; public boolean initialize() { bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false; } return true; } ... }
L'attività chiama questa funzione nell'ambito della sua implementazione di ServiceConnection
.
La gestione di un falso valore restituito dalla funzione initialize()
dipende dalle
un'applicazione. Potresti mostrare all'utente un messaggio di errore che indica che
il dispositivo corrente non supporta il funzionamento Bluetooth o non disattiva funzionalità
che richiedono il Bluetooth per funzionare. Nell'esempio seguente,
finish()
viene chiamato nell'attività
per riportare l'utente alla schermata precedente.
Kotlin
class DeviceControlActivity : AppCompatActivity() { // Code to manage Service lifecycle. private val serviceConnection: ServiceConnection = object : ServiceConnection { override fun onServiceConnected( componentName: ComponentName, service: IBinder ) { bluetoothService = (service as LocalBinder).getService() bluetoothService?.let { bluetooth -> if (!bluetooth.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth") finish() } // perform device connection } } override fun onServiceDisconnected(componentName: ComponentName) { bluetoothService = null } } ... }
Java
class DeviceControlsActivity extends AppCompatActivity { private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bluetoothService = ((LocalBinder) service).getService(); if (bluetoothService != null) { if (!bluetoothService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } // perform device connection } } @Override public void onServiceDisconnected(ComponentName name) { bluetoothService = null; } }; ... }
Collega a un dispositivo
Una volta inizializzata l'istanza BluetoothLeService
, può connettersi a BLE
dispositivo. L'attività deve inviare l'indirizzo del dispositivo al servizio affinché possa
avvia la connessione. Per prima cosa, il servizio chiama
getRemoteDevice()
su BluetoothAdapter
per accedere al dispositivo. Se l'adattatore non riesce a trovare
un dispositivo con quell'indirizzo, getRemoteDevice()
genera
IllegalArgumentException
Kotlin
fun connect(address: String): Boolean { bluetoothAdapter?.let { adapter -> try { val device = adapter.getRemoteDevice(address) } catch (exception: IllegalArgumentException) { Log.w(TAG, "Device not found with provided address.") return false } // connect to the GATT server on the device } ?: run { Log.w(TAG, "BluetoothAdapter not initialized") return false } }
Java
public boolean connect(final String address) { if (bluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } try { final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address); } catch (IllegalArgumentException exception) { Log.w(TAG, "Device not found with provided address."); return false; } // connect to the GATT server on the device }
DeviceControlActivity
chiama questa funzione connect()
una volta che il servizio viene
inizializzato. L'attività deve trasmettere l'indirizzo del dispositivo BLE. Nella
Nell'esempio seguente, l'indirizzo del dispositivo viene passato all'attività come intent
extra.
Kotlin
// Code to manage Service lifecycle. private val serviceConnection: ServiceConnection = object : ServiceConnection { override fun onServiceConnected( componentName: ComponentName, service: IBinder ) { bluetoothService = (service as LocalBinder).getService() bluetoothService?.let { bluetooth -> if (!bluetooth.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth") finish() } // perform device connection bluetooth.connect(deviceAddress) } } override fun onServiceDisconnected(componentName: ComponentName) { bluetoothService = null } }
Java
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bluetoothService = ((LocalBinder) service).getService(); if (bluetoothService != null) { if (!bluetoothService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } // perform device connection bluetoothService.connect(deviceAddress); } } @Override public void onServiceDisconnected(ComponentName name) { bluetoothService = null; } };
Dichiara il callback GATT
Una volta che l'attività indica al servizio a quale dispositivo connettersi e al servizio
si connette al dispositivo, il servizio deve connettersi al server GATT sulla
Dispositivo BLE. Questa connessione richiede un BluetoothGattCallback
per ricevere
notifiche sullo stato della connessione, sul rilevamento del servizio, sulla caratteristica
letture e notifiche delle caratteristiche.
Questo argomento è incentrato sulle notifiche sullo stato della connessione. Consulta la sezione Trasferire BLE dati su come eseguire Service Discovery, letture delle caratteristiche e caratteristica della richiesta notifiche.
La
onConnectionStateChange()
viene attivata quando cambia la connessione al server GATT del dispositivo.
Nell'esempio seguente, il callback è definito nella classe Service
, quindi
può essere utilizzato con
BluetoothDevice
una volta
che vi si connette.
Kotlin
private val bluetoothGattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { if (newState == BluetoothProfile.STATE_CONNECTED) { // successfully connected to the GATT Server } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // disconnected from the GATT Server } } }
Java
private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { // successfully connected to the GATT Server } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // disconnected from the GATT Server } } };
Connetti al servizio GATT
Una volta dichiarato BluetoothGattCallback
, il servizio può utilizzare
Oggetto BluetoothDevice
dalla funzione connect()
per connettersi al GATT
servizio sul dispositivo.
La
connectGatt()
. Richiede un oggetto Context
, un valore booleano autoConnect
e il BluetoothGattCallback
. In questo esempio, l'app viene
connessione al dispositivo BLE, quindi viene passato false
per autoConnect
.
Viene aggiunta anche una proprietà BluetoothGatt
. Ciò consente al servizio di chiudere
connessione attiva quando non è
necessario più tempo.
Kotlin
class BluetoothLeService : Service() { ... private var bluetoothGatt: BluetoothGatt? = null ... fun connect(address: String): Boolean { bluetoothAdapter?.let { adapter -> try { val device = adapter.getRemoteDevice(address) // connect to the GATT server on the device bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback) return true } catch (exception: IllegalArgumentException) { Log.w(TAG, "Device not found with provided address. Unable to connect.") return false } } ?: run { Log.w(TAG, "BluetoothAdapter not initialized") return false } } }
Java
class BluetoothLeService extends Service { ... private BluetoothGatt bluetoothGatt; ... public boolean connect(final String address) { if (bluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } try { final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address); // connect to the GATT server on the device bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback); return true; } catch (IllegalArgumentException exception) { Log.w(TAG, "Device not found with provided address. Unable to connect."); return false; } } }
Aggiornamenti sulle trasmissioni
Quando il server si connette o si disconnette dal server GATT, deve inviare una notifica l'attività del nuovo stato. Puoi farlo in vari modi. La nell'esempio che segue utilizza broadcasts per inviare il informazioni dal servizio all'attività.
Il servizio dichiara una funzione per trasmettere il nuovo stato. Questa funzione utilizza
in una stringa di azioni che viene passata a un oggetto Intent
prima di essere trasmessa
al sistema.
Kotlin
private fun broadcastUpdate(action: String) { val intent = Intent(action) sendBroadcast(intent) }
Java
private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); sendBroadcast(intent); }
Una volta impostata, la funzione broadcast viene utilizzata all'interno
BluetoothGattCallback
per inviare informazioni sullo stato della connessione con
server GATT. Sono dichiarate le costanti e lo stato di connessione attuale del servizio
nel servizio che rappresenta le azioni Intent
.
Kotlin
class BluetoothLeService : Service() { private var connectionState = STATE_DISCONNECTED private val bluetoothGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (newState == BluetoothProfile.STATE_CONNECTED) { // successfully connected to the GATT Server connectionState = STATE_CONNECTED broadcastUpdate(ACTION_GATT_CONNECTED) } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // disconnected from the GATT Server connectionState = STATE_DISCONNECTED broadcastUpdate(ACTION_GATT_DISCONNECTED) } } } ... companion object { const val ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED" const val ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED" private const val STATE_DISCONNECTED = 0 private const val STATE_CONNECTED = 2 } }
Java
class BluetoothLeService extends Service { public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTED = 2; private int connectionState; ... private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { // successfully connected to the GATT Server connectionState = STATE_CONNECTED; broadcastUpdate(ACTION_GATT_CONNECTED); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // disconnected from the GATT Server connectionState = STATE_DISCONNECTED; broadcastUpdate(ACTION_GATT_DISCONNECTED); } } }; … }
Ascolta gli aggiornamenti nell'attività
Quando il servizio trasmette l'aggiornamento della connessione, l'attività deve
implementare una BroadcastReceiver
.
Registra questo destinatario durante la configurazione dell'attività e annulla la registrazione quando
l'attività lascia lo schermo. Ascoltando gli eventi del servizio,
l'attività sia in grado di aggiornare l'interfaccia utente in base allo stato
stato della connessione con il dispositivo BLE.
Kotlin
class DeviceControlActivity : AppCompatActivity() { ... private val gattUpdateReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { BluetoothLeService.ACTION_GATT_CONNECTED -> { connected = true updateConnectionState(R.string.connected) } BluetoothLeService.ACTION_GATT_DISCONNECTED -> { connected = false updateConnectionState(R.string.disconnected) } } } } override fun onResume() { super.onResume() registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter()) if (bluetoothService != null) { val result = bluetoothService!!.connect(deviceAddress) Log.d(DeviceControlsActivity.TAG, "Connect request result=$result") } } override fun onPause() { super.onPause() unregisterReceiver(gattUpdateReceiver) } private fun makeGattUpdateIntentFilter(): IntentFilter? { return IntentFilter().apply { addAction(BluetoothLeService.ACTION_GATT_CONNECTED) addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED) } } }
Java
class DeviceControlsActivity extends AppCompatActivity { ... private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { connected = true; updateConnectionState(R.string.connected); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { connected = false; updateConnectionState(R.string.disconnected); } } }; @Override protected void onResume() { super.onResume(); registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter()); if (bluetoothService != null) { final boolean result = bluetoothService.connect(deviceAddress); Log.d(TAG, "Connect request result=" + result); } } @Override protected void onPause() { super.onPause(); unregisterReceiver(gattUpdateReceiver); } private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); return intentFilter; } }
In Trasferisci dati BLE,
BroadcastReceiver
viene utilizzato anche per comunicare il Service Discovery come
nonché i dati caratteristici del dispositivo.
Chiudi connessione GATT
Un passaggio importante quando si gestiscono le connessioni Bluetooth è la
quando hai finito. A questo scopo, chiama il close()
sull'oggetto BluetoothGatt
. Nell'esempio seguente, il servizio
contiene il riferimento a BluetoothGatt
. Quando l'attività si separa dal
la connessione è chiusa per evitare di scaricare la batteria del dispositivo.
Kotlin
class BluetoothLeService : Service() { ... override fun onUnbind(intent: Intent?): Boolean { close() return super.onUnbind(intent) } private fun close() { bluetoothGatt?.let { gatt -> gatt.close() bluetoothGatt = null } } }
Java
class BluetoothLeService extends Service { ... @Override public boolean onUnbind(Intent intent) { close(); return super.onUnbind(intent); } private void close() { if (bluetoothGatt == null) { Return; } bluetoothGatt.close(); bluetoothGatt = null; } }