Pierwszym krokiem podczas interakcji z urządzeniem BLE jest nawiązanie z nim połączenia. Więcej
a zwłaszcza z serwerem GATT na urządzeniu. Łączenie z GATT
na urządzeniu BLE, użyj
connectGatt()
. Przyjmuje ona 3 parametry:
Context
obiekt autoConnect
(wartość logiczna)
wskazujący, czy automatycznie połączyć się z urządzeniem BLE, gdy tylko
) oraz odniesienie do
BluetoothGattCallback
:
var bluetoothGatt: BluetoothGatt? = null
...
bluetoothGatt = device.connectGatt(this, false, gattCallback)
bluetoothGatt = device.connectGatt(this, false, gattCallback);
Łączy się z serwerem GATT hostowanym przez urządzenie BLE i zwraca
BluetoothGatt
, czyli
za pomocą których możesz przeprowadzać operacje klienta w GATT. Rozmówca (aplikacja na Androida)
jest klient GATT.
Usługa BluetoothGattCallback
jest używana do dostarczania klientowi wyników, takich jak:
stanu połączenia oraz innych operacji na kliencie GATT.
Konfigurowanie powiązanej usługi
W poniższym przykładzie aplikacja BLE udostępnia aktywność
(DeviceControlActivity
) aby połączyć się z urządzeniami Bluetooth, wyświetlić dane z urządzenia,
oraz wyświetlać usługi i cechy GATT obsługiwane przez urządzenie. Siedziba
na dane wejściowe użytkownika, aktywność ta komunikuje się z
Service
o nazwie BluetoothLeService
, która
współpracuje z urządzeniem BLE przez interfejs BLE API. Komunikacja jest
wykonane przy użyciu powiązanej usługi, która umożliwia
działanie związane z łączeniem się z obiektem BluetoothLeService
i wywoływaniem funkcji,
połączyć urządzenia. BluetoothLeService
wymaga:
Implementacja Binder
, która zapewnia dostęp do
i usługi związane z aktywnością.
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
}
}
}
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;
}
}
}
Działanie może uruchomić usługę za pomocą
bindService()
z wynikiem Intent
, aby rozpocząć
usługa, ServiceConnection
wdrożenia, aby nasłuchiwać zdarzeń połączenia i rozłączenia, a także flaga
aby określić dodatkowe opcje połączenia.
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)
}
}
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);
}
}
Skonfiguruj adapter Bluetooth
Powiązanie z usługą wymaga dostępu do
BluetoothAdapter
Powinna
Sprawdź, czy w urządzeniu jest dostępna przejściówka. Przeczytaj sekcję Konfiguracja
Bluetooth, by dowiedzieć się więcej
BluetoothAdapter
. W poniższym przykładzie kod konfiguracji umieszcza się w
Funkcja initialize()
, która zwraca wartość Boolean
wskazującą powodzenie.
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
}
...
}
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;
}
...
}
Ta aktywność wywołuje tę funkcję w ramach implementacji ServiceConnection
.
Obsługa wartości zwróconej przez funkcję initialize()
zależy od
aplikacji. Możesz wyświetlić użytkownikowi komunikat o błędzie informujący, że
Obecne urządzenie nie obsługuje funkcji Bluetooth lub wyłącz żadne funkcje
które wymagają Bluetootha do działania. W poniższym przykładzie
Metoda finish()
zostaje wywołana dla aktywności
aby przenieść użytkownika z powrotem na poprzedni ekran.
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
}
}
...
}
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;
}
};
...
}
Połącz się z urządzeniem
Po zainicjowaniu instancji BluetoothLeService
może się ona połączyć z BLE
urządzenia. Aktywność musi wysłać adres urządzenia do usługi, aby mogła
zainicjuj połączenie. Usługa najpierw wywoła metodę
getRemoteDevice()
na urządzeniu BluetoothAdapter
, aby uzyskać dostęp do urządzenia. Jeśli adapter nie może znaleźć
urządzenia z tym adresem, getRemoteDevice()
przesyła
IllegalArgumentException
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
}
}
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
}
Funkcja DeviceControlActivity
wywołuje funkcję connect()
, gdy usługa jest
zainicjowano. Aktywność musi być przekazywana w adresie urządzenia BLE. W
W tym przykładzie adres urządzenia jest przekazywany do aktywności jako intencja
dodatkowe.
// 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
}
}
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;
}
};
Zadeklarowanie wywołania zwrotnego GATT
Gdy aktywność poinformuje usługę, z którym urządzeniem i usługą się połączyć
jeśli połączy się z urządzeniem, usługa musi połączyć się z serwerem GATT
urządzenie BLE. To połączenie wymaga BluetoothGattCallback
, aby odbierać wiadomości
powiadomienia o stanie połączenia, wykrywanie usług, charakterystyka
odczyty i powiadomienia o charakterystycznych cechach.
Ten temat dotyczy powiadomień o stanie połączenia. Zobacz Przenoszenie BLE , aby dowiedzieć się, jak osiągnąć skuteczność wykrywanie usług, odczyty cech i charakterystyki żądań powiadomienia.
onConnectionStateChange()
jest wyzwalana po zmianie połączenia z serwerem GATT urządzenia.
W poniższym przykładzie wywołanie zwrotne jest zdefiniowane w klasie Service
, więc
można używać z
BluetoothDevice
raz
z inną usługą.
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
}
}
}
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
}
}
};
Połącz z usługą GATT
Po zadeklarowaniu obiektu BluetoothGattCallback
usługa może używać parametru
obiekt BluetoothDevice
z funkcji connect()
, który ma zostać połączony z GATT.
usłudze dostępnej na urządzeniu.
connectGatt()
. Wymaga to obiektu Context
i wartości logicznej autoConnect
flaga i BluetoothGattCallback
. W tym przykładzie aplikacja jest bezpośrednio
nawiązywane jest połączenie z urządzeniem BLE, więc sygnał false
jest przekazywany dla autoConnect
.
Dodano także właściwość BluetoothGatt
. Umożliwi to usłudze zamknięcie
, gdy nie jest
jest potrzebna dłużej.
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
}
}
}
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;
}
}
}
Aktualne informacje o transmisjach
Gdy serwer łączy się z serwerem GATT lub się od niego rozłącza, musi powiadomić o tym działania nowego stanu. Istnieje kilka sposobów wykonania tej czynności. poniższy przykład wykorzystuje transmisje do wysłania informacji między usługą a aktywnością.
Usługa deklaruje funkcję rozgłaszającą nowy stan. Ta funkcja wykonuje
w ciągu działania, który jest przekazywany do obiektu Intent
przed transmisją
do systemu.
private fun broadcastUpdate(action: String) {
val intent = Intent(action)
sendBroadcast(intent)
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
Po włączeniu funkcji transmisji jest ona wykorzystywana w
BluetoothGattCallback
, aby wysyłać informacje o stanie połączenia z
Serwer GATT. Deklarowane są stałe i bieżący stan połączenia usługi
w usłudze reprezentującej działania Intent
.
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
}
}
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);
}
}
};
…
}
Wykrywaj aktualizacje dotyczące aktywności
Gdy usługa przekaże aktualizacje połączenia, aktywność musi
wdrożyć element BroadcastReceiver
.
Zarejestruj tego odbiorcę podczas konfigurowania aktywności i wyrejestruj go, gdy
Aktywność opuszcza ekran. Nasłuchując zdarzeń z usługi,
działanie może zaktualizować interfejs użytkownika na podstawie bieżącego
stanu połączenia z urządzeniem BLE.
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)
}
}
}
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;
}
}
W sekcji Przenieś dane BLE:
BroadcastReceiver
służy też do przekazywania wykrywania usług jako
a także dane charakterystyczne urządzenia.
Zamknij połączenie GATT
Ważnym krokiem podczas obsługi połączeń Bluetooth jest zamknięcie
gdy skończysz korzystać z internetu. Aby to zrobić, wywołaj close()
na obiekcie BluetoothGatt
. W poniższym przykładzie usługa
zawiera odniesienie do elementu BluetoothGatt
. Po usunięciu powiązania aktywności z
, połączenie zostaje zamknięte, aby uniknąć rozładowywania baterii urządzenia.
class BluetoothLeService : Service() {
...
override fun onUnbind(intent: Intent?): Boolean {
close()
return super.onUnbind(intent)
}
private fun close() {
bluetoothGatt?.let { gatt ->
gatt.close()
bluetoothGatt = null
}
}
}
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;
}
}