Patricks
Patricks

Reputation: 769

Android can't find any BLE devices

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.

Upvotes: 5

Views: 15820

Answers (9)

KyluAce
KyluAce

Reputation: 1000

I think that there is a problem with Motorola devices. Motorola devices has location and gps combined into one single option called "location". In other devices ble scanning works when your app has access to location and that's all but if you have Motorola we need also to enable location (gps). It's guite strange and confusing.

Upvotes: 0

takesavy
takesavy

Reputation: 145

For Android 10, you also need the ACCESS_BACKGROUND_LOCATION permission

Kotlin Code

    if (ContextCompat.checkSelfPermission(
                   baseContext,
                   Manifest.permission.ACCESS_BACKGROUND_LOCATION
               ) != PackageManager.PERMISSION_GRANTED) 
           {
               ActivityCompat.requestPermissions(
                   this@MainActivity,
                   arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                   12)
           }

Upvotes: 0

Kandis Toompila
Kandis Toompila

Reputation: 11

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);

Upvotes: 1

Patrick Shcoll
Patrick Shcoll

Reputation: 1

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

Upvotes: 0

Luma Z
Luma Z

Reputation: 1

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

Upvotes: 0

Patricks
Patricks

Reputation: 769

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);
    }
}

Upvotes: 4

Mayela Zamora
Mayela Zamora

Reputation: 71

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,

Upvotes: 0

zed
zed

Reputation: 3287

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;
    }
}

Upvotes: 7

Samina
Samina

Reputation: 1

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.

Upvotes: 0

Related Questions