اولین قدم در تعامل با دستگاه BLE، اتصال به آن است. به طور خاص، اتصال به سرور GATT در دستگاه. برای اتصال به سرور GATT در دستگاه BLE، از متد connectGatt()
استفاده کنید. این روش سه پارامتر دارد: یک شی Context
، autoConnect
(یک بولی که نشان میدهد آیا بهمحض در دسترس شدن دستگاه BLE بهطور خودکار به آن متصل میشود)، و یک ارجاع به BluetoothGattCallback
:
کاتلین
var bluetoothGatt: BluetoothGatt? = null ... bluetoothGatt = device.connectGatt(this, false, gattCallback)
جاوا
bluetoothGatt = device.connectGatt(this, false, gattCallback);
این به سرور GATT میزبانی شده توسط دستگاه BLE متصل می شود و یک نمونه BluetoothGatt
را برمی گرداند که می توانید از آن برای انجام عملیات کلاینت GATT استفاده کنید. تماس گیرنده (برنامه اندروید) مشتری GATT است. BluetoothGattCallback
برای ارائه نتایج به مشتری، مانند وضعیت اتصال، و همچنین هرگونه عملیات مشتری GATT دیگر استفاده می شود.
یک سرویس محدود راه اندازی کنید
در مثال زیر، برنامه BLE یک فعالیت ( DeviceControlActivity
) برای اتصال به دستگاههای بلوتوث، نمایش دادههای دستگاه، و نمایش خدمات و ویژگیهای GATT که توسط دستگاه پشتیبانی میشود، ارائه میکند. بر اساس ورودی کاربر، این فعالیت با Service
به نام BluetoothLeService
ارتباط برقرار می کند که از طریق BLE API با دستگاه BLE تعامل دارد. ارتباط با استفاده از یک سرویس محدود انجام میشود که به فعالیت اجازه میدهد به BluetoothLeService
متصل شود و عملکردهای تماس را برای اتصال به دستگاهها برقرار کند. BluetoothLeService
به پیاده سازی Binder
نیاز دارد که دسترسی به سرویس را برای فعالیت فراهم می کند.
کاتلین
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; } } }
این اکتیویتی میتواند سرویس را با استفاده از bindService()
، ارسال یک Intent
برای شروع سرویس، اجرای ServiceConnection
برای گوش دادن به رویدادهای اتصال و قطع، و یک پرچم برای مشخص کردن گزینههای اتصال اضافی، شروع کند.
کاتلین
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); } }
آداپتور بلوتوث را تنظیم کنید
هنگامی که سرویس به آن متصل شد، باید به BluetoothAdapter
دسترسی پیدا کند. باید بررسی کنید که آداپتور در دستگاه موجود است. برای اطلاعات بیشتر در مورد BluetoothAdapter
، تنظیم بلوتوث را بخوانید. مثال زیر این کد راهاندازی را در یک تابع initialize()
میپیچد که یک مقدار Boolean
را نشان میدهد که موفقیت را نشان میدهد.
کاتلین
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; } ... }
فعالیت این تابع را در اجرای ServiceConnection
خود فراخوانی می کند. مدیریت یک مقدار بازگشتی نادرست از تابع initialize()
به برنامه شما بستگی دارد. میتوانید پیام خطایی به کاربر نشان دهید که نشان میدهد دستگاه فعلی از عملکرد بلوتوث پشتیبانی نمیکند یا ویژگیهایی را که برای کار کردن به بلوتوث نیاز دارند غیرفعال کنید. در مثال زیر، finish()
روی اکتیویتی فراخوانی می شود تا کاربر را به صفحه قبلی بازگرداند.
کاتلین
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; } }; ... }
به یک دستگاه متصل شوید
هنگامی که نمونه BluetoothLeService
مقداردهی اولیه شد، می تواند به دستگاه BLE متصل شود. فعالیت باید آدرس دستگاه را به سرویس ارسال کند تا بتواند اتصال را آغاز کند. این سرویس ابتدا getRemoteDevice()
در BluetoothAdapter
برای دسترسی به دستگاه فراخوانی می کند. اگر آداپتور نتواند دستگاهی را با آن آدرس پیدا کند، getRemoteDevice()
یک 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 }
DeviceControlActivity
این تابع connect()
را پس از راه اندازی اولیه سرویس فراخوانی می کند. فعالیت باید در آدرس دستگاه BLE انجام شود. در مثال زیر، آدرس دستگاه به عنوان یک هدف اضافی به فعالیت ارسال می شود.
کاتلین
// 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; } };
اعلام پاسخ به تماس GATT
هنگامی که فعالیت به سرویس می گوید که به کدام دستگاه متصل شود و سرویس به دستگاه متصل می شود، سرویس باید به سرور GATT در دستگاه BLE متصل شود. این اتصال به BluetoothGattCallback
برای دریافت اعلانهای مربوط به وضعیت اتصال، کشف سرویس، خواندن مشخصهها و اعلانهای مشخصه نیاز دارد.
این موضوع بر روی اعلانهای وضعیت اتصال متمرکز است. برای نحوه انجام کشف سرویس، خواندن مشخصه ها و درخواست اعلان های مشخصه، به انتقال داده های BLE مراجعه کنید.
تابع onConnectionStateChange()
زمانی فعال می شود که اتصال به سرور GATT دستگاه تغییر کند. در مثال زیر، callback در کلاس Service
تعریف شده است، بنابراین می توان آن را با BluetoothDevice
پس از اتصال سرویس به آن استفاده کرد.
کاتلین
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 } } };
به سرویس گات متصل شوید
هنگامی که BluetoothGattCallback
اعلام شد، سرویس می تواند از شی BluetoothDevice
از connect()
برای اتصال به سرویس GATT در دستگاه استفاده کند.
تابع connectGatt()
استفاده می شود. این به یک شی Context
، یک پرچم بولین autoConnect
، و BluetoothGattCallback
نیاز دارد. در این مثال، برنامه به طور مستقیم به دستگاه BLE متصل می شود، بنابراین false
برای autoConnect
ارسال می شود.
یک ویژگی BluetoothGatt
نیز اضافه شده است. این به سرویس اجازه می دهد تا زمانی که دیگر به آن نیازی نیست اتصال را ببندد .
کاتلین
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; } } }
به روز رسانی های پخش
هنگامی که سرور به سرور گات متصل یا قطع می شود، باید فعالیت وضعیت جدید را مطلع کند. چندین راه برای انجام این کار وجود دارد. مثال زیر از پخش برای ارسال اطلاعات از سرویس به فعالیت استفاده می کند.
این سرویس عملکردی را برای پخش وضعیت جدید اعلام می کند. این تابع یک رشته عملیاتی را می گیرد که قبل از پخش به سیستم به یک شی Intent
ارسال می شود.
کاتلین
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); }
هنگامی که عملکرد پخش در جای خود قرار گرفت، در BluetoothGattCallback
برای ارسال اطلاعات در مورد وضعیت اتصال با سرور GATT استفاده می شود. ثابت ها و وضعیت اتصال فعلی سرویس در سرویسی که اقدامات 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); } } }; … }
به به روز رسانی در فعالیت گوش دهید
هنگامی که سرویس بهروزرسانیهای اتصال را پخش میکند، فعالیت باید یک BroadcastReceiver
را پیادهسازی کند. هنگام تنظیم فعالیت، این گیرنده را ثبت کنید و زمانی که فعالیت از صفحه خارج شد، آن را لغو ثبت کنید. با گوش دادن به رویدادها از سرویس، فعالیت می تواند رابط کاربری را بر اساس وضعیت اتصال فعلی با دستگاه 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; } }
در انتقال دادههای BLE ، از BroadcastReceiver
نیز برای برقراری ارتباط با کشف سرویس و همچنین دادههای مشخصه از دستگاه استفاده میشود.
اتصال GATT را ببندید
یکی از گامهای مهم هنگام برخورد با اتصالات بلوتوث، بستن اتصال پس از پایان کار با آن است. برای انجام این کار، تابع close()
در شی BluetoothGatt
فراخوانی کنید. در مثال زیر، این سرویس به BluetoothGatt
اشاره دارد. هنگامی که فعالیت از سرویس جدا می شود، برای جلوگیری از تخلیه باتری دستگاه، اتصال بسته می شود.
کاتلین
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; } }