active
扫描和
passive
扫描的区别在于,
active
扫描从广告者请求一个
SCAN_RESPONSE
数据包。这是在检测到广告后发送一个
SCAN_REQUEST
数据包来完成的。两者的信息(有效负载)都将在发现设备回调的
scanRecord
参数中。
根据
核心规范:
“设备可以使用主动扫描来获取有关可能对填充用户界面有用的设备的更多信息。主动扫描涉及更多链路层广告消息。”
因此,在任何用例中,不需要区分这两种扫描类型。
但是,如果您想在后台侦听广告,则需要通过创建
Service
自行执行此操作-没有内置功能(截至Android 4.4)。
进行后台扫描,请参考此示例。但是,扫描会在应用程序被系统杀死(或被用户停止)时结束。
通过AlarmManager在任何地方启动PendingIntent(必须至少运行一次以启动服务的任何应用程序...)
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);
Ble扫描服务
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);
}
public boolean initialize() {
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;
}
protected boolean isInitialized() {
return mBluetoothManager != null && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
}
protected boolean isReady() {
return isInitialized() && isBleReady();
}
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);
}
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);
}
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();
}
private Handler getMainHandler() {
return new Handler(getMainLooper());
}
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;
}
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();
}
}
常量只是用于分发意图操作和额外名称的字符串。还有另一个偏好存储,用于存储扫描阶段应持续多长时间...您可以轻松地根据自己的需求进行更改。
然后,您需要使用与上述操作名称(BleServiceConstants.ACTION_DEVICE_DISCOVERED
)匹配的意图过滤器注册广播接收器。
public class DeviceWatcher extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BleServiceConstants.EXTRA_DEVICE_DISCOVERED_DEVICE);
}
}