我正在构建一个试图找到并连接到BLE设备的应用程序。我在Android 5.0的智能手机上测试了它,它的工作原理。
然后我尝试在Android 7.0上安装它,但我不能在任何BLE设备上连接。所以这是我的服务,尝试连接BLE设备并下载它的所有信息。如何更改我的代码以使用Android 6和7的应用程序?
public class BlePowerService extends Service {
public DbLayer db;
Setting settingApp;
List<ScanFilter> filters;
String[] stringSequence = new String[] {CHARACTERISTIC_FORZA_STRING, CHARACTERISTIC_TEMPERATURA_STRING};
BluetoothAdapter mBluetoothAdapter;
BluetoothGatt mGatt;
BluetoothDevice currDevice;
static final long SCAN_PERIOD = 1000;
static String SPLIT_CHAR =";";
BluetoothLeScanner mLEScanner;
Handler mHandler;
int ReadQueueIndex;
List<BluetoothGattCharacteristic> ReadQueue;
BluetoothGattCharacteristic caratteristicaDaLeggere;
ScanSettings settings;
Integer ultimaForzaLetta,ultimaTemperaturaLetta;
boolean continuaLetturaForza, continuaLetturaTemperatura;
private final Object readLock = new Object();
boolean isReading = true;
String LOG_CODE = "NOTIFSRV";
GattClientCallback gattClientCallback;
public BlePowerService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
Context sharedContext = null;
try {
sharedContext = this.createPackageContext(
"com.eresult.diabesitycare.devicesensor",
Context.CONTEXT_INCLUDE_CODE);
if (sharedContext == null) {
return;
}
db=new DbLayer(sharedContext);
db.open();
} catch (Exception e) {
String error = e.getMessage();
// Log.d(LOG_CODE,"DB error : " + error);
return;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
//RECUPERO LE IMPOSTAZIONI SETTATE DALL'UTENTE
settingApp = db.fetchSetting();
if (settingApp != null && settingApp.getAddressBleSX()!=null) {
ScanFilter.Builder scanFilterMac = null;
scanFilterMac = new ScanFilter.Builder().setDeviceAddress(settingApp.getAddressBleSX());
if(filters==null)
filters = new ArrayList<ScanFilter>();
filters.add(scanFilterMac.build());
//FILTRO ANCHE PER LA CARATTERISTICA DI FORZA
ScanFilter filter = null;
filter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(CHARACTERISTIC_FORZA_STRING)).build();
filters.add(filter);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
scanLeDevice(true);
mTimer = new Timer();
int nMinuti = settingApp.getFrequenzaDownload()!= null ? settingApp.getFrequenzaDownload() : 1;
mTimer.schedule(timerTask, 10000, 60000 * nMinuti);
}
} catch (Exception e) {
// Log.e("POWER_SERVICE", e.getMessage());
}
return super.onStartCommand(intent, flags, startId);
}
public void connectToDevice(BluetoothDevice device) {
//VERIFICO SE IL DEVICE è QUELLO CHE VOGLIO IO
if (mGatt == null && settingApp != null
&& device.getAddress().equals(settingApp.getAddressBleSX())) {
currDevice = device;
gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Handler h = new Handler(getApplicationContext().getMainLooper());
// Although you need to pass an appropriate context
h.post(new Runnable() {
@Override
public void run() {
// Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = null;
btDevice = result.getDevice();
connectToDevice(btDevice);
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
@Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
private class GattClientCallback extends BluetoothGattCallback {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
try{
super.onConnectionStateChange(gatt, status, newState);
Log.i("tag", "onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
Log.e("ERROR_SERVICE", "Connection Gatt failure status " + status);
if(mGatt == null){
}else{
disconnectGattServer();
mGatt = null;
}
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
Log.e("ERROR_SERVICE", "Connection not GATT sucess status " + status);
if(mGatt == null){
}else{
disconnectGattServer();
mGatt = null;
}
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
//Log.i("INFO", "Connected to device " + gatt.getDevice().getAddress());
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("INFO", "Disconnected from device");
if(mGatt == null){
}else{
disconnectGattServer();
mGatt = null;
}
}
}catch(Exception e){
Log.e("tag", e.getMessage());
}
}
public void disconnectGattServer() {
continuaLetturaForza = false;
continuaLetturaTemperatura = false;
if (mGatt == null) {
}
else{
try{
mGatt.disconnect();
mGatt.close();
}catch(Exception e){
mGatt = null;
}
}
mGatt = null;
currDevice = null;
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
// Log.i("INFO", "Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics =
BluetoothUtils.findCharacteristics(gatt,stringSequence);
if (matchingCharacteristics.isEmpty()) {
// Log.e("ERROR_SERVICE","Unable to find characteristics.");
return;
}else {
ReadQueue = new ArrayList<>();
for (BluetoothGattCharacteristic characterist : matchingCharacteristics) {
ReadQueue.add(characterist);
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//TO DO
} else {
//TO DO
}
}
}
public void onDestroy() {
try {
db.close();
Log.d(LOG_CODE,"DB connection closed" );
mTimer.cancel();
timerTask.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我还在我的AndroidManifest.xml中插入了这行代码:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
如果Android版本是6或更高版本,我可以设置另一个权限吗?
不必在运行时请求BLUETOOTH和BLUETOOTH_ADMIN等权限,但必须是ACCESS_COARSE_LOCATION。尝试使用以下代码请求ACCESS_COARSE_LOCATION权限:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
Log.d(TAG, "We need to show an explanation...");
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_COARSE_LOCATION);
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
finish();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Access to position is required in order to scan Bluetooth LE devices, please grant this permission to this app.").setPositiveButton("Grant now", dialogClickListener)
.setNegativeButton("Grant later", dialogClickListener).show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_COARSE_LOCATION);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// You have already the permission
}
然后,您可以在此回调中检索用户响应:
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_COARSE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
请记住,ACCESS_COARSE_LOCATION仅对使用“startLeScan”方法扫描BLE设备有用(连接时不是必需的)。在某些情况下,您必须在智能手机上启用GPS才能获得扫描结果。