2016-09-18 1 views
0

Zunächst möchte ich nur darauf hinweisen, dass ich Android für nur ein paar Wochen jetzt gelernt habe, also bitte entschuldigen Sie alle schäbigen Code. Ich versuche, eine App zu machen, die einfach in der Nähe von Bluetooth Low-Energy-Geräte (in den Logs für jetzt) ​​auflisten und schließlich mit ihnen verbinden.Bluetooth Location Permissions auf Android 6.0

Mehrere Wochen nach dem Start dieses Projekts habe ich eine Mauer mit Android 6.0-Standortberechtigungen geknackt, die für einen erfolgreichen Bluetooth-Scan erforderlich sind. Der folgende Code ist das, was ich im Moment habe:

package com.benstechtips.bluetoothletest4; 

import android.annotation.TargetApi; 
import android.app.Activity; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothGatt; 
import android.bluetooth.BluetoothGattCallback; 
import android.bluetooth.BluetoothGattCharacteristic; 
import android.bluetooth.BluetoothGattService; 
import android.bluetooth.BluetoothManager; 
import android.bluetooth.BluetoothProfile; 
import android.bluetooth.le.BluetoothLeScanner; 
import android.bluetooth.le.ScanCallback; 
import android.bluetooth.le.ScanFilter; 
import android.bluetooth.le.ScanResult; 
import android.bluetooth.le.ScanSettings; 
import android.content.Context; 
import android.content.Intent; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Bundle; 
import android.os.Handler; 
import android.support.v7.app.AppCompatActivity; 
import android.util.Log; 
import android.widget.Toast; 

import java.util.ArrayList; 
import java.util.List; 

@TargetApi(21) 
public class MainActivity extends AppCompatActivity { 

private BluetoothAdapter mBluetoothAdapter; 
private int REQUEST_ENABLE_BT = 1; 
private Handler mHandler; 
private static final long SCAN_PERIOD = 10000; 
private BluetoothLeScanner mLEScanner; 
private ScanSettings settings; 
private List<ScanFilter> filters; 
private BluetoothGatt mGatt; 

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

    mHandler = new Handler(); 
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
     Toast.makeText(this, "BLE Not Supported", Toast.LENGTH_SHORT).show(); 
     finish(); 
    } 
    final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
    mBluetoothAdapter = bluetoothManager.getAdapter(); 


} 

@Override 
protected void onResume() { 
    super.onResume(); 

    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { 
     Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
     startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 
    } else { 
     if (Build.VERSION.SDK_INT >= 21) { 
      mLEScanner = mBluetoothAdapter.getBluetoothLeScanner(); 
      settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); 
      filters = new ArrayList<ScanFilter>(); 
     } 
     scanLeDevice(true); 
    } 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { 
     scanLeDevice(false); 
    } 
} 

@Override 
protected void onDestroy() { 
    if (mGatt == null) { 
     return; 
    } 
    mGatt.close(); 
    mGatt = null; 
    super.onDestroy(); 
} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == REQUEST_ENABLE_BT) { 
     if (resultCode == Activity.RESULT_CANCELED) { 
      //Bluetooth not enabled. 
      finish(); 
      return; 
     } 
    } 
    super.onActivityResult(requestCode, resultCode, data); 
} 

private void scanLeDevice(final boolean enable) { 
    if (enable) { 
     mHandler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       Log.i("Scan Status", "Stopping Scan..."); 
       if (Build.VERSION.SDK_INT < 21) { 
        mBluetoothAdapter.stopLeScan(mLeScanCallback); 
       } else { 
        mLEScanner.stopScan(mScanCallback); 

       } 
      } 
     }, SCAN_PERIOD); 
     if (Build.VERSION.SDK_INT < 21) { 
      Log.i("Scan Status", "Starting Scan..."); 
      mBluetoothAdapter.startLeScan(mLeScanCallback); 
     } else { 
      mLEScanner.startScan(filters, settings, mScanCallback); 
     } 
    } else { 
     Log.i("Scan Status", "Stopping Scan..."); 
     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) { 
     Log.i("callbackType", String.valueOf(callbackType)); 
     Log.i("result", result.toString()); 
     BluetoothDevice 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 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("onLeScan", device.toString()); 
         //connectToDevice(device); 
        } 
       }); 
      } 
}; 

public void connectToDevice(BluetoothDevice device) { 
    if (mGatt == null) { 
     mGatt = device.connectGatt(this, false, gattCallback); 
     scanLeDevice(false);// will stop after first device detection 
    } 
} 

private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
    @Override 
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
     Log.i("onConnectionStateChange", "Status: " + status); 
     switch (newState) { 
      case BluetoothProfile.STATE_CONNECTED: 
       Log.i("gattCallback", "STATE_CONNECTED"); 
       gatt.discoverServices(); 
       break; 
      case BluetoothProfile.STATE_DISCONNECTED: 
       Log.e("gattCallback", "STATE_DISCONNECTED"); 
       break; 
      default: 
       Log.e("gattCallback", "STATE_OTHER"); 
     } 

    } 

    @Override 
    public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
     List<BluetoothGattService> services = gatt.getServices(); 
     Log.i("onServicesDiscovered", services.toString()); 
     gatt.readCharacteristic(services.get(1).getCharacteristics().get 
       (0)); 
    } 

    @Override 
    public void onCharacteristicRead(BluetoothGatt gatt, 
            BluetoothGattCharacteristic 
              characteristic, int status) { 
     Log.i("onCharacteristicRead", characteristic.toString()); 
     gatt.disconnect(); 
    } 
}; 

Nun, soweit ich das beurteilen kann, auf einer Android-Version vor Version 6.0, würde dieser Code arbeiten und die Namen der gefundenen Geräte (I Anzeige die Verbindung zum Gerät für den Moment deaktiviert haben). Doch auf Android 6.0, erhalte ich folgende Fehlermeldung:

java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results 

Ich verstehe, dass dies meine app aufgrund nicht zu haben gewünschten Ort Berechtigungen. Obwohl ich das folgende in meiner AndroidManifest.xml Datei habe, weiß ich, dass ich Erlaubnis vom Benutzer anfordern muss.

<?xml version="1.0" encoding="utf-8"?> 

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
<uses-permission android:name="android.permission.BLUETOOTH"/> 
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> 

<application 
    android:allowBackup="true" 
    android:icon="@mipmap/ic_launcher" 
    android:label="@string/app_name" 
    android:supportsRtl="true" 
    android:theme="@style/AppTheme"> 
    <activity android:name=".MainActivity"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 

      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
</application> 

Aber meine Frage ist, wie kann ich bitte um die Erlaubnis vom Benutzer?

Antwort

1

Ich stieß auf das gleiche Problem! Dies war ein kürzlich hinzugefügtes Sicherheitsmerkmal in Marshmallow. Hier ist, was die Erlaubnis eingeholt wie folgt aussieht:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
     if (this.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      requestPermissions(new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 
        PERMISSION_REQUEST_COARSE_LOCATION); 
     } 
} 

so dass

private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1; 

ich nur grob Standort gewählt haben. Soweit ich weiß, spielt es keine Rolle, welche Sie auswählen. Sie können dies für Ihre Hauptaktivität in onCreate ablegen. Hoffe das hilft!

Verwandte Themen