BluetoothAdapter — کلاس سیستمی اندروید است که آداپتور بلوتوث محلی دستگاه را نشان میدهد. BluetoothAdapter نقطه ورود برای تمام عملیات بلوتوث در اندروید است: فعالسازی رادیو (enable)، اسکن دستگاهها، مدیریت قابلیت مشاهده (setScanMode)، دریافت اطلاعات درباره آداپتور (getName, getAddress, getState). این کلاس از طریق BluetoothManager.getAdapter() (API 18+) یا BluetoothAdapter.getDefaultAdapter() در دسترس است. در دستگاههای بدون ماژول بلوتوث، getDefaultAdapter() مقدار null برمیگرداند. طبق Android Developers, 2026، BluetoothAdapter یک کامپوننت اجباری برای هر برنامه BLE در اندروید از API 5 به بعد است.
نکات اصلی
BluetoothAdapter آداپتور بلوتوث فیزیکی دستگاه اندرویدی را نشان میدهد. هر دستگاه دقیقاً یک آداپتور دارد (استثنا — Android Automotive با چندین تراشه بلوتوث، که در آن از BluetoothManager.getAdapterList() استفاده میشود). BluetoothAdapter وضعیت رادیو را کپسوله میکند: STATE_OFF (0)، STATE_TURNING_ON (1)، STATE_ON (2)، STATE_TURNING_OFF (3). وضعیت از طریق BroadcastReceiver روی ACTION_STATE_CHANGED ردیابی میشود.
دریافت نمونه BluetoothAdapter اولین قدم هر برنامه BLE در اندروید است. روش توصیهشده — از طریق BluetoothManager.getAdapter() از API 18+. جایگزین — متد استاتیک BluetoothAdapter.getDefaultAdapter() که از API 5 کار میکند اما انعطافپذیری کمتری دارد. هر دو روش در صورت نداشتن ماژول بلوتوث در دستگاه (تبلتهای Wi-Fi-only، شبیهساز) null برمیگردانند. بررسی null اجباری است: برنامه باید به درستی کار خود را پایان دهد یا عملکردهای BLE را غیرفعال کند.
// گرفتن BluetoothAdapter (توصیه شده)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// روش 1: از طریق BluetoothManager (API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// روش 2: از طریق متد استاتیک (API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// بررسی null
if (bluetoothAdapter == null) {
// دستگاه از بلوتوث پشتیبانی نمیکند
}
}
// وضعیت بلوتوث را بررسی کنید
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// اطلاعات آداپتور را دریافت کنید
fun getAdapterInfo(): Map<String, String> {
return mapOf(
"name" to (bluetoothAdapter?.name ?: "N/A"),
"address" to (bluetoothAdapter?.address ?: "N/A"),
"state" to (bluetoothAdapter?.state?.toString() ?: "N/A"),
"scanMode" to (bluetoothAdapter?.scanMode?.toString() ?: "N/A")
)
}
}
کلاس BluetoothHelper دریافت BluetoothAdapter از طریق BluetoothManager را با بررسی بعدی null نشان میدهد. isBluetoothEnabled isEnabled را بررسی میکند — شرط اجباری قبل از هر عملیات BLE. getAdapterInfo نام دستگاه، آدرس MAC، وضعیت و حالت مشاهده را برمیگرداند. مهم: در اندروید 10+ (API 29+) سرویس سیستم یک آدرس MAC جعلی (02:00:00:00:00:00) برمیگرداند اگر برنامه مجوز BLUETOOTH_ADMIN و ACCESS_FINE_LOCATION را نداشته باشد.
BluetoothAdapter روشهای مدیریت رادیوی بلوتوث را فراهم میکند. enable() و disable() بلوتوث را فعال و غیرفعال میکنند. هر دو روش نیازمند مجوز BLUETOOTH_ADMIN هستند و به صورت ناهمگام اجرا میشوند: پس از فراخوانی enable() سیستم فرآیند فعالسازی رادیو را شروع میکند، وضعیت از طریق BroadcastReceiver با اکشن BluetoothAdapter.ACTION_STATE_CHANGED ردیابی میشود. از اندروید 10+ enable() و disable() نیازمند مجوز اضافی سیستم هستند — برنامههای معمولی نمیتوانند بدون دیالوگ کاربر بلوتوث را برنامهریزی مدیریت کنند.
getState() وضعیت فعلی آداپتور را برمیگرداند: STATE_OFF (10)، STATE_TURNING_ON (11)، STATE_ON (12)، STATE_TURNING_OFF (13). getAddress() آدرس MAC آداپتور بلوتوث را برمیگرداند. در اندروید 6+ برای درخواست آدرس MAC نیاز به ACCESS_FINE_LOCATION (یا ACCESS_COARSE_LOCATION برای API 31+) است. در اندروید 10+ getAddress() آدرس ثابت 02:00:00:00:00:00 را برمیگرداند — آدرس واقعی از طریق API عمومی در دسترس نیست.
getScanMode() حالت مشاهده آداپتور را تعیین میکند: SCAN_MODE_NONE (غیرقابل مشاهده)، SCAN_MODE_CONNECTABLE (قابل مشاهده برای متصلشوندگان)، SCAN_MODE_CONNECTABLE_DISCOVERABLE (قابل مشاهده برای همه). حالت مشاهده برای امنیت محدود به زمان است (معمولاً 60–300 ثانیه). تنظیم حالت از طریق setScanMode() نیازمند BLUETOOTH_ADMIN و مجوز سیستم در اندروید 10+ است.
| متد | توضیح | مجوز مورد نیاز |
|---|---|---|
| enable() | فعالسازی رادیوی بلوتوث | BLUETOOTH_ADMIN |
| disable() | غیرفعالسازی رادیوی بلوتوث | BLUETOOTH_ADMIN |
| getState() | وضعیت فعلی آداپتور | BLUETOOTH |
| getAddress() | آدرس MAC آداپتور | BLUETOOTH + ACCESS_FINE_LOCATION (API 23+) |
| getScanMode() | حالت مشاهده دستگاه | BLUETOOTH |
| setScanMode() | تنظیم حالت مشاهده | BLUETOOTH_ADMIN |
BluetoothAdapter از دو نوع اسکن پشتیبانی میکند. اسکن کلاسیک بلوتوث (BR/EDR) از طریق startDiscovery() راهاندازی میشود — دستگاههای بلوتوث از همه انواع از جمله تلفنها و هدفونها را شناسایی میکند. نتایج از طریق BroadcastReceiver با اکشن BluetoothDevice.ACTION_FOUND برگردانده میشوند. startDiscovery() به مدت 12 ثانیه کار میکند و میتواند با فراخوانی cancelDiscovery() لغو شود. این روش برای BLE منسوخ شده است — از BluetoothLeScanner استفاده کنید.
اسکن BLE از طریق BluetoothAdapter با روش منسوخ شده startLeScan(LeScanCallback) انجام میشود. از API 21، Google استفاده از BluetoothLeScanner را توصیه میکند که از طریق BluetoothAdapter.getBluetoothLeScanner() دریافت میشود. BluetoothLeScanner API انعطافپذیرتری ارائه میدهد: پیکربندی اسکن از طریق ScanSettings (حالت، callback type، match mode)، فیلتر کردن از طریق ScanFilter (با UUID سرویس، نام دستگاه، آدرس MAC) و پشتیبانی از PendingIntent برای اسکن پسزمینه.
// API اسکن BLE قدیمی (منسوخ) در مقابل جدید
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// منسوخ شده: startLeScan (API 18+, API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// جدید: BluetoothLeScanner (API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// تنظیمات اسکن
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// فیلتر بر اساس سرویس (UUID ضربان قلب)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// شروع اسکن
scanner.startScan(filters, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
val rssi = result.rssi
print("Found (BLE Scanner): ${device.name}, RSSI: $rssi, address: ${device.address}")
}
override fun onScanFailed(errorCode: Int) {
print("Scan error: $errorCode")
}
})
}
}
کلاس BLEScanner startLeScan منسوخ شده و BluetoothLeScanner مدرن را مقایسه میکند. در legacyScan، callback LeScanCallback BluetoothDevice، RSSI و scanRecord خام را دریافت میکند. در modernScan از ScanSettings با حالت LOW_LATENCY (حداکثر سرعت شناسایی) و ScanFilter برای فیلتر کردن با UUID سرویس ضربان قلب (Heart Rate Service 0x180D) استفاده میشود. ScanCallback onScanResult را با شیء ScanResult حاوی اطلاعات پیشرفته ارائه میدهد: نام، RSSI، دادههای تبلیغاتی، نوع اتصال.
BluetoothManager — سرویس سیستمی اندروید است که در API 18 (اندروید 4.3) برای مدیریت عملیات بلوتوث معرفی شد. قبل از API 18 تنها راه دریافت BluetoothAdapter متد استاتیک getDefaultAdapter() بود. BluetoothManager ارائه میدهد: adapter — نمونه BluetoothAdapter، getConnectedDevices() — لیست دستگاههای متصل، getDevicesMatchingConnectionStates() — فیلتر کردن بر اساس وضعیت. BluetoothManager همچنین برای دریافت BluetoothLeScanner در APIهای قدیمی استفاده میشود.
مزایای BluetoothManager نسبت به فراخوانی مستقیم BluetoothAdapter.getDefaultAdapter(): برنامه به singletons استاتیک وابسته نیست، مدیر زمینه (Activity/Application) را در نظر میگیرد که برای سناریوهای چند حسابی Android Enterprise مهم است. در Android Automotive با چندین تراشه بلوتوث، BluetoothManager.getAdapterList() همه آداپتورهای موجود را برمیگرداند — BluetoothAdapter.getDefaultAdapter() فقط اولین را برمیگرداند.
// استفاده از BluetoothManager برای BLE
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// گرفتن لیست دستگاههای BLE متصل
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// فیلتر کردن دستگاهها بر اساس وضعیت
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// بررسی پشتیبانی BLE در دستگاه
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// درخواست فعالسازی بلوتوث از طریق دیالوگ سیستم
fun requestEnableBluetooth(activity: MainActivity) {
if (adapter?.isEnabled == false) {
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
activity.startActivityForResult(intent, REQUEST_ENABLE_BT)
}
}
companion object {
const val REQUEST_ENABLE_BT = 1001
}
}
کلاس BLEConnection از BluetoothManager برای دسترسی به BluetoothAdapter و دریافت لیست دستگاههای GATT متصل استفاده میکند. isBLESupported وجود رادیوی BLE را از طریق PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) بررسی میکند — بررسی مهم برای دستگاههای دارای Bluetooth Classic بدون BLE. requestEnableBluetooth دیالوگ سیستمی فعالسازی بلوتوث را نشان میدهد (ACTION_REQUEST_ENABLE) بدون نیاز به مجوز BLUETOOTH_ADMIN — این تنها راه قانونی فعالسازی بلوتوث در اندروید 10+ بدون برنامه سیستمی است.
مجوزها برای BluetoothAdapter با هر نسخه اندروید تکامل یافتهاند. در اندروید 6–11 (API 23–30) برای اسکن BLE، BLUETOOTH، BLUETOOTH_ADMIN و ACCESS_FINE_LOCATION اجباری هستند. در اندروید 12+ (API 31+) Google مجوزها را تقسیم کرده است: ACCESS_FINE_LOCATION با BLUETOOTH_SCAN (اسکن)، BLUETOOTH_CONNECT (اتصال)، BLUETOOTH_ADVERTISE (تبلیغات) جایگزین شده است. برای جستجوی دستگاههای BLE، BLUETOOTH_SCAN کافی است و مکان مورد نیاز نیست.
جدول مجوزها بر اساس نسخههای اندروید:
| عملیات | API 23–30 | API 31+ |
|---|---|---|
| اسکن BLE | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN (بدون مکان) |
| اتصال به BLE | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| تبلیغات BLE | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| فعال/غیرفعالسازی | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN (سیستمی) |
| دریافت آدرس MAC | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT (آدرس جعلی) |
در اندروید 12+ همه مجوزهای بلوتوث مجوزهای زمان اجرا هستند — باید در زمان اجرا از طریق ActivityResultContracts.RequestMultiplePermissions درخواست شوند. BLUETOOTH_SCAN و BLUETOOTH_ADVERTISE به گروه NEARBY_DEVICES تعلق دارند، BLUETOOTH_CONNECT — به همان گروه. مجوزهای BLUETOOTH و BLUETOOTH_ADMIN برای سازگاری با API < 31 در مانیفست باقی میمانند، اما برای API 31+ نادیده گرفته میشوند — Google نیاز به مشخص کردن صریح مجوزهای جدید دارد.
// درخواست مجوزهای بلوتوث در اندروید 12+
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
class PermissionHelper(context: Context) {
fun getRequiredPermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// اندروید 12+: اسکن BLE
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// اندروید 6-11: اسکن BLE
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// بررسی همه مجوزها
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
کلاس PermissionHelper مجموعه مجوز صحیح را بر اساس سطح API برمیگرداند. در اندروید 12+ از BLUETOOTH_SCAN، BLUETOOTH_CONNECT، BLUETOOTH_ADVERTISE بدون مکان استفاده میشود. در اندروید 6–11 برای اسکن BLE همچنان ACCESS_FINE_LOCATION مورد نیاز است. توسعهدهنده باید هر دو سناریو را هنگام درخواست مجوز از طریق ActivityResultContracts یا RxPermissions در نظر بگیرد.
مثال کامل برنامه BLE در کاتلین با استفاده از BluetoothAdapter برای اسکن، اتصال و خواندن دادههای دستگاه BLE. مثال شامل بررسی مجوزها، دریافت آداپتور، اسکن از طریق BluetoothLeScanner و اتصال از طریق BluetoothDevice.connectGatt است.
// مدیر کامل BLE در کاتلین
class BLEManager(private val context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
private var scanner: BluetoothLeScanner? = adapter?.bluetoothLeScanner
private var gatt: BluetoothGatt? = null
// 1. کشف سرویسها
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. اسکن با فیلتر
fun startScanning(callback: (BluetoothDevice, Int) -> Unit) {
if (!canScan()) return
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build()
scanner?.startScan(null, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
callback(result.device, result.rssi)
}
})
}
// 3. توقف اسکن
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. اتصال به دستگاه BLE
fun connectToDevice(device: BluetoothDevice) {
if (adapter?.isEnabled != true) return
gatt = device.connectGatt(
context,
false,
object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
// سرویسها پیدا شدند، میتوان ویژگیها را خواند
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. آزادسازی منابع
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
مدیر BLEManager چرخه کامل BLE را در اندروید ترکیب میکند: بررسی آداپتور و مجوزها (canScan)، اسکن از طریق BluetoothLeScanner با ScanSettings (startScanning)، اتصال از طریق BluetoothDevice.connectGatt با TRANSPORT_LE (connectToDevice)، آزادسازی منابع (disconnect). تمام عملیات BLE در رشته UI انجام میشوند — اندروید callbackهای BluetoothGattCallback را در رشته اصلی فراخوانی میکند. برای کارهای BLE پربازده، توصیه میشود عملیات GATT را به HandlerThread پسزمینه منتقل کنید.
سوالات متداول
BluetoothAdapter — کلاسی است که آداپتور بلوتوث محلی دستگاه اندرویدی را نشان میدهد. از طریق BluetoothManager.getAdapter() (API 18+) یا BluetoothAdapter.getDefaultAdapter() دریافت میشود. روشهای فعال/غیرفعالسازی بلوتوث، اسکن دستگاهها، مدیریت مشاهده و دریافت اطلاعات درباره آداپتور را فراهم میکند. در دستگاههای بدون ماژول بلوتوث null برمیگرداند.
دلیل — نبود رادیوی بلوتوث در دستگاه. مشخصه تبلتهای Wi-Fi-only، شبیهساز اندروید و Android TV بدون بلوتوث. getDefaultAdapter() را در هنگام راهاندازی برنامه برای null بررسی کنید و در صورت نبود آداپتور، عملکردهای BLE را غیرفعال کنید. جایگزین — بررسی از طریق PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) برای تعیین دقیقتر.
BluetoothLeScanner (API 21+) — API مدرن برای اسکن BLE با پشتیبانی از ScanFilter، ScanSettings و PendingIntent. startLeScan (API 18+) — متد منسوخ شده BluetoothAdapter که LeScanCallback را با مجموعه داده محدود میپذیرد. BluetoothLeScanner توسط Google برای همه پروژههای جدید توصیه میشود، امکان فیلتر کردن با UUID، پیکربندی حالت مصرف انرژی و کار در پسزمینه از طریق PendingIntent را فراهم میکند.
در اندروید 12+ (API 31) برای اسکن BLE نیاز به BLUETOOTH_SCAN، برای اتصال — BLUETOOTH_CONNECT، برای تبلیغات — BLUETOOTH_ADVERTISE است. مجوز مکان ACCESS_FINE_LOCATION دیگر برای BLE مورد نیاز نیست. در اندروید 6–11 ACCESS_FINE_LOCATION لازم است. همه مجوزها در زمان اجرا از طریق ActivityResultContracts درخواست میشوند.
از اندروید 10+ فعالسازی برنامهریزی بلوتوث بدون دیالوگ سیستم فقط برای برنامههای سیستمی با مجوز BLUETOOTH_PRIVILEGED امکانپذیر است. برنامههای معمولی باید از Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) و startActivityForResult استفاده کنند — کاربر فعالسازی را در دیالوگ سیستم تأیید میکند. BLUETOOTH_ADMIN در مانیفست حق enable() را در اندروید 10+ نمیدهد.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید