BluetoothLeScanner — ما هو، طرق ومسح BLE في Android

المؤلف: IT Sectr نُشر: 2026-07-16 وقت القراءة: 10 دق

BluetoothLeScanner هي فئة Android لمسح أجهزة Bluetooth Low Energy، متاحة منذ API 21 (Android 5.0). استبدلت BluetoothLeScanner الطريقة القديمة startLeScan على BluetoothAdapter، مما يوفر واجهة برمجة تطبيقات مرنة مع إعدادات المسح (ScanSettings)، والتصفية (ScanFilter)، ودعم وضع الخلفية (PendingIntent). يتم الحصول على المثيل عبر BluetoothAdapter.getBluetoothLeScanner(). وفقًا لـ Android Developers, 2026، يدعم BluetoothLeScanner ثلاثة أوضاع للطاقة ويسمح بمسح حزم الإعلان BLE مع التصفية بواسطة UUID الخدمة أو اسم الجهاز أو عنوان MAC.

النقاط الرئيسية

  • BluetoothLeScanner — واجهة برمجة تطبيقات Android حديثة (API 21+) لمسح BLE، بديل لـ startLeScan القديم
  • ScanSettings — تكوين وضع المسح: LOW_POWER، BALANCED، LOW_LATENCY ونوع الاستدعاء
  • ScanFilter — تصفية النتائج حسب UUID الخدمة واسم الجهاز وعنوان MAC وبيانات الشركة المصنعة
  • ScanCallback — استدعاءات النتائج onScanResult و onBatchScanResults و onScanFailed مع رموز الخطأ
  • PendingIntent — المسح في الخلفية عبر BroadcastReceiver، حتى عندما يكون التطبيق في الخلفية

ما هو BluetoothLeScanner: الجوهر والحصول على المثيل

BluetoothLeScanner هي فئة نظام لإدارة مسح BLE على Android. على عكس BluetoothAdapter.startLeScan() التي تقبل استدعاءً بسيطًا LeScanCallback، توفر BluetoothLeScanner واجهة برمجة تطبيقات كائنية مع إعدادات ومرشحات ومعالجة متقدمة للأخطاء. تم تقديم هذه الفئة في API 21 (Android 5.0) إلى جانب دعم BLE 4.2 ولا تزال الطريقة الرئيسية لمسح BLE على جميع إصدارات Android الحديثة.

يتم الحصول على مثيل BluetoothLeScanner عبر BluetoothAdapter.getBluetoothLeScanner(). تُرجع الطريقة قيمة فارغة إذا كان محول Bluetooth غير متاح (Bluetooth معطل أو الجهاز لا يدعم BLE). قبل الحصول عليه، تحقق من BluetoothAdapter.isEnabled() ووجود FEATURE_BLUETOOTH_LE عبر PackageManager. بعد الحصول على الماسح، يمكن بدء المسح في أي سلسلة — يقوم Android بجدولة عمليات BLE على سلسلة داخلية لمكدس Bluetooth.

kotlin
// الحصول على 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 من توفر BLE عبر hasSystemFeature، وBluetooth مفعل، والحصول الناجح على الماسح. يبدأ startBasicScan المسح بدون إعدادات أو مرشحات — يكتشف جميع أجهزة BLE في النطاق. يحلل handleResult ScanResult: BluetoothDevice (الاسم، العنوان)، RSSI (قوة الإشارة)، scanRecord (بيانات الإعلان).

ScanSettings: أوضاع المسح ونوع الاستدعاء

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 مللي ثانية)، أقصى استهلاك للطاقة. للبحث النشط عن الأجهزة استخدم LOW_LATENCY، للمراقبة في الخلفية استخدم LOW_POWER.

reportDelay — تأخير بالمللي ثانية قبل التسليم المجمع للنتائج. إذا كان reportDelay = 0، تُرسل النتائج فورًا عند الاكتشاف. إذا كان > 0، يجمع Android النتائج ويرسل دفعة عبر onBatchScanResults. يقلل التسليم المجمع من استدعاءات الاسترجاع واستهلاك الطاقة، وهو مناسب للمسح في الخلفية بأولوية منخفضة.

kotlin
// تكوين 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)  // دفعة كل ثانيتين
            .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 لمسح واجهة المستخدم (بحث «هنا والآن»). يُستخدم lowPowerScan للمراقبة في الخلفية مع دفعة كل ثانيتين وcallbackType FIRST_MATCH (يعمل فقط عند أول اكتشاف). يستخدم longRangeScan PHY_LE_CODED (BLE بعيد المدى، حتى 1 كم). يستخدم highSpeedScan PHY_LE_2M (2 ميجابت/ثانية، أجهزة BLE 5.0+ فقط).

