首页 > 解决方案 > 在后台运行 BLE ScanCallback

问题描述

我希望能够在后台扫描 BLE 标签。

我已阅读有关使用服务来执行此操作的信息。但是,当服务被执行,然后我在手机上运行另一个应用程序时,BLE 扫描回调停止执行,但服务仍然正常运行。

我知道 BLE 回调停止是因为 log cat 停止生成日志数据,直到我再次打开应用程序。

以下是我的 MainActivity:

public class MainActivity extends AppCompatActivity {

BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
Button startScanningButton;
Button stopScanningButton;
TextView peripheralTextView;
private NotificationManagerCompat notificationManager;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;

private static final String TAG = "ExampleJobService";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Log.d(TAG, "onCreate MAIN");

    notificationManager = NotificationManagerCompat.from(this);
    peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
    peripheralTextView.setMovementMethod(new ScrollingMovementMethod());

    startScanningButton = (Button) findViewById(R.id.StartScanButton);

    startScanningButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Log.d(TAG, "Start button");
            startService(new Intent(MainActivity.this, ExampleService.class));
        }
    });

    stopScanningButton = (Button) findViewById(R.id.StopScanButton);
    stopScanningButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Log.d(TAG, "Stop 1");
            Intent serviceIntent = new Intent(MainActivity.this, ExampleService.class);
            stopScanning();
            stopService(serviceIntent);
            Log.d(TAG, "Stop 2");

        }
    });

    btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    btAdapter = btManager.getAdapter();
    btScanner = btAdapter.getBluetoothLeScanner();


    if (btAdapter != null && !btAdapter.isEnabled()) {
        Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
    }

    // Make sure we have access coarse location enabled, if not, prompt the user to enable it
    if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("This app needs location access");
        builder.setMessage("Please grant location access so this app can detect peripherals.");
        builder.setPositiveButton(android.R.string.ok, null);
        builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
            }
        });
        builder.show();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {

    switch (requestCode) {
        case PERMISSION_REQUEST_COARSE_LOCATION: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                System.out.println("coarse location permission granted");
            } else {
                final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("Functionality limited");
                builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                    @Override
                    public void onDismiss(DialogInterface dialog) {
                    }
                });
                builder.show();
            }
            return;
        }
    }
}

public void startScanning() {

    peripheralTextView.setText("");
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            btScanner.startScan(leScanCallback);
        }
    });
}

public void stopScanning() {
    System.out.println("stopping scanning");
    peripheralTextView.append("Stopped Scanning");
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            btScanner.stopScan(leScanCallback);
        }
    });
}

}

下面是示例服务:

public class ExampleService extends Service {

BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;

TextView peripheralTextView;

private NotificationManagerCompat notificationManager;
private static final String TAG = "ExampleJobService";

@Override
public void onCreate() {
    super.onCreate();
    Log.d(TAG, "onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d(TAG, "onStartCommand");

    btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    btAdapter = btManager.getAdapter();
    btScanner = btAdapter.getBluetoothLeScanner();

    //do heavy work on a background thread
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            btScanner.startScan(leScanCallback);
        }
    });

    return START_REDELIVER_INTENT;
}

private ScanCallback leScanCallback = new ScanCallback() {
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        Log.d(TAG, "BLE executed");
        if(result.getDevice().getAddress().equals("EE:7E:DE:9B:65:46") && result.getRssi() > -80){
            Log.d(TAG, "Tag found");
        }
    }
};

@Override
public void onDestroy() {
    Log.d(TAG, "Destroy");
    super.onDestroy();
}

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

编辑1:

String[] peripheralAddresses = new String[]{"EE:7E:DE:9B:65:46"};

 @Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d(TAG, "onStartCommand");

    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,
            0, notificationIntent, 0);

    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Example Service")
            .setContentText("input")
            .setSmallIcon(R.drawable.ic_one)
            .setContentIntent(pendingIntent)
            .build();
    startForeground(1, notification);

    ScanSettings settings = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
            .build();

    // Build filters list
    List<ScanFilter> filters = null;
    if (peripheralAddresses != null) {
        filters = new ArrayList<>();
        for (String address : peripheralAddresses) {
            ScanFilter filter = new ScanFilter.Builder()
                    .setDeviceAddress(address)
                    .build();
            filters.add(filter);
        }
    }

    btScanner.startScan(filters, settings, leScanCallback);

    return START_STICKY;
}

标签: androidbluetooth-lowenergy

解决方案


首先,我建议您添加扫描过滤器,因为如果您没有扫描过滤器,Android 会在一段时间后停止扫描。

其次,您的服务不会长期存在,因为如果您设备的 Android 版本或多或等于 Android Oreo(Android 8),Android 会杀死它。

因此,我建议您阅读本文以找到更好的解决方案。

希望对你有帮助!


推荐阅读