مقدمه‌ای بر Bluetooth  در Android

پلتفرم اندروید، شامل پشتیبانی برای شبکه بلوتوث است که به دستگاه اجازه می‌دهد تا بدون سیم، اطلاعات را با سایر دستگاه‌های بلوتوث مبادله کند. چهارچوب اپلیکیشن، از طریق APlهای بلوتوث Android ، دسترسی کاربردی به بلوتوث را امکان پذیر می‌کند. این APlها، به اپلیکیشن‌ها اجازه می‌دهند که به صورت وایرلس، به سایر دستگاه‌های بلوتوث متصل شوند. همچنین، قابلیت‌های وایرلسی ( ویکی پدیا ) نقطه به نقطه یا چند نقطه‌ای را فعال می‌کنند. با استفاده از APl های بلوتوث، اپلیکیشن اندروید می‌تواند موارد زیر را اجرا کند:

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

در این مقاله به آموزش کار با بلوتوث در برنامه نویسی اندروید پرداخته‌ایم. در نظر داشته‌باشید که در این متن، روی بلوتوث کلاسیک تمرکز کرده‌ایم. کلاس Bluetooth adapter کلاسیک، انتخاب درستی برای فعالیت‌هایی است که باتری بیشتری مصرف می‌کنند. این فعالیت‌ها شامل streaming  و ارتباط بین دستگاه‌های اندروید است. دستگاه‌های اندروید با مصرف باتری کمتر، Android 4.3 (API level 18)  ، APl  برای کلاس Bluetoothadapter با انرژی پایین را پشتیبانی می‌کنند.

این مقاله، نمایه‌های مختلف بلوتوث، از جمله نمایه دستگاه سلامت را توصیف می کند. سپس توضیح می‌دهد که چگونه از API بلوتوث اندروید، برای انجام چهار مرحله اصلی لازم برای برقراری ارتباط، باید استفاده کنید. این مراحل شامل: راه‌اندازی بلوتوث، یافتن دستگاه‌هایی که در منطقه محلی جفت شوند یا در دسترس باشند، اتصال دستگاه‌ها و انتقال داده‌ها بین دستگاه‌ها، هستند.

اطلاعات پایه آموزش کار با بلوتوث در اندروید

اساس ارتباط بین دو دستگاه اندروید با بلوتوث

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

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

مجوز‌های بلوتوث در اندروید

در این قسمت از آموزش کار با بلوتوث در برنامه نویسی اندروید، نحوه ایجاد مجوز یا  permission  را برای bluetooth  یاد می‌گیرید.

برای استفاده از ویژگی‌های بلوتوث در برنامه خود، باید دو مجوز را اعلام کنید. اولین مجوز، BLUETOOTH است. برای ایجاد هر گونه ارتباط بلوتوث مانند درخواست اتصال، پذیرش اتصال و انتقال داده‌ها، به این مجوز نیاز دارید. مجوز دیگری که باید اعلام کنید، ACCESS_FINE_LOCATION است. برنامه اندروید شما، به این مجوز نیاز دارد زیرا با استفاده از اسکن bluetooth می‌توان اطلاعات مکان کاربر را جمع آوری کرد. اطلاعات ممکن است از دستگاه‌ خود کاربر و یا چراغ‌های بلوتوثی که در مکان‌هایی مانند مغازه‌ها و وسایل حمل و نقل استفاده می‌شوند، به دست بیاید.  به عنوان جایگزین، در دستگاه‌هایی که Android 8.0 (API level 26) و بالاتر هستند، می‌توانید از CompanionDeviceManager  استفاده کنید تا بدون نیاز به اجازه مکان، با برنامه خود اسکن دستگاه‌های اندروید در آن محدوده را انجام دهید.

*توجه:اگر برنامه شما، Android 8.0 (API level 26) یا پایین‌تر را هدف قرار می‌دهد، می‌توانید به جای مجوز ACCESS_FINE_LOCATION، مجوز ACCESS_COARSE_LOCATION را اعلام کنید.

اگر می‌خواهید برنامه شما شروع به کشف دستگاه کند یا تنظیمات بلوتوث را تغییر دهد، باید علاوه بر مجوز BLUETOOTH، مجوز BLUETOOTH_ADMIN را نیز اعلام کنید. اکثر برنامه‌ها فقط به منظور کشف دستگاه‌های لوکال بلوتوث به این مجوز نیاز دارند. از قابلیت‌های دیگری که این مجوز ایجاد می‌کند، فقط زمانی باید استفاده کرد که اپلیکیشن، یک تنظیم کننده باتری باشد‌ و تنظیمات بلوتوث را به درخواست کاربر تغییر بدهد.

مجوز‌های بلوتوث را در فایل مانیفست برنامه خود اعلام کنید. برای مثال، به کد زیر توجه کنید:

<manifest ... >
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

  <!-- If your app targets Android 9 or lower, you can declare
       ACCESS_COARSE_LOCATION instead. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  ...
</manifest>

آموزش کار با بلوتوث در برنامه نویسی اندروید: با پروفایل‌ها کار کنید

با شروع از Android 3.0 ، APl کلاس Bluetooth adapter، کار کردن با پروفایل‌های بلوتوث را پشتیبانی می‌کند. نمایه یا پروفایل بلوتوث، رابط بی‌سیم مخصوصی برای ارتباط مبتنی بر Bluetooth بین دستگاه‌ها است. یک مثال، نمایه Hands _Free است. برای اتصال تلفن همراه به هدست بی سیم، هر دو دستگاه باید  نمایه  Hands_ Free  را پشتیبانی کنند.

APl مربوط به Android bluetooth، پیاده‌ سازی نمایه‌های بلوتوث زیر را فراهم می‌کند:

  • Headset

نمایه Headset، از هدست‌های بلوتوث، برای استفاده در تلفن‌های همراه پشتیبانی می‌کند. اندروید، کلاس BluetoothHeadset را که یک پروکسی برای کنترل سرویس هدست بلوتوث است، را فراهم می‌کند. که شامل پروفایل‌های هدست بلوتوث و هندزفری (v1.5) است. کلاس BluetoothHeadset، دستورات AT را پشتیبانی می‌کند.

  • A2DP

نمایه توزیع صدای پیشرفته (A2DP) تعیین می‌کند که چگونه، می‌توان صدای صوتی با کیفیت بالا را از یک دستگاه به دستگاه دیگر، از طریق بلوتوث، منتقل کرد. اندروید، کلاس BluetoothA2dp را که یک پروکسی برای کنترل سرویس A2DP بلوتوث است، فراهم می‌سازد.

  • Health Device

Android 4.0 (API level 14)، پشتیبانی از نمایه دستگاه سلامت بلوتوث (HDP) را پوشش می‌دهد. می‌توانید برنامه‌هایی ایجاد کنید که از بلوتوث برای برقراری ارتباط با دستگاه‌های سلامتی پشتیبان بلوتوث، استفاده می‌کنند. مانند دستگاه‌های اندازه گیری ضربان قلب، دستگاه‌های اندازه گیری خون، دماسنج، مقیاس و سایر دستگاه‌ها.

در این‌ بخش از آموزش کار با بلوتوث در برنامه نویسی اندروید، مراحل اولیه برای کار کردن با پروفایل را برایتان آورده‌ایم:

  • همان طور که در تنظیم بلوتوث توضیح داده شده‌است، آداپتور پیش فرض را دریافت کنید.
  • کد ServiceListener را تنظیم کنید. این شنونده، به مشتریان BluetoothProfile، هنگامی که به سرویس متصل یا از آن جدا شده‌اند، اطلاع می‌دهد.
  • برای برقراری ارتباط با شیء پروکسی پروفایل مرتبط با نمایه، از ()getProfileProxyاستفاده کنید. در مثال زیر، شیء پروکسی پروفایل، نمونه‌ای از BluetoothHeadset است.
  • در ()onServiceConnected، به شیء پروکسی نمایه، رسیدگی کنید.
  • هنگامی که شیء پروکسی پروفایل را دارید، می‌توانید از آن برای نظارت بر وضعیت اتصال و انجام سایر فعالیت‌های مرتبط با آن نمایه، استفاده کنید.

به عنوان مثال، قطعه کد زیر نحوه اتصال به شیء پروکسی BluetoothHeadset را نشان می‌دهد تا بتوانید نمایه هدست را کنترل کنید.

در kotlin :

var bluetoothHeadset: BluetoothHeadset? = null

// Get the default adapter
val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()

private val profileListener = object : BluetoothProfile.ServiceListener {

override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
if (profile == BluetoothProfile.HEADSET) {
bluetoothHeadset = proxy as BluetoothHeadset
}
}

override fun onServiceDisconnected(profile: Int) {
if (profile == BluetoothProfile.HEADSET) {
bluetoothHeadset = null
}
}
}

// Establish connection to the proxy.
bluetoothAdapter?.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET)

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter?.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset)

 

در جاوا :

BluetoothHeadset bluetoothHeadset;

// Get the default adapter
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

private BluetoothProfile.ServiceListener profileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
bluetoothHeadset = (BluetoothHeadset) proxy;
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
bluetoothHeadset = null;
}
}
};

// Establish connection to the proxy.
bluetoothAdapter.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET);

// ... call functions on bluetoothHeadset

// Close proxy connection after use.
bluetoothAdapter.closeProfileProxy(bluetoothHeadset);


دستورات خاص
AT  برای فروشنده

با شروع از Android 3.0 (API level 11) ، برنامه‌ها می‌توانند برای دریافت پخش سیستم، از دستورات AT مخصوص فروشنده که از پیش تعریف و توسط هدست ارسال شده‌اند، استفاده کنند(مانند دستور Plantronics XEVENT). به عنوان مثال، یک برنامه می‌تواند پخش‌هایی را دریافت کند که میزان باتری دستگاه متصل را نشان می‌دهند و می‌توانند به کاربر اطلاع داده یا اقدامات دیگری را در صورت لزوم، انجام دهند. یک گیرنده پخش برای ACTION_VENDOR_SPECIFIC_HEADSET_EVENT بسازید تا دستورات خاص AT برای فروشنده را برای هدست ایجاد کنید.

نمایه دستگاه سلامت در بلوتوث اندروید

Android 4.0 (API level 14)، مشخصات دستگاه سلامت بلوتوث (HDP) را پشتیبانی می‌کند. با این کار می‌توانید برنامه‌هایی را ایجاد کنید که از Bluetooth برای برقراری ارتباط با دستگاه‌های سلامتی پشتیبان بلوتوث استفاده می‌کنند. مانند دستگاه‌های اندازه گیری ضربان قلب، دستگاه‌های اندازه گیری خون، دماسنج و غیره. APl مربوط به Bluetooth health، کلاس‌های BluetoothHealth ، BluetoothHealthCallback  و BluetoothHealthAppConfiguration را پشتیبانی می‌کند.

در آموزش کار با بلوتوث در برنامه نویسی اندروید، برای استفاده از Bluetooth Health API، درک مفاهیم کلیدی HDP مفید است که به شرح زیر می‌باشند:

  • منبع یا source: یک دستگاه سلامتی، مانند مقیاس وزن، اندازه گیرنده گلوکز یا دماسنج، که اطلاعات پزشکی را به یک دستگاه هوشمند مانند موبایل یا تبلت Android منتقل می‌کند.
  • :sink دستگاه هوشمندی که اطلاعات پزشکی را دریافت می‌کند. در یک برنامه Android HDP، سینک توسط شیء Bluetooth BluetoothHealthAppConfiguration نشان داده می‌شود.
  • ثبت یا Registration: برای ثبت یک sink، به منظور برقراری ارتباط با یک دستگاه سلامت خاص استفاده می‌شود.
  • ارتباط یا Connection: فرایند به کار رفته برای باز کردن کانال بین یک دستگاه سلامتی (منبع) و یک دستگاه هوشمند (سینک).

ساخت اپلیکیشن HDP در آموزش کار با بلوتوث در برنامه نویسی اندروید

در این جا، مراحل اساسی ساخت یک برنامه اندروید HDP را برایتان آورده‌ایم:

  • به شیء پروکسی BluetoothHealth مراجعه کنید. مشابه دستگاه‌های هدست معمولی و نمایه A2DP، برای برقراری ارتباط با شیء پروکسی پروفایل، باید از ()getProfileProxy با ServiceListener و نوع نمایه HEALTH استفاده کنید.
  • یک BluetoothHealthCallback ایجاد کنید و یک چارچوب برنامه (BluetoothHealthAppConfiguration) را که به عنوان یک sink سلاما عمل می‌کند، ثبت کنید.
  • اتصال به دستگاه سلامتی را راه اندازی کنید.

*توجه: برخی از دستگاه‌ها، اتصال را به طور خودکار آغاز می‌کنند. انجام این مرحله برای آن‌ها ضروری نیست.

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

 بلوتوث را تنظیم کنید

قبل از اینکه برنامه شما از طریق بلوتوث ارتباط برقرار کند، باید اطمینان حاصل کنید که کلاس Bluetooth adapter در دستگاه پشتیبانی می‌شود و اگر چنین است، از فعال بودن آن نیز مطمئن شوید. اگر بلوتوث پشتیبانی نمی‌شود، باید ویژگی‌های بلوتوث را غیرفعال کنید. اگر بلوتوث پشتیبانی می‌شود، اما غیرفعال است، می‌توانید بلوتوث را فعال کنید اما اپلیکیشن شما را ترک نکند. این تنظیم با استفاده از BluetoothAdapter در دو مرحله انجام می‌شود:

  • BluetoothAdapter: برای هر فعالیت بلوتوثی مورد نیاز است. برای دریافت BluetoothAdapter ، از روش ()getDefaultAdapter استفاده کنید. این روش BluetoothAdapter را برمی‌گرداند که نشان دهنده آداپتور بلوتوث خود دستگاه (رادیو بلوتوث) است. یک آداپتور بلوتوث برای کل سیستم وجود دارد و برنامه شما می‌تواند با استفاده از این کد با آن ارتباط برقرار کند. اگر ()getDefaultAdapter به null  تبدیل شود، دستگاه اندروید از بلوتوث پشتیبانی نمی‌کند.

در کاتلین :

val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
}

در جاوا :

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
}

برای مثال:

 

فعال کردن بلوتوث: باید از فعال بودن بلوتوث اطمینان حاصل کنید. برای بررسی این که آیا بلوتوث در حال حاضر فعال است یا خیر، از isEnabled()  استفاده کنید. اگر این روش نادرست بود، بلوتوث غیرفعال است. برای درخواست فعال کردن بلوتوث، از شروع (اقدام) ACTION_REQUEST_ENABLE با startActivityForResult() استفاده کنید. این روش، برای فعال کردن بلوتوث از طریق تنظیمات سیستم به کار می‌رود(بدون متوقف کردن برنامه شما).

