Bir BDE cihazıyla etkileşim kurmanın ilk adımı cihaza bağlanmaktır. Daha ayrıntılı belirtmek gerekirse cihaz üzerinde GATT sunucusuna bağlanma. BDE cihazında GATT sunucusuna bağlanmak için connectGatt()
yöntemini kullanın. Bu yöntem üç parametre alır: bir Context
nesnesi, autoConnect
(BLE cihazına otomatik olarak bağlanıp bağlanmayacağını belirten bir boole) ve bir BluetoothGattCallback
referansı:
Kotlin
var bluetoothGatt: BluetoothGatt? = null ... bluetoothGatt = device.connectGatt(this, false, gattCallback)
Java
bluetoothGatt = device.connectGatt(this, false, gattCallback);
Bu bağlantı, BDE cihazı tarafından barındırılan GATT sunucusuna bağlanır ve GATT istemci işlemlerini yürütmek için kullanabileceğiniz bir BluetoothGatt
örneği döndürür. Arayan (Android uygulaması)
GATT istemcisidir. BluetoothGattCallback
, istemciye bağlantı durumu gibi sonuçların yanı sıra diğer GATT istemci işlemlerini göndermek için kullanılır.
Bağlı hizmet ayarla
Aşağıdaki örnekte BLE uygulaması, Bluetooth cihazlara bağlanmak, cihaz verilerini görüntülemek ve cihaz tarafından desteklenen GATT hizmetlerini ve özelliklerini görüntülemek için bir etkinlik (DeviceControlActivity
) sağlar. Bu etkinlik, kullanıcı girişine bağlı olarak BluetoothLeService
adlı Service
ile iletişim kurar ve BLE API üzerinden BLE cihazıyla etkileşim kurar. İletişim, etkinliğin cihazlara bağlanmasına ve BluetoothLeService
'ye bağlanmasına ve işlevleri çağırmasına olanak tanıyan bağlı bir hizmet kullanılarak gerçekleştirilir. BluetoothLeService
, etkinlik için hizmete erişim sağlayan bir Binder
uygulamasına ihtiyaç duyar.
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; } } }
Etkinlik; bindService()
kullanarak hizmeti başlatabilir, hizmeti başlatmak için bir Intent
geçişini, bağlantı ve bağlantı kesme etkinliklerini dinlemek için ServiceConnection
uygulamasını ve ek bağlantı seçeneklerini belirtmek için bir işareti kullanabilir.
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); } }
BluetoothAdapter'ı kurma
Hizmet bağlandıktan sonra BluetoothAdapter
'e erişmesi gerekir. Adaptörün cihazda mevcut olup olmadığını kontrol etmelidir. Daha fazla bilgi için BluetoothAdapter
ile ilgili Bluetooth'u kurma bölümünü okuyun. Aşağıdaki örnekte bu kurulum kodu, işlemin başarılı olduğunu belirten bir Boolean
değeri döndüren bir initialize()
işlevi içine sarmalanmıştır.
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; } ... }
Etkinlik, bu işlevi kendi ServiceConnection
uygulaması içinde çağırır.
initialize()
işlevinden yanlış bir döndürülen değer işleme, uygulamanıza bağlıdır. Kullanıcıya, geçerli cihazın Bluetooth işlemini desteklemediğini belirten bir hata mesajı gösterebilir veya Bluetooth'un çalışmasını gerektiren özellikleri devre dışı bırakabilirsiniz. Aşağıdaki örnekte, finish()
etkinliği kullanıcıyı bir önceki ekrana geri göndermek için çağrılmıştır.
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; } }; ... }
Bir cihaza bağlan
BluetoothService
başlatıldıktan sonra BDE cihazına bağlanabilir.
Etkinliğin, bağlantıyı başlatabilmesi için cihaz adresini hizmete göndermesi gerekir. Hizmet, cihaza erişmek için ilk olarak BluetoothAdapter
cihazında getRemoteDevice()
numarasını arar. Bağdaştırıcı bu adrese sahip bir cihaz bulamazsa getRemoteDevice()
, IllegalArgumentException
gönderir.
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 }
Hizmet başlatıldıktan sonra DeviceControlActivity
, bu connect()
işlevini çağırır. Etkinlik, BDE cihazının adresine iletilmelidir. Aşağıdaki örnekte, cihaz adresi ekstra bir amaç olarak etkinliğe aktarılır.
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; } };
GATT geri çağırmayı bildir
Etkinlik, hizmete hangi cihazın bağlanacağını ve hizmetin cihaza bağlanacağını bildirdikten sonra, hizmetin BLE cihazındaki GATT sunucusuna bağlanması gerekir. Bu bağlantı; bağlantı durumu, hizmet keşfi, özellik okumaları ve karakteristik bildirimler hakkında bildirim almak için bir BluetoothGattCallback
gerektirir.
Bu konu, bağlantı durumu bildirimlerine odaklanır. Hizmet keşfi, özellik okumaları ve özellik bildirimlerinin nasıl yapılacağını öğrenmek için BLE verilerini aktarma bölümüne bakın.
Cihazın GATT sunucusuyla bağlantı değiştiğinde onConnectionStateChange()
işlevi tetiklenir.
Aşağıdaki örnekte, geri çağırma Service
sınıfında tanımlanmıştır. Bu nedenle, hizmet bağlandığında BluetoothDevice
ile kullanılabilir.
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 } } };
GATT hizmetine bağlan
BluetoothGattCallback
bildirildikten sonra hizmet, cihazdaki GATT hizmetine bağlanmak için connect()
işlevindeki BluetoothDevice
nesnesini kullanabilir.
connectGatt()
işlevi kullanılır. Bunun için Context
nesnesi, autoConnect
boole işareti ve BluetoothGattCallback
gerekir. Bu örnekte, uygulama doğrudan BDE cihazına bağlandığından autoConnect
için false
iletilir.
Ayrıca bir BluetoothGatt
özelliği eklenir. Bu sayede hizmet, artık ihtiyaç duyulmadığında bağlantıyı kapatabilir.
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 BluetoothService 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; } } }
Yayın güncellemeleri
Sunucu, GATT sunucusuna bağlandığında veya sunucu ile bağlantısı kesildiğinde, yeni durumun etkinliğini bildirmesi gerekir. Bunu yapmanın birkaç yolu vardır. Aşağıdaki örnekte, bilgileri hizmetten etkinliğe göndermek için yayınlar kullanılmıştır.
Hizmet, yeni durumu yayınlamak için bir işlev tanımlar. Bu işlev, sisteme yayınlanmadan önce bir Intent
nesnesine geçirilen bir işlem dizesini alır.
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); }
Yayın işlevi etkinleştirildikten sonra, GATT sunucusuyla bağlantı durumu hakkında bilgi göndermek için BluetoothGattCallback
içinde kullanılır. Sabitler ve hizmetin mevcut bağlantı durumu, Intent
işlemlerini temsil eden hizmette belirtilir.
Kotlin
class BluetoothService : 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 BluetoothService 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); } } }; … }
Etkinlikteki güncellemeleri dinleyin
Hizmet, bağlantı güncellemelerini yayınladıktan sonra etkinliğin bir BroadcastReceiver
uygulaması gerekir.
Etkinliği ayarlarken bu alıcıyı kaydedin ve etkinlik ekrandan ayrılırken
kaydını iptal edin. Etkinlik, hizmetten gelen etkinlikleri dinleyerek kullanıcı arayüzünü BDE cihazıyla mevcut bağlantı durumuna göre güncelleyebilir.
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; } }
BLE verilerini aktarma işleminde BroadcastReceiver
, hizmet keşfini ve cihazdan alınan karakteristik verileri iletmek için de kullanılır.
GATT bağlantısını kapat
Bluetooth bağlantılarıyla ilgili önemli adımlardan biri, işiniz bittiğinde bağlantıyı kapatmaktır. Bunu yapmak için BluetoothGatt
nesnesinde close()
işlevini çağırın. Aşağıdaki örnekte hizmet, BluetoothGatt
referansını barındırır. Etkinliğin hizmet ile bağlantısı kesildiğinde, cihazın pilinin boşalmasını önlemek için bağlantı kapatılır.
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 BluetoothService extends Service { ... @Override public boolean onUnbind(Intent intent) { close(); return super.onUnbind(intent); } private void close() { if (bluetoothGatt == null) { Return; } bluetoothGatt.close(); bluetoothGatt = null; } }