ScanFilter: تصفية أجهزة BLE حسب UUID والاسم

ScanFilter هي فئة لتصفية نتائج مسح BLE. بدون مرشح، يُرجع BluetoothLeScanner جميع أجهزة BLE في النطاق — في بيئة BLE كثيفة يمكن أن تكون مئات الحزم في الدقيقة. يعمل ScanFilter على تضييق النتائج إلى الأجهزة المطلوبة، مما يقلل استهلاك الطاقة وحمل التطبيق. تُطبق المرشحات على مستوى مكدس Bluetooth — يتم تجاهل الحزم غير المتطابقة قبل الوصول إلى التطبيق.

أنواع المرشحات: setServiceUuid — UUID الخدمة (تنسيق 128 بت كامل مطلوب). setDeviceName — سلسلة فرعية من اسم الجهاز (حساس لحالة الأحرف، تطابق تام للسلسلة الفرعية). setDeviceAddress — عنوان MAC دقيق. setManufacturerData — بيانات الشركة المصنعة (معرف الشركة + قناع). يمكن تعيين مرشحات متعددة لمسح واحد — يجب أن يتطابق الجهاز مع جميعها (منطق AND). لمنطق OR، ابدأ عمليات مسح متعددة.

kotlin
// إنشاء 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 — مرشح AND حسب UUID والاسم. byManufacturer — مرشح حسب بيانات الشركة المصنعة (على سبيل المثال، لـ iBeacon يُستخدم معرف شركة Apple 0x004C).

ScanCallback: معالجة نتائج المسح والأخطاء

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 غير مدعوم على الجهاز.

kotlin
// نتائج المسح الكاملة ومعالجة الأخطاء
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: مسح BLE في الخلفية عبر BroadcastReceiver

المسح باستخدام PendingIntent هي آلية BluetoothLeScanner لمسح BLE الذي يعمل حتى عندما يكون التطبيق في الخلفية (مع قيود Android 8+). بدلاً من ScanCallback، يُستخدم PendingIntent الذي يرسل Broadcast إلى BroadcastReceiver النظام عند اكتشاف جهاز BLE. يسمح هذا للتطبيق بتلقي إشعارات أجهزة BLE دون البقاء في الذاكرة (يقوم النظام بإنشاء العملية عند استلام البث).

قيود المسح في الخلفية: على Android 8+ (API 26)، الخدمات الخلفية مقيدة — يتجاوز المسح باستخدام PendingIntent هذا القيد عبر BroadcastReceiver الذي يمكن للنظام تشغيله عند استلام حدث BLE. على Android 10+ (API 29)، المسح BLE في الخلفية مقيد إضافيًا بسياسات توفير الطاقة من الشركات المصنعة (Xiaomi، Huawei، Samsung تحظر عمليات BLE الخلفية). للسيناريوهات BLE الحرجة، مطلوب إشعار خدمة أمامية.

kotlin
// مسح BLE في الخلفية عبر PendingIntent
class BackgroundBLEScanner(private val context: Context) {

    private val scanner: BluetoothLeScanner? by lazy {
        val adapter = BluetoothAdapter.getDefaultAdapter()
        adapter?.bluetoothLeScanner
    }