برای مثال:

در کاتلین :

if (bluetoothAdapter?.isEnabled == false) {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
}

در جاوا :

if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

ثابت REQUEST_ENABLE_BT گذر کرده به startActivityForResult() یک عدد صحیح تعریف شده محلی است که باید بزرگ‌تر از 0 باشد. سیستم در اجرای onActivityResult() این ثابت را به عنوان پارامتر requestCode به شما منتقل می‌کند. اگر فعال کردن بلوتوث موفقیت آمیز باشد، فعالیت شما کد نتیجه RESULT_OK را در پاسخ onActivityResult() دریافت می‌کند. اگر بلوتوث به دلیل خطا فعال نشده‌باشد(یا کاربر “نه” را پاسخ دهد)، کد نتیجه، RESULT_CANCELED است.

برنامه شما می‌تواند  پخش ACTION_STATE_CHANGED(که هر زمان وضعیت بلوتوث تغییر کند سیستم آن را پخش می‌کند)را نیز دریافت کند. این پخش شامل قسمت‌های اضافی EXTRA_STATE و EXTRA_PREVIOUS_STATE، به ترتیب حاوی کلاس Bluetooth adapter  جدید و قدیمی است. مقادیر احتمالی این فیلدهای اضافی STATE_TURNING_ON، STATE_ON، STATE_TURNING_OFF و STATE_OFF هستند. اگر برنامه اندروید شما نیاز به شناسایی تغییرات زمان اجرا در شبکه داشته‌باشد، دریافت این پخش می‌تواند مفید باشد.

*نکته: فعال کردن قابلیت کشف به طور خودکار، bluetooth را فعال می‌کند. اگر قصد دارید قبل از انجام فعالیت بلوتوث، قابلیت کشف دستگاه را به طور مداوم فعال کنید، مرحله 2 را که در بالا بیان کردیم،انجام ندهید.

آموزش کار با بلوتوث در اندروید : دستگاه‌ها را پیدا کنید

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

از آنجا که دستگاه‌های قابل کشف ممکن است اطلاعات مربوط به مکان کاربر را نشان دهند، فرایند کشف دستگاه نیاز به دسترسی به location دارد. اگر اپلیکیشن شما در دستگاهی با Android 8.0 (API level 26) یا بالاتر استفاده می‌شود، از Companion Device Manager API استفاده کنید. این API، کشف دستگاه را از طرف برنامه شما انجام می‌دهد، بنابراین برنامه نیازی به درخواست مجوز مکان ندارد.

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

در این بخش از آموزش کار با بلوتوث در برنامه نویسی اندروید، توجه کنید که بین جفت شدن و اتصال، تفاوت وجود دارد:

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

در بخش‌های بعدی، نحوه یافتن دستگاه‌های جفت شده یا کشف دستگاه‌های جدید، با استفاده از “دستگاه کشف” شرح داده شده‌است.

*توجه: دستگاه‌های دارای سیستم عامل Android به طور پیش فرض قابل کشف نیستند. کاربر می‌تواند از طریق تنظیمات سیستم برای مدت محدودی دستگاه را قابل شناسایی کند، یا یک برنامه می‌تواند بدون خروج از برنامه، از کاربر بخواهد که قابلیت کشف شدن دستگاه Android را فعال کند.

جستجوی دستگاه های جفت شده

در این بخش از آموزش کار با بلوتوث در اندروید، بیاموزید که قبل از انجام کشف دستگاه، لازم است مجموعه دستگاه‌های جفت شده را جستجو کنید تا ببینید آیا دستگاه مورد نظر از قبل شناخته شده‌است یا خیر. برای این کار، از getBondedDevice() استفاده کنید. این کد مجموعه‌ای از اشیا BluetoothDevice را نشان می‌دهد که نمایانگر دستگاه‌های جفت شده هستند. به عنوان مثال، می‌توانید همه دستگاه‌های جفت شده را جستجو کرده و نام و آدرس MAC هر دستگاه را بدست آورید.

برای مثال:

در کاتلین :

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

در جاوا :

s();

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
}
}

 

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

دستگاه‌ها را کشف کنید

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

برای دریافت اطلاعات در مورد دستگاه کشف شده، برنامه شما باید 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);
}

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

*احتیاط: با انجام کشف دستگاه، مقدار زیادی از منابع آداپتور بلوتوث مصرف می‌شود. بعد از اینکه دستگاهی برای اتصال پیدا کردید، مطمئن باشید که قبل از اقدام به اتصال، با cancelDiscovery() کشف را متوقف کنید. همچنین، هنگام اتصال به دستگاه، نباید کشف را انجام دهید زیرا روند کشف، پهنای باند موجود برای اتصال را به میزان قابل توجهی کاهش می‌دهد.

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

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

* احتیاط: اگر مقدار EXTRA_DISCOVERABLE_DURATION را 0 قرار دهید، دستگاه همیشه قابل کشف خواهد بود. این پیکربندی، ناامن است و بنابراین به شدت توصیه می‌شود که از ان استفاده نکنید.

قطعه کد زیر، دستگاه را برای مدت 5 دقیقه(300 ثانیه) قابل شناسایی می‌کند:

در کاتلین :

val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivity(discoverableIntent)

در جاوا :

Intent discoverableIntent =
new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

 

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

* توجه: اگر بلوتوث بر روی دستگاه فعال نشده‌است، قابل شناسایی بودن دستگاه به طور خودکار bluetooth را فعال می‌کند.

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

  • SCAN_MODE_CONNECTABLE_DISCOVERABLE

دستگاه در حالت قابل کشف است.

  • SCAN_MODE_CONNECTABLE

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

  • SCAN_MODE_NONE

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

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

نکته
مقاله پیشنهادی: آموزش session در اندروید

آموزش کار با بلوتوث در اندروید : اتصال به دستگاه‌ها

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

سرور و سرویس گیرنده، زمانی به یکدیگر متصل در نظر گرفته می‌شوند که هرکدام دارای یک BluetoothSocket متصل در همان کانال RFCOMM باشند. در این مرحله، هر دستگاه می‌تواند جریان ورودی و خروجی را بدست آورد و انتقال داده می‌تواند آغاز شود.

در بخش بعدی، نحوه آغاز ارتباط بین دو دستگاه به شما آموزش داده می‌شود.

تکنیک.های اتصال

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

*توجه: اگر دو دستگاه قبلاً جفت نشده‌اند، در چارچوب Android  در هنگام اتصال، یک اعلان درخواست مکالمه یا گفتگو به کاربر نشان داده می‌شود. بنابراین، هنگامی که برنامه شما سعی در اتصال دستگاه‌ها دارد، این کار انجام نمی‌شود. لازم نیست نگران جفت شدن یا نشدن دستگاه‌ها باشید. اتصال RFCOMM شما تا زمانی که کاربر با موفقیت دو دستگاه را جفت کند، مسدود می‌شود. اگر کاربر جفت شدن را رد کند یا پروسه جفت شدن با شکست مواجه شود و یا زمان آن به پایان برسد، این تلاش ناموفق خواهد بود‌.

اتصال به عنوان سرور

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

برای راه اندازی سوکت سرور و پذیرش اتصال، مراحل زیر را دنبال کنید:

  • با استفاده از ،BluetoothServerSocket()listenUsingRfcommWithServiceRecord را دریافت کنید.

رشته, یک نام قابل شناسایی از سرویس شماست که سیستم به طور خودکار، آن را در ورودی پایگاه داده پروتکل کشف سرویس جدید (SDP) روی دستگاه می‌نویسد. انتخاب نام دلخواه است و می‌تواند نام برنامه شما باشد. شناسه جهانی منحصر به فرد (UUID) نیز، در قسمت ورودی SDP گنجانده شده و اساس اتصال با دستگاه سرویس گیرنده است. یعنی وقتی مشتری سعی در اتصال به این دستگاه را دارد، UUID ای را حمل می‌کند که منحصراً سرویسی را که می‌خواهد با آن متصل شود، شناسایی می‌کند. برای پذیرش اتصال، این UUID‌ها باید مطابقت داشته‌باشند.

UUID یک قالب استاندارد 128 بیتی برای شناسه رشته‌ای است که برای شناسایی منحصر به فرد اطلاعات استفاده می‌شود. ویژگی UUID این است که به اندازه کافی بزرگ است و می‌توانید هر شناسه تصادفی را انتخاب کنید که با هیچ شناسه دیگری در تضاد نیست. در این حالت، برای شناسایی منحصر به فرد سرویس بلوتوث، برنامه اندروید شما استفاده می‌شود. برای دریافت UUID به منظور استفاده در برنامه خود، می‌توانید از یکی از انواع مولدهای تصادفی UUID در وب استفاده کنید. سپس یک UUID را با fromString (String) به صورت اولیه مقدار دهی کنید.

  • با استفاده از Accept() شروع به جستجو برای درخواست‌های اتصال کنید.

این یک دستور مسدود کننده است. وقتی ارتباطی پذیرفته می‌شود یا مورد استثنایی رخ داده است، دستور باز می‌گردد. اتصال فقط زمانی پذیرفته می‌شود که یک دستگاه از راه دور، درخواست اتصال حاوی UUID را ارسال کند که با اتصال ثبت شده در سوکت سرور مطابقت داشته‌باشد. در صورت موفقیت، Accept() بلوتوث سوکت متصل را برمی گرداند.

  • اگر می‌خواهید اتصالات اضافی را بپذیرید، از close() استفاده کنید.

این روش، سوکت سرور و تمام منابع آن را آزاد می‌کند. اما BluetoothSocket متصل را که با پذیرش برگردانده شده، نمی‌بندد. برخلاف TCP / IP، RFCOMM هر بار فقط یک سرویس گیرنده متصل را در هر کانال ممکن می‌کند. بنابراین در اکثر موارد، بلافاصله پس از پذیرش سوکت متصل، اتصال close() در BluetoothServerSocket مناسب است.

از آنجا که دستور accept() یک دستور مسدود کننده است، بنابراین نباید در رشته فعالیت UI، فعالیت اصلی اجرا شود تا برنامه اندروید شما همچنان بتواند به سایر تعاملات کاربر پاسخ دهد. خوب است که همه کارهایی که شامل BluetoothServerSocket یا BluetoothSocket هستند در رشته‌ای که توسط برنامه شمااجرا می‌شود، انجام گیرد. برای توقف دستور accept()، از close()  در BluetoothServerSocket یا BluetoothSocket از یک موضوع دیگر استفاده کنید. توجه داشته‌باشید که تمام روش های موجود در BluetoothServerSocket یا BluetoothSocket امن باشند.

در این بخش از آموزش کار با بلوتوث در برنامه نویسی اندروید مثالی را برایتان آورده‌ایم که در آن یک رشته ساده برای سرور وجود دارد که اتصالات ورودی را می‌پذیرد:

در کاتلین :

private inner class AcceptThread : Thread() {

private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) {
bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID)
}

override fun run() {
// Keep listening until exception occurs or a socket is returned.
var shouldLoop = true
while (shouldLoop) {
val socket: BluetoothSocket? = try {
mmServerSocket?.accept()
} catch (e: IOException) {
Log.e(TAG, "Socket's accept() method failed", e)
shouldLoop = false
null
}
socket?.also {
manageMyConnectedSocket(it)
mmServerSocket?.close()
shouldLoop = false
}
}
}

// Closes the connect socket and causes the thread to finish.
fun cancel() {
try {
mmServerSocket?.close()
} catch (e: IOException) {
Log.e(TAG, "Could not close the connect socket", e)
}
}
}

در جاوا :

private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket
// because mmServerSocket is final.
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code.
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
}public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned.
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
break;
}
if (socket != null) {
// A connection was accepted. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}

// Closes the connect socket and causes the thread to finish.
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}

 

اتصال به عنوان مشتری

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

روال اساسی به شرح زیر است:

1- با استفاده از BluetoothDevice، با فراخوانی createRfcommSocketToServiceRecord (UUID) یک BluetoothSocket دریافت کنید.

این روش، یک BluetoothSocket را فراهم می‌کند که به مشتری اجازه می‌دهد تا به یک BluetoothDevice متصل شود. UUID منتقل شده در اینجا باید با UUID استفاده شده توسط دستگاه سرور، هنگامی که listenUsingRfcommWithServiceRecord (رشته، UUID) را جستجو می‌کند تا BluetoothServerSocket خود را پیدا کند، مطابقت داشته‌باشد. برای استفاده از UUID منطبق، رشته UUID را در برنامه خود رمزگذاری کنید و سپس آن را از سرور و سرویس گیرنده ارجاع دهید.

2- با فراخوانی connect() اتصال را آغاز کنید. توجه داشته‌باشید که این یک روش مسدود کننده است.

پس از برقرای ارتباط مشتری با این روش، سیستم برای یافتن دستگاه از راه دور با UUID منطبق، جستجوی SDP را انجام می‌دهد. اگر جستجو موفقیت آمیز باشد و دستگاه از راه دور اتصال را بپذیرد، کانال RFCOMM را برای استفاده در حین اتصال به اشتراک می.گذارد و accept() برمی‌گردد. اگر اتصال قطع شود، یا اگر اتصال accept()  پایان یابد (بعد از حدود 12 ثانیه)، این روش یک IOException را ایجاد می‌کند. از آن‌جا که accept() یک دستور مسدود کننده است، شما همیشه باید این روش اتصال را در رشته‌ای جدا از رشته فعالیت اصلی (UI) انجام دهید.

* توجه: برای اطمینان از اینکه دستگاه قبل از ارتباط با connect()، کشف دستگاه را انجام نمی‌دهد، همیشه باید از cancelDiscovery() استفاده کنید. اگر کشف در حال انجام است، تلاش اتصال به طور قابل توجهی کند شده و احتمال شکست آن بیشتر می‌گردد.

در اینجا مثالی از  اتصال مشتری را آورده‌ایم که اتصال Bluetooth را آغاز می کند:

در کاتلین :

private inner class ConnectThread(device: BluetoothDevice) : Thread() {

private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
device.createRfcommSocketToServiceRecord(MY_UUID)
}

public override fun run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter?.cancelDiscovery()

mmSocket?.use { socket ->
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
socket.connect()

// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(socket)
}
}

// Closes the client socket and causes the thread to finish.
fun cancel() {
try {
mmSocket?.close()
} catch (e: IOException) {
Log.e(TAG, "Could not close the client socket", e)
}
}
}

در جاوا :

private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}

// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);
}

// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
}

 

در این قسمت از آموزش کار با بلوتوث در برنامه نویسی اندروید، توجه داشته‌باشید که در کد بالا، cancelDiscovery() قبل از وقوع تلاش برای اتصال اجرا می‌شود. همیشه قبل از connect()  باید از cancelDiscovery() استفاده کنید، خصوصاً به این دلیل که cancelDiscovery() صرف نظر از اینکه هم اکنون کشف دستگاه در حال انجام است، موفقیت آمیز عمل می‌کند. اگر برنامه شما نیاز دارد تعیین کند که آیا کشف دستگاه در حال انجام است یا خیر، می‌توانید با استفاده از isDiscovering() این مساله را بررسی کنید.

administMyConnectedSocket()مدیریت خاص برای برنامه است که برای شروع رشته انتقال اطلاعات، طراحی شده‌است.

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

آموزش کار با بلوتوث در اندروید : مدیریت یک اتصال

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

با استفاده از BluetoothSocket، روش کلی انتقال داده‌ها به شرح زیر است:

  • InputStream و OutputStream را که به ترتیب با استفاده از getInputStream() و getOutputStream() انتقال از طریق سوکت را کنترل می‌کنند، دریافت کنید.
  • خواندن و نوشتن داده‌ها را با استفاده از read(byte[]) و  write(byte[]) اجرا کنید.

البته باید جزئیات پیاده سازی نیز در نظر گرفته‌شود. به طور خاص، شما باید از یک موضوع اختصاصی برای خواندن از جریان و نوشتن در آن استفاده کنید. این مساله مهم است زیرا هر دو روش read(byte[]) و write(byte[]) تماس‌ها را مسدود می‌کنند. روش read(byte[]) تا جایی که چیزی برای خواندن از جریان وجود داشته باشد، مسدودیت ایجاد می‌کند. روش write(byte[]) معمولاً مسدود نمی‌شود، اما اگر دستگاه از راه دور به سرعت از read(byte[]) استفاده نکند، ​​می‌تواند برای کنترل جریان مسدود شود. بنابراین، حلقه اصلی شما در موضوع باید به خواندن از InputStream اختصاص یابد. برای شروع نوشتن در OutputStream می‌توان از یک روش عمومی جداگانه استفاده کرد.

در اینجا مثالی از نحوه انتقال داده ها بین دو دستگاه متصل شده از طریق Bluetooth آورده شده است:

در کاتلین :

private const val TAG = "MY_APP_DEBUG_TAG"

// Defines several constants used when transmitting messages between the
// service and the UI.
const val MESSAGE_READ: Int = 0
const val MESSAGE_WRITE: Int = 1
const val MESSAGE_TOAST: Int = 2
// ... (Add other message types here as needed.)

class MyBluetoothService(
// handler that gets info from Bluetooth service
private val handler: Handler) {

private inner class ConnectedThread(private val mmSocket: BluetoothSocket) : Thread() {

private val mmInStream: InputStream = mmSocket.inputStream
private val mmOutStream: OutputStream = mmSocket.outputStream
private val mmBuffer: ByteArray = ByteArray(1024) // mmBuffer store for the stream

override fun run() {
var numBytes: Int // bytes returned from read()

// Keep listening to the InputStream until an exception occurs.
while (true) {
// Read from the InputStream.
numBytes = try {
mmInStream.read(mmBuffer)
} catch (e: IOException) {
Log.d(TAG, "Input stream was disconnected", e)
break
}

// Send the obtained bytes to the UI activity.
val readMsg = handler.obtainMessage(
MESSAGE_READ, numBytes, -1,
mmBuffer)
readMsg.sendToTarget()
}
}

// Call this from the main activity to send data to the remote device.
fun write(bytes: ByteArray) {
try {
mmOutStream.write(bytes)
} catch (e: IOException) {
Log.e(TAG, "Error occurred when sending data", e)

// Send a failure message back to the activity.
val writeErrorMsg = handler.obtainMessage(MESSAGE_TOAST)
val bundle = Bundle().apply {
putString("toast", "Couldn't send data to the other device")
}
writeErrorMsg.data = bundle
handler.sendMessage(writeErrorMsg)
return
}

// Share the sent message with the UI activity.
val writtenMsg = handler.obtainMessage(
MESSAGE_WRITE, -1, -1, mmBuffer)
writtenMsg.sendToTarget()
}

// Call this method from the main activity to shut down the connection.
fun cancel() {
try {
mmSocket.close()
} catch (e: IOException) {
Log.e(TAG, "Could not close the connect socket", e)
}
}
}
}

در جاوا :

public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler handler; // handler that gets info from Bluetooth service// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;// ... (Add other message types here as needed.)
}private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte[] mmBuffer; // mmBuffer store for the stream
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;

// Get the input and output streams; using temp objects because
// member streams are final.
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating input stream", e);
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating output stream", e);
}

mmInStream = tmpIn;
mmOutStream = tmpOut;
}

public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()

// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
mmBuffer);
readMsg.sendToTarget();
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}

// Call this from the main activity to send data to the remote device.
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);

// Share the sent message with the UI activity.
Message writtenMsg = handler.obtainMessage(
MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
writtenMsg.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Error occurred when sending data", e);

// Send a failure message back to the activity.
Message writeErrorMsg =
handler.obtainMessage(MessageConstants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString("toast",
"Couldn't send data to the other device");
writeErrorMsg.setData(bundle);
handler.sendMessage(writeErrorMsg);
}
}

// Call this method from the main activity to shut down the connection.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
}

پس از اینکه سازنده، جریان‌های لازم را بدست آورد، رشته منتظر می‌ماند تا داده‌‌ها از طریق InputStream وارد شوند. وقتی read (byte []) همراه با داده‌های جریان بازگردد، داده‌ها با استفاده از یک Handler عضو از parent calss به فعالیت اصلی ارسال می‌شوند. سپس  منتظر خوانده‌شدن بایت‌های بیشتر از InputStream خواهد ماند.

ارسال داده‌های خروجی با فراخوانی روش write() از فعالیت اصلی و عبور بایت‌ها برای ارسال انجام می‌شود. این روش برای ارسال داده‌ها به دستگاه از راه دور، write(byte[]) را فراخوانی می‌کند. اگر هنگام فراخوانی write(byte[]) یک IOException استفاده شود، جریان به فعالیت اصلی پیامی ارسال می‌کند و به کاربر توضیح می‌دهد که دستگاه نمی‌تواند بایت‌های داده شده را به دستگاه متصل دیگر ارسال کند.

جریان روش  thread() اجازه می‌دهد تا اتصال با بستن BluetoothSocket در هر زمان قطع شود. این روش همیشه باید پس از اتمام استفاده از اتصال بلوتوث فراخوانی شود.

جمع بندی: کلاس ها و رابط های کلیدی

به عنوان سخن آخر در  آموزش کار با بلوتوث در برنامه نویسی اندروید، در اینجا خلاصه‌ای از کلاس‌ها و رابط‌های مورد نیاز برای ایجاد اتصالات android blietoith آورده شده‌است:

  • BluetoothAdapter

نشانگر آداپتور بلوتوث محلی (رادیو بلوتوث) است. BluetoothAdapter نقطه ورود کلیه تعاملات بلوتوث است. با استفاده از آن، می‌توانید سایر دستگاه‌های بلوتوث را کشف کنید، لیستی از دستگاه‌های جفت شده را جستجو کنید، یک BluetoothDevice را با استفاده از یک آدرس MAC شناخته شده نمونه کنید و یک BluetoothServerSocket برای یافتن  ارتباطات با سایر دستگاه‌ها، ایجاد کنید.

  • BluetoothDevice

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

  • BluetoothSocket

رابط سوکت بلوتوث را نشان می‌دهد (شبیه سوکت TCP). این نقطه اتصال است که به یک برنامه اجازه می‌دهد تا با استفاده از InputStream و OutputStream داده‌ها را با یک دستگاه bluetooth دیگر تبادل کند.

  • BluetoothClass

مشخصات و قابلیت‌های کلی دستگاه بلوتوث را توصیف می‌کند. این یک مجموعه فقط برای خوانون است که کلاس‌ها و خدمات دستگاه را تعریف می‌کند. اگرچه این اطلاعات در مورد نوع دستگاه، نکات مفیدی را ارائه می‌دهد، اما ویژگی‌های این کلاس لزوماً تمام پروفایل‌ها و خدمات بلوتوثی را که دستگاه اندروید پشتیبانی می‌کند را نمی‌تواند توصیف کند.

  • BluetoothProfile

رابطی که نمایه مشخصات بلوتوث است. نمایه بلوتوث، مشخصات رابط بی سیم برای ارتباط مبتنی بر bluetooth بین دستگاه‌ها است. یک مثال، نمایه Hands Free است.

  • BluetoothHeadset

پشتیبانی از هدست‌های بلوتوث برای استفاده در تلفن همراه را فراهم می سازد. شامل پروفایل هدست بلوتوث و نمایه Hands Free (v1.5) است.

  • BluetoothA2dp

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

  • BluetoothHealth

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

  • BluetoothHealthCallback

یک کلاس انتزاعی که برای پیاده سازی پاسخ‌های BluetoothHealth استفاده می‌شود. برای دریافت به روزرسانی درباره تغییرات در وضعیت ثبت برنامه اندروید و وضعیت کانال بلوتوث، باید این کلاس را گسترش دهید و روش‌های پاسخگویی را پیاده سازی کنید.

  • BluetoothHealthAppConfiguration

پیکربندی برنامه‌ای را نشان می‌دهد که برنامه شخص ثالث Bluetooth Health برای برقراری ارتباط با یک دستگاه سلامت بلوتوث از راه دور ثبت می‌کند.

  • ServiceListener

رابطی که ارتباط گیرنده‌های ارتباط پردازش BluetoothProfile (IPC) را با اطلاع از اتصال به سرویس داخلی که نمایه خاصی را اجرا می‌کند یا از آن جدا شده است، اطلاع می‌دهد.