Android Marshmallow [API 23] : Bluetooth UUID retu

2019-07-15 07:57发布

问题:

Just updated my android to marshmallow and realized that is not working very well. I have just created an app that reports the Devices and Services (with UUIDs) availables via classical bluetooth:

I've tested it in:

API 16

API 22

API 23

My manifiest permissions are:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

And if you want the check the code of the app:

  • Here it is

I'm running out of ideas, so, any help would be greatly appreciated

Thanks!

回答1:

To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods now return a constant value of 02:00:00:00:00:00.

To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions:

WifiManager.getScanResults();
BluetoothDevice.ACTION_FOUND;
BluetoothLeScanner.startScan();

so this is the update feature, add those three method you can get the UUID



回答2:

After headaches and hours of research, the answer is create the socket not with CreateInsecureRfcommSocketToServiceRecord, but instead with CreateRfcommSocketToServiceRecord and a default UUID like "00001101-0000-1000-8000-00805F9B34FB"



回答3:

I should imagine you are having the same problem I had, for SDK 23 you have to get the user to confirm they give permission to ACCESS_COARSE_LOCATION. (I assume you are running BLE searches)

have a look at you console log and I am guessing you will find a very add error that looks like this, highlighted in blue.

java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
               at android.os.Parcel.readException(Parcel.java:1627)
               at android.os.Parcel.readException(Parcel.java:1579)
               at android.bluetooth.IBluetoothGatt$Stub$Proxy.startScan(IBluetoothGatt.java:772)
               at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.onClientRegistered(BluetoothLeScanner.java:324)
               at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:56)
               at android.os.Binder.execTransact(Binder.java:453)

It appears that you need to get user permission (like an iOS app) so you need to add in some code in you init like this

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)){
                if (DEBUG) Log.i(TAG, "EXPLANATION NEEDED");
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("Warning Permission Needed");
                builder.setMessage("If you don't enable the location for this app then we can not connect to the controller");
                builder.setPositiveButton("Change", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
                        }
                    }
                });
                AlertDialog dialog = builder.create();
                dialog.show();
            }else{
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_LOCATION);
            }
        }
    }

Here you must handle what to do if the user doesn't read the message and clicks deny. so check the return in the below method

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_LOCATION){
        if (grantResults[0] != PackageManager.PERMISSION_GRANTED){
           // ask the question again as they denied the permission 
        }
    }

}

After all that you it will all suddenly work again if your problem was like mine