    fun startBackgroundScan() {
        // إنشاء PendingIntent لـ BroadcastReceiver
        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 المسح BLE في الخلفية عبر PendingIntent. يقوم startBackgroundScan بإنشاء PendingIntent الذي، عند اكتشاف جهاز BLE، يرسل Broadcast إلى BLEBroadcastReceiver. يستخرج BroadcastReceiver ScanResult عبر getPendingIntentScanResults() ويمكنه عرض إشعار أو إرسال بيانات إلى الخادم. يعمل هذا النهج حتى إذا تم إنهاء التطبيق بواسطة النظام — يعيد Android تشغيل BroadcastReceiver عند استلام البث.

مثال ماسح BLE في Kotlin مع BluetoothLeScanner

مثال كامل لماسح BLE في Kotlin يستخدم BluetoothLeScanner مع ScanSettings و ScanFilter و ScanCallback للعثور على أجهزة مراقب معدل ضربات القلب. يعرض الماسح قائمة بالأجهزة التي تم العثور عليها مع RSSI و UUIDs الخدمة، مع إمكانية الاتصال عبر BluetoothGatt.

kotlin
// ماسح BLE كامل مع coroutines في Kotlin
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 Kotlin Flow (callbackFlow) لمسح BLE التفاعلي. يبدأ المسح بإعدادات LOW_LATENCY ومرشح UUID لخدمة Heart Rate Service. تنبعث النتائج عبر onScanResult إلى Flow. إيقاف تلقائي بعد مدة محددة (10 ثوانٍ افتراضيًا). يقوم FlowOn(Dispatchers.IO) بنقل عمليات BLE إلى سلسلة خلفية. يسمح هذا النهج باستخدام مسح BLE في بنية MVVM عبر viewModelScope.launch و collect.

الأسئلة الشائعة

ما هو BluetoothLeScanner في Android؟

BluetoothLeScanner هي فئة Android (API 21+) لمسح BLE. يتم الحصول عليها عبر BluetoothAdapter.getBluetoothLeScanner(). تدعم ثلاثة أوضاع مسح (LOW_POWER، BALANCED، LOW_LATENCY)، والتصفية حسب UUID والاسم وعنوان MAC، والنتائج المجمعة، و PendingIntent للمسح في الخلفية. تحل محل الطريقة القديمة BluetoothAdapter.startLeScan().

كيف يختلف LOW_POWER عن LOW_LATENCY؟

SCAN_MODE_LOW_POWER — وضع الخلفية مع تأخير اكتشاف 5–10 ثوانٍ، استهلاك طاقة أدنى. SCAN_MODE_LOW_LATENCY — وضع نشط مع تأخير حوالي 100 مللي ثانية، أقصى استهلاك للطاقة. SCAN_MODE_BALANCED — حل وسط (تأخير ~2 ثانية). استخدم LOW_LATENCY لمسح واجهة المستخدم، و LOW_POWER مع PendingIntent للمراقبة في الخلفية.

لماذا لا يعثر BluetoothLeScanner على أجهزة؟

الأسباب: Bluetooth معطل (تحقق من adapter.isEnabled)، الأذونات المفقودة (BLUETOOTH_SCAN على API 31+، ACCESS_FINE_LOCATION على API 23–30)، scanner = فارغ (المحول غير متاح)، الجهاز خارج النطاق، أو مرشح غير صحيح. تحقق أيضًا من onScanFailed — يشير رمز الخطأ إلى السبب: SCAN_FAILED_ALREADY_STARTED (1) أو SCAN_FAILED_APPLICATION_REGISTRATION_FAILED (2).

كيفية مسح BLE في الخلفية على Android؟

استخدم إصدار PendingIntent من startScan() — مرر PendingIntent بدلاً من ScanCallback. عند اكتشاف جهاز BLE، يرسل Android Broadcast إلى BroadcastReceiver، والذي يمكن تشغيله بواسطة النظام حتى إذا كان التطبيق في الخلفية. بالنسبة لـ Android 8+، أضف BroadcastReceiver إلى البيان. على Android 10+، ضع في اعتبارك قيود توفير الطاقة من الشركات المصنعة.

كم عدد أجهزة BLE التي يمكن اكتشافها في مسح واحد؟

BluetoothLeScanner ليس له حد على عدد الأجهزة المكتشفة — يعتمد القيد على تشبع BLE للبيئة. قد يحتوي المكتب على 20–50 جهاز BLE نشطًا، ومركز التسوق المئات. استخدم ScanFilter (حسب UUID، الاسم) للتصفية. بدون تصفية، قم بمعالجة النتائج بشكل غير متزامن — قد يتم استدعاء onScanResult عشرات المرات في الثانية.

الملخص

  • BluetoothLeScanner — فئة Android حديثة (API 21+) لمسح BLE مع إعدادات وتصفية
  • ScanSettings — ثلاثة أوضاع: LOW_POWER (خلفية)، BALANCED، LOW_LATENCY (نشط)
  • ScanFilter — تصفية حسب UUID الخدمة واسم الجهاز وعنوان MAC وبيانات الشركة المصنعة بمنطق AND
  • ScanCallback — onScanResult (فردي)، onBatchScanResults (مجمّع)، onScanFailed (رموز الخطأ)
  • PendingIntent — مسح في الخلفية عبر BroadcastReceiver، يعمل عند إنهاء التطبيق
  • ScanRecord — بيانات إعلان BLE: serviceData، manufacturerSpecificData، advertiseFlags، مستوى طاقة TX
  • Kotlin Flow — يسمح callbackFlow باستخدام BluetoothLeScanner في بنية تفاعلية مع إيقاف تلقائي

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا