پیدا کردن دستگاه‌های بلوتوث

بااستفاده از BluetoothAdapter، می‌توانید دستگاه‌های بلوتوث راه دور را ازطریق کاوش دستگاه یا با پرس‌وجو از فهرست دستگاه‌های جفت‌شده پیدا کنید.

قبل‌از تلاش برای پیدا کردن دستگاه‌های بلوتوث، مطمئن شوید که اجازه‌های بلوتوث مناسب را دارید و برنامه‌تان را برای بلوتوث راه‌اندازی کرده‌اید.

«یافتن دستگاه» فرایند اسکن کردن است که منطقه محلی را برای یافتن دستگاه‌های دارای بلوتوث جستجو می‌کند و اطلاعاتی درباره هرکدام درخواست می‌کند. به این فرایند گاهی اوقات کاوش، پرس‌وجو، یا اسکن گفته می‌شود. دستگاه بلوتوث اطراف فقط درصورتی به درخواست شناسایی پاسخ می‌دهد که درحال‌حاضر با قابل‌شناسایی بودن، درخواست‌های اطلاعات را بپذیرد. اگر دستگاهی قابل‌شناسایی باشد، با هم‌رسانی برخی اطلاعات، مانند نام دستگاه، کلاس آن، و نشانی MAC منحصربه‌فرد آن، به درخواست شناسایی پاسخ می‌دهد. بااستفاده از این اطلاعات، دستگاهی که فرایند کاوش را انجام می‌دهد می‌تواند انتخاب کند که اتصالی با دستگاه کاوش‌شده برقرار کند.

چون دستگاه‌های یافتنی ممکن است اطلاعاتی درباره مکان کاربر فاش کنند، فرایند کاوش دستگاه به دسترسی به مکان نیاز دارد. اگر برنامه‌تان در دستگاهی استفاده می‌شود که Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) یا بالاتر دارد، به‌جای آن از Companion Device Manager API استفاده کنید. این میانای برنامه‌سازی کاربردی ازطرف برنامه شما دستگاه‌ها را پیدا می‌کند، بنابراین برنامه‌تان نیازی به درخواست اجازه‌های مکان ندارد.

وقتی برای اولین‌بار با دستگاهی از راه دور اتصال برقرار می‌شود، درخواست جفت‌سازی به‌طور خودکار به کاربر ارائه می‌شود. وقتی دستگاهی جفت می‌شود، اطلاعات پایه آن دستگاه (مثل نام، کلاس، و نشانی MAC دستگاه) ذخیره می‌شود و بااستفاده از Bluetooth API قابل‌خواندن است. بااستفاده از نشانی MAC شناخته‌شده برای دستگاه ازراه‌دور، می‌توان در هر زمانی بدون انجام کاوش، اتصالی با آن برقرار کرد، با این فرض که دستگاه هنوز در محدوده باشد.

توجه داشته باشید که بین جفت شدن و متصل شدن تفاوت وجود دارد:

  • جفت شدن یعنی دو دستگاه از وجود یکدیگر مطلع هستند، کلید پیوند مشترکی دارند که می‌تواند برای اصالت‌سنجی استفاده شود، و قادرند اتصال رمزگذاری‌شده‌ای با یکدیگر برقرار کنند.
  • متصل بودن یعنی دستگاه‌ها درحال‌حاضر کانال RFCOMM مشترکی دارند و می‌توانند داده‌ها را بین یکدیگر منتقل کنند. میاناهای برنامه‌سازی کاربردی بلوتوث فعلی نیاز دارند که دستگاه‌ها قبل‌از برقراری اتصال RFCOMM جفت شوند. وقتی اتصال رمزگذاری‌شده‌ای را با میاناهای برنامه‌سازی کاربردی بلوتوث آغاز می‌کنید، جفت‌سازی به‌طور خودکار انجام می‌شود.

بخش‌های زیر نحوه پیدا کردن دستگاه‌هایی را که جفت شده‌اند و نحوه کشف دستگاه‌های جدید را بااستفاده از «کشف دستگاه» توضیح می‌دهد.

پرس‌وجو از دستگاه‌های جفت‌شده

قبل‌از انجام اکتشاف دستگاه، بهتر است مجموعه دستگاه‌های جفت‌شده را پُرسمان کنید تا ببینید آیا دستگاه موردنظر قبلاً شناخته شده است یا نه. برای انجام این کار، با getBondedDevices() تماس بگیرید. این کنش مجموعه‌ای از اشیاء BluetoothDevice را که نشان‌دهنده دستگاه‌های جفت‌شده هستند برمی‌گرداند. برای مثال، می‌توانید همه دستگاه‌های جفت‌شده را جستجو کنید و نام و مک آدرس هر دستگاه را دریافت کنید، همان‌طور که تکه‌کد زیر نشان می‌دهد:

کاتلین

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
   val deviceName = device.name
   val deviceHardwareAddress = device.address // MAC address
}

جاوا

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
   // There are paired devices. Get the name and address of each paired device.
   for (BluetoothDevice device : pairedDevices) {
       String deviceName = device.getName();
       String deviceHardwareAddress = device.getAddress(); // MAC address
   }
}

برای شروع اتصال با دستگاه بلوتوث، تنها چیزی که از شیء BluetoothDevice مرتبط نیاز است، مک آدرس است که با فراخوانی getAddress() آن را بازیابی می‌کنید. می‌توانید درباره ایجاد اتصال در اتصال دستگاه‌های بلوتوث بیشتر بدانید.

کاوش کردن دستگاه‌ها

برای شروع پیدا کردن دستگاه‌ها، startDiscovery() را فراخوانی کنید. این فرایند ناهمگام است و مقدار بولی را برمی‌گرداند که نشان می‌دهد آیا کاوش با موفقیت شروع شده است یا نه. فرایند شناسایی معمولاً شامل اسکن پرس‌وجو به‌مدت حدود ۱۲ ثانیه است و سپس هر دستگاهی که پیدا شود اسکن صفحه می‌شود تا نام بلوتوث آن بازیابی شود.

برای دریافت اطلاعات درباره هر دستگاه شناسایی‌شده، برنامه‌تان باید BroadcastReceiver را برای هدف ACTION_FOUND ثبت کند. سیستم این هدف را برای هر دستگاه همه‌فرستی می‌کند. هدف حاوی فیلدهای اضافی EXTRA_DEVICE و EXTRA_CLASS است که به‌ترتیب حاوی BluetoothDevice و BluetoothClass هستند. تکه‌کد زیر نشان می‌دهد که چگونه می‌توانید برای مدیریت همه‌فرستی هنگام شناسایی دستگاه‌ها ثبت‌نام کنید:

کاتلین

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   // Register for broadcasts when a device is discovered.
   val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
   registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when(action) {
           BluetoothDevice.ACTION_FOUND -> {
               // Discovery has found a device. Get the BluetoothDevice
               // object and its info from the Intent.
               val device: BluetoothDevice =
                       intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
           }
       }
   }
}

override fun onDestroy() {
   super.onDestroy()
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver)
}

جاوا

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...

   // Register for broadcasts when a device is discovered.
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           // Discovery has found a device. Get the BluetoothDevice
           // object and its info from the Intent.
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           String deviceName = device.getName();
           String deviceHardwareAddress = device.getAddress(); // MAC address
       }
   }
};

@Override
protected void onDestroy() {
   super.onDestroy();
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver);
}

برای شروع اتصال با دستگاه بلوتوث، getAddress() را در BluetoothDevice فراخوانی می‌کنید تا مک آدرس مربوطه را بازیابی کنید.

فعال کردن قابلیت شناسایی

برای اینکه دستگاه محلی برای دستگاه‌های دیگر یافتنی شود، startActivityForResult(Intent, int) را با هدف ACTION_REQUEST_DISCOVERABLE فراخوانی کنید. این کار درخواستی برای فعال کردن حالت قابل‌شناسایی سیستم بدون نیاز به پیمایش به برنامه «تنظیمات» صادر می‌کند، که باعث توقف برنامه شما می‌شود. به‌طور پیش‌فرض، دستگاه به‌مدت دو دقیقه قابل‌شناسایی می‌شود. می‌توانید با افزودن EXTRA_DISCOVERABLE_DURATION اضافی، مدت زمان متفاوتی را تا پنج دقیقه تعریف کنید.

تکه‌کد زیر دستگاه را برای پنج دقیقه در حالت قابل‌شناسایی قرار می‌دهد:

کاتلین

val requestCode = 1;
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
   putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivityForResult(discoverableIntent, requestCode)

جاوا

int requestCode = 1;
Intent discoverableIntent =
       new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, requestCode);


شکل ۲: کادر گفتگوی فعال کردن قابلیت شناسایی.

همان‌طور که در شکل ۲ نشان داده شده است، کادر گفتگویی نمایش داده می‌شود که از کاربر اجازه می‌خواهد دستگاه را قابل‌شناسایی کند. اگر کاربر «اجازه دادن» را انتخاب کند، دستگاه برای مدت زمان مشخص‌شده قابل‌شناسایی می‌شود. سپس فعالیت شما تماسی با onActivityResult() فراخوانی برگشتی دریافت می‌کند، با کد نتیجه‌ای برابر با مدت زمانی که دستگاه قابل‌شناسایی است. اگر کاربر «رد کردن» را انتخاب کند یا خطایی رخ دهد، کد نتیجه RESULT_CANCELED است.

دستگاه در مدت زمان اختصاص‌داده‌شده بی‌صدا در حالت قابل‌شناسایی باقی می‌ماند. برای دریافت اعلان هنگام تغییر حالت قابل‌کشف، یک BroadcastReceiver برای هدف ACTION_SCAN_MODE_CHANGED ثبت کنید. این هدف حاوی فیلدهای اضافی EXTRA_SCAN_MODE و EXTRA_PREVIOUS_SCAN_MODE است که به‌ترتیب حالت اسکن جدید و قدیمی را ارائه می‌دهند. مقادیر احتمالی برای هر گزینه اضافی به شرح زیر است:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
دستگاه در حالت یافتنی است.
SCAN_MODE_CONNECTABLE
دستگاه در حالت قابل‌شناسایی نیست اما همچنان می‌تواند اتصال دریافت کند.
SCAN_MODE_NONE
دستگاه در حالت قابل‌شناسایی نیست و نمی‌تواند اتصال دریافت کند.

اگر اتصال به دستگاه از راه دور را شما شروع می‌کنید، نیازی نیست قابلیت شناسایی دستگاه را فعال کنید. فعال کردن قابلیت شناسایی فقط زمانی لازم است که بخواهید برنامه‌تان میزبان سوکت سروری باشد که اتصال‌های ورودی را می‌پذیرد، زیرا دستگاه‌های از راه دور باید بتوانند قبل‌از شروع اتصال به دستگاه‌های دیگر، آن دستگاه‌ها را شناسایی کنند.