اولین قدم در تعامل با دستگاه 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;
}
}