问题
Here's he problem. I've developed an app for iOS to control an BLE LED device (and a few other things). Everything works fine and smooth. Now I wanted develop the same app for android and I already fail at the scanning of BLE devices. I have tried a few tutorials and sample codes but whatever I do I can't find any devices. I work on a Moto G4 Play. The bluetooth works and I can pair devices in the settings but it won't work with any sample code/tutorial I've tried. For example this one: https://github.com/kaviles/BLE_Tutorials
I build this app as it is and it can't find anything.
So I downloaded a BLE Scanner from the Playstore and that works fine to and finds all devices.
I know it's hard to say without any sample code but I've tried so many and I'm not sure if I miss something completely basic.
回答1:
As discussed in the comments, you have to set up the permissions accordingly if your targetSdk is 23+ or other. The location services must be on.
Manifest permissions for API 23+:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
To check bluetooth permissions:
public boolean hasBlePermissions() {
if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return false;
} else {
return true;
}
}
To request runtime permissions with :
public void requestBlePermissions(final Activity activity, int requestCode) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
requestCode);
}
Then to check the grant results from OnRequestPermissionResult
:
public boolean checkGrantResults(String[] permissions, int[] grantResults) {
int granted = 0;
if (grantResults.length > 0) {
for(int i = 0; i < permissions.length ; i++) {
String permission = permissions[i];
if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION) ||
permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
granted++;
}
}
}
} else { // if cancelled
return false;
}
return granted == 2;
}
Check location services:
public boolean areLocationServicesEnabled(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
回答2:
Thanks for the good explanation. Now I feel quite dumb cause I really don't know how to get this working.
Here's my manifest:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
And here my activity:
public class LightActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private final static int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_light);
if(hasBlePermissions() && areLocationServicesEnabled(this)) {
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "Bluetooth low energy is not supported", Toast.LENGTH_SHORT).show();
finish();
}
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
scanLeDevice(true);
}
}
}
public boolean hasBlePermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
public void requestBlePermissions(final Activity activity, int requestCode) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, requestCode);
}
public boolean checkGrantResults(String[] permissions, int[] grantResults) {
int granted = 0;
if (grantResults.length > 0) {
for(int i = 0; i < permissions.length ; i++) {
String permission = permissions[i];
if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION) || permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
granted++;
}
}
}
} else { // if cancelled
return false;
}
return granted == 2;
}
public boolean areLocationServicesEnabled(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i("NEW DEVICE", device.getName());
}
});
}
};
}
I just recognized that hasBlePermissions() always returns false even so the permissions in the manifest are set correctly.
UPDATE: Got it working. Once you understand it it's not that hard. First grant the permissions then scan for the device. Here's my updated code in the onCreate method:
int permissionCheck = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
} else {
if(areLocationServicesEnabled(this)) {
mHandler = new Handler();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
scanLeDevice(true);
}
}
回答3:
Have you tried with android BLE sample code from developer site.
https://developer.android.com/samples/BluetoothLeGatt/index.html
Please make sure about UUID and do needful changes to communicate with android application in this sample code if required.
回答4:
I am using the Cordova plugin cordova-plugin-ble-central, which works well with Android. The Plugin requires the following permissions:
ACCESS_COARSE_LOCATION
BLUETOOTH
BLUETOOTH_ADMIN
Hope this helps,
回答5:
For Xamarin, API>=24 I figured out how to make it work, it might not be intuitive that you need COARSE_LOCATION permission to get the Bluetooth to work. Go to the project on Xamarin > right click > Options > Check the boxes for Bluetooth, and location permissions > OK --> rebuild on device
回答6:
I am also very new to app development, but I managed to adapt the BLE GATT example for my Android 8 device. I hope it works for yours as well:
https://github.com/schollp/BluetoothLEGatt-Android8
回答7:
If you build your project with https://github.com/kaviles/BLE_Tutorials just add this line after you get Adapter in MainActivity:
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001);
来源:https://stackoverflow.com/questions/42250866/android-cant-find-any-ble-devices