当前位置: 首页 > 知识库问答 >
问题:

AndroidBLE被动扫描

房冥夜
2023-03-14

我想在我的Android应用程序中被动地扫描BLE广告商,
但我找不到如何做到这一点。

> < li>

根据蓝牙4.0核心规范,存在被动扫描模式。< br >第6卷:核心系统包[低能耗控制器卷],< br > D部分:4.1被动扫描< br > https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=282159
“设备可以使用被动扫描来查找区域中的广告设备。”

而且,android有一个决定扫描类型的参数。(主动/被动)
http://androidxref.com/4.3_r2.1/xref/external/bluetooth/bluedroid/stack/btm/btm_ble_gap.c#555
“扫描类型:主动扫描或被动扫描”

同时,iOS可以被动扫描ble广告主。(可惜仅限后台模式)< br > http://lists . apple . com/archives/bluetooth-dev/2012/May/msg 00041 . html < br >“当应用程序在后台时,iOS会执行被动扫描。”

但是我无法找到是否可以使用被动扫描模式。

问:是否可以在Android上使用“被动扫描”?如果可能,如何使用此功能?

共有2个答案

柯景龙
2023-03-14

在AOSP存储库中找到btif_gatt_client.c,编辑它,

取代

BTM_BleSetScanParams(p_cb->scan_interval, p_cb->scan_window, BTM_BLE_SCAN_MODE_ACTI);

BTM_BleSetScanParams(p_cb->scan_interval, p_cb->scan_window, BTM_BLE_SCAN_MODE_PASS);

然后构建AOSP,将图像闪存到手机,然后被动扫描工作。

扈沛
2023-03-14

< code >主动和< code >被动扫描的区别在于< code >主动扫描向广告商请求一个< code>SCAN_RESPONSE数据包。这是通过在检测到广告后发送一个< code>SCAN_REQUEST包来完成的。两者的信息(有效载荷)将在设备发现回调的< code>scanRecord参数中。

从核心规范来看:

设备可以使用主动扫描来获得关于设备的更多信息,这些信息对于填充用户界面可能是有用的。主动扫描涉及更多的链路层广告消息。

因此,对于任何用例,没有必要区分这两种扫描类型。

但是,如果您想在后台侦听广告,那么您需要通过创建服务来自己执行此操作 - 没有内置功能(从Android 4.4开始)。

对于背景扫描,以此为例。但是扫描会在你的应用被系统终止(或者被用户停止)的时候结束。

通过AlarmManager启动PendingEvent(应用程序中的任何位置,必须至少运行一次才能启动服务…)

AlarmManager alarmMgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), BleScanService.class);
PendingIntent scanIntent = PendingIntent.getService(getActivity(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(), intervalMillis, scanIntent);

BleScanService

public class BleScanService extends Service implements LeScanCallback {

private final static String TAG = BleScanService.class.getSimpleName();

private final IBinder mBinder = new LocalBinder();

private BluetoothManager mBluetoothManager;

private BluetoothAdapter mBluetoothAdapter;

public class LocalBinder extends Binder {
        public BleScanService getService() {
            return BleScanService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initialize();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        long timeToScan = preferences.scanLength().get();
        startScan(timeToScan);

        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * Initializes a reference to the local bluetooth adapter.
     * 
     * @return Return true if the initialization is successful.
     */
    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter
        // through
        // BluetoothManager.
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                Log.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        if (mBluetoothAdapter == null) {
            mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (mBluetoothAdapter == null) {
                Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
                return false;
            }
        }

        Log.d(TAG, "Initialzed scanner.");
        return true;
    }

    /**
     * Checks if bluetooth is correctly set up.
     * 
     * @return
     */
    protected boolean isInitialized() {
        return mBluetoothManager != null && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
    }

    /**
     * Checks if ble is ready and bluetooth is correctly setup.
     * 
     * @return
     */
    protected boolean isReady() {
        return isInitialized() && isBleReady();
    }

    /**
     * Checks if the device is ble ready.
     * 
     * @return
     */
    protected boolean isBleReady() {
        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
    }

    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        Log.d(TAG, "Found ble device " + device.getName() + " " + device.getAddress());
        broadcastOnDeviceFound(device, scanRecord);
    }

    /**
     * Broadcasts a message with the given device.
     * 
     * @param device
     * @param scanRecord 
     */
    protected void broadcastOnDeviceFound(final BluetoothDevice device, byte[] scanRecord) {
        assert device != null : "Device should not be null.";

        Intent intent = new Intent(BleServiceConstants.ACTION_DEVICE_DISCOVERED);
        intent.putExtra(BleServiceConstants.EXTRA_DEVICE_DISCOVERED_DEVICE, device);
        intent.putExtra(BleServiceConstants.EXTRA_DEVICE_DISCOVERED_SCAN_RECORD, scanRecord);
        sendBroadcast(intent);
    }

    /**
     * Starts the bluetooth low energy scan It scans at least the
     * delayStopTimeInMillis.
     * 
     * @param delayStopTimeInMillis
     *            the duration of the scan
     * @return <code>true</code> if the scan is successfully started.
     */
    public boolean startScan(long delayStopTimeInMillis) {
        if (!isReady())
            return false;

        if (preferences.shouldScan().get()) {
            if (delayStopTimeInMillis <= 0) {
                Log.w(TAG, "Did not start scanning with automatic stop delay time of " + delayStopTimeInMillis);
                return false;
            }

            Log.d(TAG, "Auto-Stop scan after " + delayStopTimeInMillis + " ms");
            getMainHandler().postDelayed(new Runnable() {

                @Override
                public void run() {
                    Log.d(TAG, "Stopped scan.");
                    stopScan();
                }
            }, delayStopTimeInMillis);
        }
        return startScan();
    }

    /**
     * @return an handler with the main (ui) looper.
     */
    private Handler getMainHandler() {
        return new Handler(getMainLooper());
    }

    /**
     * Starts the bluetooth low energy scan. It scans without time limit.
     * 
     * @return <code>true</code> if the scan is successfully started.
     */
    public boolean startScan() {
        if (!isReady())
            return false;

        if (preferences.shouldScan().get()) {
            if (mBluetoothAdapter != null) {
                Log.d(TAG, "Started scan.");
                return mBluetoothAdapter.startLeScan(this);
            } else {
                Log.d(TAG, "BluetoothAdapter is null.");
                return false;
            }
        }
        return false;
    }

    /**
     * Stops the bluetooth low energy scan.
     */
    public void stopScan() {
        if (!isReady())
            return;

        if (mBluetoothAdapter != null)
            mBluetoothAdapter.stopLeScan(this);
        else {
            Log.d(TAG, "BluetoothAdapter is null.");
        }
    }

    @Override
    public void onDestroy() {
        preferences.edit().shouldScan().put(false).apply();
        super.onDestroy();
    }
}

常量只是用于分发意向操作和额外名称的字符串。还有另一个首选项存储存储扫描阶段应该多长时间...您可以根据需要轻松替换它。

然后,您必须使用与上述操作名称(< code>BleServiceConstants)匹配的意图过滤器注册一个广播接收器。操作设备发现)

public class DeviceWatcher extends BroadcastReceiver {

  @Override
    public void onReceive(Context context, Intent intent) {
        BluetoothDevice device =  intent.getParcelableExtra(BleServiceConstants.EXTRA_DEVICE_DISCOVERED_DEVICE);

  // do anything with this information

  }
}
 类似资料:
  • 我正在Android(移动设备a)上执行UUID过滤扫描,我有两个测试用例。 一个人在另一个Android设备(移动设备b)上使用一个名为BLE扫描仪的应用程序来创建一个具有两个测试服务的BLE服务器(每个服务都有自己唯一的UUID)。另一种是通过Arduino BLE服务器,为其服务定制UUID。 如果我使用移动设备B的BLE扫描仪应用程序并扫描arduino,我可以找到它,连接到它并查看服务以

  • 我必须构建一个Android应用程序,用于读取一种设备上的信息,该设备仅在过滤时在扫描时显示(一般扫描不会显示它)。该设备类似于信标,因此它仅通告数据,这些数据在通告上具有我想要的信息(它不可连接)。制造商给我的过滤器是原始数据。即: 0x02010612435542 我不能按名称过滤它,因为设备不会宣传它的名称。我也不能通过来完成,因为应用程序以前不会知道设备的地址(这将是许多此类设备)。 nr

  • 我试图从用户那里得到2个整数。这是我的代码的相关部分: 起初,它抛出一个,所以我使用了。现在,它只需跳过扫描器并立即调用。

  • 本文向大家介绍扫二维码下载apk并统计被扫描次数,包括了扫二维码下载apk并统计被扫描次数的使用技巧和注意事项,需要的朋友参考一下 需求:想让用户扫描一个二维码就能下载APP,并统计被扫描次数。 两种实现方法: 1.一般我们用草料生成二维码,如果没有注册的话只能生成一个包含下载网址的静态码,没有统计功能,而且出了自己截图保存外,草料是不会保存你的二维码的。 如果注册草料后,可以选择生成活码。所谓活

  • 您可以通过Burp 控制台(Burp Dashboard)上的新的扫描(New scan)按钮或是 Burp 中出现的菜单中的Scan选项来启动扫描。利用这些方法可打开扫描启动窗口,然后您可以使用它配置扫描中的各种详细参数。 扫描细节 扫描启动界面的详细的扫描信息(Scan details)部分允许您选择扫描类型,配置要扫描的内容等等信息。 扫描类型 您可以选择以下扫描类型: 抓取并审计(Craw

  • 我必须建立一个应用程序,扫描BLE设备,并返回它的数据。扫描时设备不会显示,除非我使用过滤器。 UUID 不是一个选项,设备不会广播其名称(使用 扫描时会显示 N/A。 我正在尝试按MAC地址扫描它。但是,我不知道MAC地址,因为它可以是任何类型的设备,所以应用程序之前不会知道设备的MAC地址。 我已经知道设备的地址上有一个前缀,即。问题是后缀。我如何(如果可能的话)制作一个正则表达式作为参数传递