BluetoothLeScanner হল Android-এর একটি ক্লাস যা Bluetooth Low Energy ডিভাইস স্ক্যান করার জন্য, API 21 (Android 5.0) থেকে উপলব্ধ। BluetoothLeScanner BluetoothAdapter-এ পুরনো startLeScan পদ্ধতি প্রতিস্থাপন করেছে, যা স্ক্যান কনফিগারেশন (ScanSettings), ফিল্টারিং (ScanFilter) এবং ব্যাকগ্রাউন্ড মোড সমর্থন (PendingIntent) সহ একটি নমনীয় API প্রদান করে। ইনস্ট্যান্স BluetoothAdapter.getBluetoothLeScanner() এর মাধ্যমে পাওয়া যায়। Android Developers, 2026 অনুসারে, BluetoothLeScanner তিনটি পাওয়ার মোড সমর্থন করে এবং সার্ভিস UUID, ডিভাইস নাম বা MAC ঠিকানা দ্বারা ফিল্টারিং সহ BLE বিজ্ঞাপন প্যাকেট স্ক্যান করার অনুমতি দেয়।
মূল বিষয়
BluetoothLeScanner Android-এ BLE স্ক্যানিং পরিচালনার জন্য একটি সিস্টেম ক্লাস। BluetoothAdapter.startLeScan()-এর বিপরীতে, যা একটি সরল LeScanCallback গ্রহণ করে, BluetoothLeScanner সেটিংস, ফিল্টার এবং উন্নত ত্রুটি পরিচালনা সহ একটি অবজেক্ট-ওরিয়েন্টেড API প্রদান করে। এই ক্লাসটি API 21 (Android 5.0)-এ BLE 4.2 সমর্থনের সাথে প্রবর্তিত হয়েছিল এবং সমস্ত আধুনিক Android সংস্করণে BLE স্ক্যানিংয়ের প্রাথমিক পদ্ধতি হিসাবে রয়ে গেছে।
BluetoothLeScanner-এর একটি ইনস্ট্যান্স BluetoothAdapter.getBluetoothLeScanner()-এর মাধ্যমে পাওয়া যায়। যদি Bluetooth অ্যাডাপ্টার অনুপলব্ধ হয় (Bluetooth নিষ্ক্রিয় বা ডিভাইস BLE সমর্থন করে না) তাহলে পদ্ধতিটি null ফেরত দেয়। এটি পাওয়ার আগে, PackageManager-এর মাধ্যমে BluetoothAdapter.isEnabled() এবং FEATURE_BLUETOOTH_LE-এর উপস্থিতি পরীক্ষা করুন। স্ক্যানার পাওয়ার পরে, যেকোনো থ্রেডে স্ক্যানিং শুরু করা যেতে পারে — Android একটি অভ্যন্তরীণ Bluetooth স্ট্যাক থ্রেডে BLE অপারেশন নির্ধারণ করে।
// BluetoothLeScanner পাওয়া
class BLEScannerManager(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
private var scanner: BluetoothLeScanner? = null
fun initScanner(): Boolean {
// BLE প্রাপ্যতা পরীক্ষা করুন
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
return false
}
// Bluetooth সক্রিয় আছে কিনা পরীক্ষা করুন
if (adapter?.isEnabled != true) {
return false
}
// স্ক্যানার পান
scanner = adapter?.bluetoothLeScanner
return scanner != null
}
// স্ক্যানার প্রাপ্যতা পরীক্ষা করুন
val isAvailable: Boolean
get() = scanner != null
// ফিল্টার ছাড়া মৌলিক স্ক্যান শুরু করুন
fun startBasicScan() {
scanner?.startScan(object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
handleResult(result)
}
})
}
private fun handleResult(result: ScanResult) {
val device = result.device
print("Device: ${device.name ?: "Unnamed"}, RSSI: ${result.rssi}, address: ${device.address}")
}
}
BLEScannerManager ক্লাসটি BluetoothLeScanner-এর নিরাপদ প্রাপ্তি এবং আরম্ভকরণ প্রদর্শন করে। initScanner hasSystemFeature-এর মাধ্যমে BLE প্রাপ্যতা, সক্রিয় Bluetooth এবং সফল স্ক্যানার প্রাপ্তি পরীক্ষা করে। startBasicScan সেটিংস এবং ফিল্টার ছাড়াই স্ক্যানিং শুরু করে — পরিসরের মধ্যে সমস্ত BLE ডিভাইস আবিষ্কার করে। handleResult ScanResult পার্স করে: BluetoothDevice (নাম, ঠিকানা), RSSI (সংকেত শক্তি), scanRecord (বিজ্ঞাপন ডেটা)।
ScanSettings BLE স্ক্যান কনফিগারেশনের জন্য একটি ক্লাস। প্রধান প্যারামিটার হল স্ক্যান মোড (scanMode), যা পাওয়ার খরচ এবং আবিষ্কার বিলম্বের মধ্যে ট্রেড-অফ নির্ধারণ করে। ScanSettings.Builder আপনাকে কনফিগার করতে দেয়: scanMode, callbackType (CALLBACK_TYPE_ALL_MATCHES, CALLBACK_TYPE_FIRST_MATCH, CALLBACK_TYPE_MATCH_LOST), matchMode (MATCH_MODE_AGGRESSIVE, MATCH_MODE_STICKY), reportDelay (ব্যাচ ডেলিভারি বিলম্ব), এবং phy (PHY_LE_1M, PHY_LE_2M, PHY_LE_CODED)।
তিনটি স্ক্যান মোড: SCAN_MODE_LOW_POWER (0) — কম পাওয়ার খরচ সহ ব্যাকগ্রাউন্ড স্ক্যানিং, কয়েক সেকেন্ডের আবিষ্কার বিলম্ব। SCAN_MODE_BALANCED (1) — বেশিরভাগ পরিস্থিতির জন্য ভারসাম্যপূর্ণ মোড। SCAN_MODE_LOW_LATENCY (2) — ন্যূনতম আবিষ্কার বিলম্ব (প্রায় 100 ms), সর্বোচ্চ পাওয়ার খরচ। সক্রিয় ডিভাইস আবিষ্কারের জন্য LOW_LATENCY ব্যবহার করুন, ব্যাকগ্রাউন্ড মনিটরিংয়ের জন্য LOW_POWER ব্যবহার করুন।
reportDelay — ফলাফলের ব্যাচ ডেলিভারির আগে মিলিসেকেন্ডে বিলম্ব। reportDelay = 0 হলে, ফলাফল আবিষ্কারের সাথে সাথে পাঠানো হয়। > 0 হলে, Android ফলাফল জমা করে এবং onBatchScanResults-এর মাধ্যমে একটি ব্যাচ পাঠায়। ব্যাচ ডেলিভারি কলব্যাক আহ্বান এবং পাওয়ার খরচ হ্রাস করে, নিম্ন-অগ্রাধিকার ব্যাকগ্রাউন্ড স্ক্যানিংয়ের জন্য উপযুক্ত।
// বিভিন্ন পরিস্থিতির জন্য ScanSettings কনফিগারেশন
class ScanSettingsProvider {
// 1. দ্রুত স্ক্যান (সক্রিয় অনুসন্ধান)
fun lowLatencyScan(): ScanSettings {
return ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setReportDelay(0)
.setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED)
.build()
}
// 2. শক্তি সাশ্রয়ী স্ক্যান (ব্যাকগ্রাউন্ড মনিটরিং)
fun lowPowerScan(): ScanSettings {
return ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
.setMatchMode(ScanSettings.MATCH_MODE_STICKY)
.setReportDelay(2000) // প্রতি 2 সেকেন্ডে ব্যাচ
.build()
}
// 3. BLE লং রেঞ্জ স্ক্যান (Coded PHY)
fun longRangeScan(): ScanSettings {
return ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setPhy(ScanSettings.PHY_LE_CODED)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build()
}
// 4. শুধুমাত্র 2M PHY-তে স্ক্যান করুন (BLE 5.0+)
fun highSpeedScan(): ScanSettings {
return ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setPhy(ScanSettings.PHY_LE_2M)
.build()
}
}
ScanSettingsProvider ক্লাসে সাধারণ কনফিগারেশন রয়েছে। lowLatencyScan — UI স্ক্যানিংয়ের জন্য (অনুসন্ধান «এখানে এবং এখন»)। lowPowerScan — প্রতি 2 সেকেন্ডে ব্যাচ এবং callbackType FIRST_MATCH সহ ব্যাকগ্রাউন্ড মনিটরিংয়ের জন্য (শুধুমাত্র প্রথম আবিষ্কারে সক্রিয় হয়)। longRangeScan PHY_LE_CODED (BLE লং রেঞ্জ, 1 কিমি পর্যন্ত) ব্যবহার করে। highSpeedScan — PHY_LE_2M (2 Mbit/s, শুধুমাত্র BLE 5.0+ ডিভাইস)।
ScanFilter BLE স্ক্যান ফলাফল ফিল্টার করার জন্য একটি ক্লাস। ফিল্টার ছাড়া, BluetoothLeScanner পরিসরের মধ্যে সমস্ত BLE ডিভাইস ফেরত দেয় — ঘন BLE পরিবেশে এটি প্রতি মিনিটে শত শত প্যাকেট হতে পারে। ScanFilter ফলাফলগুলি পছন্দসই ডিভাইসে সীমাবদ্ধ করে, পাওয়ার খরচ এবং অ্যাপ লোড হ্রাস করে। ফিল্টারগুলি Bluetooth স্ট্যাক স্তরে প্রয়োগ করা হয় — অপ্রাসঙ্গিক প্যাকেটগুলি অ্যাপে পৌঁছানোর আগে বাতিল করা হয়।
ফিল্টারের প্রকার: setServiceUuid — সার্ভিস UUID (সম্পূর্ণ 128-বিট ফর্ম্যাট প্রয়োজন)। setDeviceName — ডিভাইস নামের সাবস্ট্রিং (কেস-সংবেদনশীল, সঠিক সাবস্ট্রিং মিল)। setDeviceAddress — সঠিক MAC ঠিকানা। setManufacturerData — প্রস্তুতকারক ডেটা (কোম্পানি ID + মাস্ক)। একটি স্ক্যানের জন্য একাধিক ফিল্টার সেট করা যেতে পারে — ডিভাইসটিকে সমস্ত ফিল্টারের সাথে মেলাতে হবে (AND যুক্তি)। OR যুক্তির জন্য, একাধিক স্ক্যান শুরু করুন।
// বিভিন্ন পরিস্থিতির জন্য ScanFilter তৈরি
class ScanFilterFactory {
// 1. সার্ভিস UUID দ্বারা ফিল্টার (হার্ট রেট মনিটর)
fun byHeartRateService(): ScanFilter {
return ScanFilter.Builder()
.setServiceUuid(
ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB")
)
.build()
}
// 2. ডিভাইস নাম দ্বারা ফিল্টার ( "iBeacon*")
fun byDeviceName(): ScanFilter {
return ScanFilter.Builder()
.setDeviceName("Sensor")
.build()
}
// 3. MAC- ( ডিভাইস)
fun byMacAddress(mac: String): ScanFilter {
return ScanFilter.Builder()
.setDeviceAddress(mac)
.build()
}
// 4. সম্মিলিত ফিল্টার (UUID + )
fun combinedFilter(): List<ScanFilter> {
return listOf(
ScanFilter.Builder()
.setServiceUuid(
ParcelUuid.fromString("0000A001-0000-1000-8000-00805F9B34FB")
)
.setDeviceName("MyDevice")
.build()
)
}
// 5. প্রস্তুতকারক ডেটা
fun byManufacturer(companyId: Int, data: ByteArray, mask: ByteArray): ScanFilter {
return ScanFilter.Builder()
.setManufacturerData(companyId, data, mask)
.build()
}
}
ScanFilterFactory ক্লাস সমস্ত ফিল্টার প্রকার দেখায়। byHeartRateService হার্ট রেট সার্ভিস 0x180D সহ ডিভাইসগুলি ফিল্টার করে। byDeviceName নামে «Sensor» থাকা ডিভাইসগুলি খুঁজে পায় (Apple ফিল্টারিংয়ের জন্য অনন্য নাম সুপারিশ করে)। byMacAddress — একটি নির্দিষ্ট ডিভাইসের সঠিক অনুসন্ধান। combinedFilter — UUID এবং নাম দ্বারা AND ফিল্টার। byManufacturer — প্রস্তুতকারক ডেটা দ্বারা ফিল্টার (উদাহরণস্বরূপ, iBeacon-এর জন্য Apple কোম্পানি ID 0x004C ব্যবহৃত হয়)।
ScanCallback BLE স্ক্যান ফলাফল প্রাপ্তির জন্য একটি বিমূর্ত ক্লাস। এতে তিনটি পদ্ধতি রয়েছে: onScanResult — একক ফলাফল (কলব্যাক প্রকার, ScanResult), onBatchScanResults — reportDelay > 0-এর জন্য ব্যাচ ফলাফল, onScanFailed — ত্রুটি কোড। সমস্ত পদ্ধতি Android মূল থ্রেডে কল করা হয়। onScanResult-এ দীর্ঘ প্রক্রিয়াকরণের জন্য, coroutines বা HandlerThread ব্যবহার করুন।
ScanResult-এ রয়েছে: BluetoothDevice device, int rssi (dBm-এ সংকেত স্তর), ScanRecord scanRecord (বিজ্ঞাপন ডেটা), long timestampNanos (সিস্টেম বুট থেকে আবিষ্কারের সময়)। ScanRecord প্রদান করে: getServiceData() — UUID + কাস্টম ডেটা, getManufacturerSpecificData() — প্রস্তুতকারক ডেটা, getAdvertiseFlags() — BLE ফ্ল্যাগ। কলব্যাক প্রকার নির্দেশ করে: CALLBACK_TYPE_ALL_MATCHES — ফিল্টারের সাথে মিল, CALLBACK_TYPE_FIRST_MATCH — প্রথম আবিষ্কার, CALLBACK_TYPE_MATCH_LOST — ডিভাইস হারিয়ে গেছে।
onScanFailed ত্রুটি কোড: SCAN_FAILED_ALREADY_STARTED (1) — স্ক্যানিং ইতিমধ্যে শুরু হয়েছে, SCAN_FAILED_APPLICATION_REGISTRATION_FAILED (2) — Bluetooth স্টাকে অ্যাপ নিবন্ধন ব্যর্থ হয়েছে, SCAN_FAILED_INTERNAL_ERROR (3) — অভ্যন্তরীণ স্ট্যাক ত্রুটি, SCAN_FAILED_FEATURE_UNSUPPORTED (4) — ডিভাইসে BLE স্ক্যানিং সমর্থিত নয়।
// সম্পূর্ণ স্ক্যান ফলাফল এবং ত্রুটি পরিচালনা
class ScanResultHandler {
private val results = mutableListOf<ScanResult>()
val scanCallback = object : ScanCallback() {
// 1. একক ফলাফল
override fun onScanResult(callbackType: Int, result: ScanResult) {
// callbackType: 1 = ALL_MATCHES, 2 = FIRST_MATCH, 4 = MATCH_LOST
if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
onDeviceLost(result)
return
}
// তালিকায় যোগ করুন (ঠিকানা দ্বারা ডি-ডুপ)
val existingIndex = results.indexOfFirst {
it.device.address == result.device.address
}
if (existingIndex >= 0) {
results[existingIndex] = result // RSSI আপডেট করুন
} else {
results.add(result)
}
// বিজ্ঞাপন প্যাকেট থেকে ডেটা বের করুন
val record = result.scanRecord
val serviceData = record?.serviceData
val manufacturerData = record?.manufacturerSpecificData
print("Found: ${result.device.name ?: "N/A"}, RSSI: ${result.rssi}")
}
// 2. ব্যাচ ফলাফল (reportDelay > 0)
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
results?.let { batch ->
print("Batch: ${batch.size} devices")
}
}
// 3. স্ক্যান ত্রুটি
override fun onScanFailed(errorCode: Int) {
val error = when (errorCode) {
ScanCallback.SCAN_FAILED_ALREADY_STARTED -> "Already scanning"
ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> "Registration failed"
ScanCallback.SCAN_FAILED_INTERNAL_ERROR -> "Internal error"
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED -> "BLE not supported"
else -> "Unknown error: $errorCode"
}
print("Error: $error")
}
}
private fun onDeviceLost(result: ScanResult) {
results.removeAll { it.device.address == result.device.address }
print("Device lost: ${result.device.address}")
}
}
ScanResultHandler ক্লাস সমস্ত BluetoothLeScanner কলব্যাক প্রকার পরিচালনা করে। onScanResult MAC ঠিকানা দ্বারা ডি-ডুপ্লিকেশন সহ ডিভাইস তালিকা আপডেট করে — ইতিমধ্যে পাওয়া ডিভাইসগুলির জন্য RSSI আপডেট করা হয়। CALLBACK_TYPE_MATCH_LOST ডিভাইস হারানোর সংকেত দেয় (তালিকা থেকে অপসারণ)। onBatchScanResults reportDelay > 0-এর জন্য ব্যাচ ফলাফল প্রক্রিয়া করে। onScanFailed ত্রুটি কোডকে মানুষ-পাঠযোগ্য বার্তায় ম্যাপ করে — BLE স্ক্যানিং ডিবাগিংয়ের জন্য গুরুত্বপূর্ণ।
PendingIntent স্ক্যানিং হল BluetoothLeScanner-এর একটি প্রক্রিয়া যা BLE স্ক্যানিংয়ের জন্য যা অ্যাপ ব্যাকগ্রাউন্ডে থাকলেও কাজ করে (Android 8+ সীমাবদ্ধতা সহ)। ScanCallback-এর পরিবর্তে, একটি PendingIntent ব্যবহার করা হয়, যা BLE ডিভাইস আবিষ্কৃত হলে সিস্টেম BroadcastReceiver-এ একটি Broadcast পাঠায়। এটি অ্যাপকে মেমোরিতে না থেকেই BLE ডিভাইস বিজ্ঞপ্তি পেতে দেয় (Broadcast পাওয়ার সময় সিস্টেম প্রক্রিয়া তৈরি করে)।
ব্যাকগ্রাউন্ড স্ক্যানিং সীমাবদ্ধতা: Android 8+ (API 26)-এ, ব্যাকগ্রাউন্ড সার্ভিস সীমাবদ্ধ — PendingIntent স্ক্যানিং BroadcastReceiver-এর মাধ্যমে এই সীমাবদ্ধতা অতিক্রম করে, যা সিস্টেম BLE ঘটনা পাওয়ার সময় শুরু করতে পারে। Android 10+ (API 29)-এ, ব্যাকগ্রাউন্ড BLE স্ক্যানিং প্রস্তুতকারক শক্তি সঞ্চয় নীতির (Xiaomi, Huawei, Samsung ব্যাকগ্রাউন্ড BLE কার্যক্রম ব্লক করে) দ্বারা আরও সীমাবদ্ধ। গুরুত্বপূর্ণ BLE পরিস্থিতির জন্য, একটি ফোরগ্রাউন্ড সার্ভিস বিজ্ঞপ্তি প্রয়োজন।
// PendingIntent-এর মাধ্যমে ব্যাকগ্রাউন্ড BLE স্ক্যানিং
class BackgroundBLEScanner(private val context: Context) {
private val scanner: BluetoothLeScanner? by lazy {
val adapter = BluetoothAdapter.getDefaultAdapter()
adapter?.bluetoothLeScanner
}
fun startBackgroundScan() {
// BroadcastReceiver-এর জন্য PendingIntent তৈরি করুন
val intent = Intent(context, BLEBroadcastReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// ব্যাকগ্রাউন্ড স্ক্যান সেটিংস
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
.setMatchMode(ScanSettings.MATCH_MODE_STICKY)
.build()
// ব্যাকগ্রাউন্ড স্ক্যান শুরু করুন
scanner?.startScan(
null, // ফিল্টার
settings,
pendingIntent
)
}
fun stopBackgroundScan() {
val intent = Intent(context, BLEBroadcastReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
scanner?.stopScan(pendingIntent)
}
}
// BroadcastReceiver BLE-
class BLEBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// স্ক্যান ফলাফল পান
val results = BluetoothLeScanner.getPendingIntentScanResults(intent)
results?.let { scanResults ->
for (result in scanResults) {
// ব্যবহারকারীকে বিজ্ঞপ্তি পাঠান
showNotification(context, result.device.name ?: " ")
}
}
}
private fun showNotification(context: Context, name: String) {
val notification = Notification.Builder(context, "ble_channel")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("BLE devices")
.setContentText("Found: $name")
.setAutoCancel(true)
.build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
manager.notify(System.currentTimeMillis().toInt(), notification)
}
}
BackgroundBLEScanner ক্লাস PendingIntent-এর মাধ্যমে ব্যাকগ্রাউন্ড BLE স্ক্যানিং শুরু করে। startBackgroundScan একটি PendingIntent তৈরি করে যা BLE ডিভাইস আবিষ্কারের পরে BLEBroadcastReceiver-এ Broadcast পাঠায়। BroadcastReceiver getPendingIntentScanResults()-এর মাধ্যমে ScanResult বের করে এবং একটি বিজ্ঞপ্তি দেখাতে বা সার্ভারে ডেটা পাঠাতে পারে। এই পদ্ধতি কাজ করে এমনকি যদি অ্যাপ সিস্টেম দ্বারা সমাপ্ত করা হয় — Android Broadcast পাওয়ার পর BroadcastReceiver পুনরায় চালু করে।
সম্পূর্ণ উদাহরণ Kotlin-এ একটি BLE স্ক্যানারের যা Heart Rate Monitor ডিভাইস খোঁজার জন্য BluetoothLeScanner কে ScanSettings, ScanFilter এবং ScanCallback সহ ব্যবহার করে। স্ক্যানারটি পাওয়া ডিভাইসগুলির একটি তালিকা RSSI এবং সার্ভিস UUID সহ দেখায়, BluetoothGatt-এর মাধ্যমে সংযোগ করার ক্ষমতা সহ।
// Kotlin-এ coroutines সহ সম্পূর্ণ BLE স্ক্যানার
class DeviceScanner(private val context: Context) {
private val adapter: BluetoothAdapter? by lazy {
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager
manager.adapter
}
private val scanner: BluetoothLeScanner? by lazy {
adapter?.bluetoothLeScanner
}
fun startScan(duration: Long = 10000): Flow<ScanResult> = callbackFlow {
// Bluetooth অবস্থা পরীক্ষা করুন
if (adapter?.isEnabled != true) {
close(IllegalStateException("Bluetooth disabled"))
return@callbackFlow
}
// স্ক্যান কনফিগারেশন
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build()
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
val callback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
trySend(result)
}
override fun onScanFailed(errorCode: Int) {
close(BLEException("Scan failed: $errorCode"))
}
}
// স্ক্যানিং শুরু করুন
scanner?.startScan(filters, settings, callback)
// সময়ের পরে অটো-স্টপ
delay(duration)
scanner?.stopScan(callback)
close()
}.flowOn(Dispatchers.IO)
fun stop() {
scanner?.stopScan(object : ScanCallback() {})
}
}
class BLEException(message: String) : Exception(message)
DeviceScanner ক্লাস প্রতিক্রিয়াশীল BLE স্ক্যানিংয়ের জন্য Kotlin Flow (callbackFlow) ব্যবহার করে। স্ক্যানিং LOW_LATENCY সেটিংস এবং Heart Rate Service UUID ফিল্টার দিয়ে শুরু হয়। ফলাফল onScanResult-এর মাধ্যমে Flow-তে নির্গত হয়। নির্দিষ্ট সময়ের পর অটো-স্টপ (ডিফল্ট 10 সেকেন্ড)। FlowOn(Dispatchers.IO) BLE কার্যক্রমকে ব্যাকগ্রাউন্ড থ্রেডে স্থানান্তর করে। এই পদ্ধতি viewModelScope.launch এবং collect-এর মাধ্যমে MVVM আর্কিটেকচারে BLE স্ক্যানিং সক্ষম করে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
BluetoothLeScanner BLE স্ক্যানিংয়ের জন্য একটি Android ক্লাস (API 21+)। এটি BluetoothAdapter.getBluetoothLeScanner()-এর মাধ্যমে পাওয়া যায়। এটি তিনটি স্ক্যান মোড (LOW_POWER, BALANCED, LOW_LATENCY), UUID, নাম এবং MAC ঠিকানা দ্বারা ফিল্টারিং, ব্যাচ ফলাফল এবং ব্যাকগ্রাউন্ড স্ক্যানিংয়ের জন্য PendingIntent সমর্থন করে। এটি পুরনো BluetoothAdapter.startLeScan() পদ্ধতি প্রতিস্থাপন করে।
SCAN_MODE_LOW_POWER — 5–10 সেকেন্ড আবিষ্কার বিলম্ব সহ ব্যাকগ্রাউন্ড মোড, ন্যূনতম পাওয়ার খরচ। SCAN_MODE_LOW_LATENCY — প্রায় 100 ms বিলম্ব সহ সক্রিয় মোড, সর্বোচ্চ পাওয়ার খরচ। SCAN_MODE_BALANCED — আপস (~2 সেকেন্ড বিলম্ব)। UI স্ক্যানিংয়ের জন্য LOW_LATENCY ব্যবহার করুন, ব্যাকগ্রাউন্ড মনিটরিংয়ের জন্য PendingIntent সহ LOW_POWER ব্যবহার করুন।
কারণ: Bluetooth নিষ্ক্রিয় (adapter.isEnabled পরীক্ষা করুন), অনুমতি অনুপস্থিত (API 31+-এ BLUETOOTH_SCAN, API 23–30-এ ACCESS_FINE_LOCATION), scanner = null (অ্যাডাপ্টার অনুপলব্ধ), ডিভাইস সীমার বাইরে, বা ভুল ফিল্টার। onScanFailed-ও পরীক্ষা করুন — ত্রুটি কোড কারণ নির্দেশ করে: SCAN_FAILED_ALREADY_STARTED (1) বা SCAN_FAILED_APPLICATION_REGISTRATION_FAILED (2)।
startScan()-এর PendingIntent সংস্করণ ব্যবহার করুন — ScanCallback-এর পরিবর্তে PendingIntent পাস করুন। যখন একটি BLE ডিভাইস আবিষ্কৃত হয়, Android BroadcastReceiver-এ একটি Broadcast পাঠায়, যা সিস্টেম শুরু করতে পারে এমনকি অ্যাপ ব্যাকগ্রাউন্ডে থাকলেও। Android 8+-এর জন্য, BroadcastReceiver ম্যানিফেস্টে যোগ করুন। Android 10+-এ, প্রস্তুতকারক শক্তি সঞ্চয় সীমাবদ্ধতা বিবেচনা করুন।
BluetoothLeScanner-এর আবিষ্কৃত ডিভাইসের সংখ্যার কোনও সীমা নেই — সীমা পরিবেশের BLE সম্পৃক্ততার উপর নির্ভর করে। একটি অফিসে 20–50টি সক্রিয় BLE ডিভাইস থাকতে পারে, একটি শপিং সেন্টারে শত শত। ফিল্টারিংয়ের জন্য ScanFilter (UUID, নাম দ্বারা) ব্যবহার করুন। ফিল্টারিং ছাড়া, ফলাফলগুলি অ্যাসিঙ্ক্রোনাসভাবে প্রক্রিয়া করুন — onScanResult প্রতি সেকেন্ডে ডজন ডজন বার কল হতে পারে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন