2017-02-15 133 views
0

这是他的问题。我开发了一款iOS应用程序来控制BLE LED设备(以及其他一些功能)。一切正常,顺利。现在我想为Android开发相同的应用程序,并且我已经在扫描BLE设备时失败了。我已经尝试了几个教程和示例代码,但无论我做什么,我都找不到任何设备。我在Moto G4 Play上工作。蓝牙的作品,我可以在设备中配对设备,但它不会与我尝试过的任何示例代码/教程。 例如这一个: https://github.com/kaviles/BLE_TutorialsAndroid无法找到任何BLE设备

我建立这个应用程序,因为它是,它找不到任何东西。

因此,我从Playstore下载了一款BLE扫描仪,并且可以正常工作并找到所有设备。

我知道这很难说没有任何示例代码,但我已经尝试了这么多,我不知道如果我错过了一个完全基本的东西。

+2

检查应用程序的权限。检查SDK 23权限,因为您需要位置权限。确保位置服务处于打开状态。除此之外,请检查您的代码是否正常! – zed

+0

我设置了所有权限,但它无法正常工作。根据这个:https://code.google.com/p/android/issues/detail?id=196485 这似乎是一个问题 – Patricks

+0

这不是一个问题,它的目的是行为,因为BLE设备可以发出地点信息。您必须添加位置服务权限,并且如果您针对API 23+进行构建,则必须在运行时询问权限。 – zed

回答

2

正如评论中所述,如果您的targetSdk是23+或其他,您必须相应地设置权限。位置服务必须开启。

为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"/> 

要检查蓝牙权限:

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

要请求运行时权限与:

public void requestBlePermissions(final Activity activity, int requestCode) { 
    ActivityCompat.requestPermissions(activity, 
      new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 
      requestCode); 
} 

然后检查起批结果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; 
} 

检查位置服务:

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

感谢您的很好的解释。现在我觉得很愚蠢,因为我真的不知道如何让这个工作。

这里是我的清单:

<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"/> 

在这里,我的活动:

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

}

我刚刚认识到,hasBlePermissions()始终返回false即便如此清单中的权限正确设置。

更新:得到它的工作。一旦你了解它并不难。首先授予权限,然后扫描设备。这是我在onCreate方法更新的代码:

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

不适合我。你确定这是你的代码吗? –

+1

看到我上面更新的代码。我希望这是必不可少的部分。自从我上一篇文章以来,我的代码发生了很大变化,所以我找回了问题所在。 – Patricks

0

我使用科尔多瓦插件cordova-plugin-ble-central,它与Android很好地协作。该插件需要以下权限:

ACCESS_COARSE_LOCATION

蓝牙

BLUETOOTH_ADMIN

希望这有助于

0

对于Xamarin,API> = 24 我想出如何使它工作,可能不太直观,您需要使用COARSE_LOCATION权限才能使蓝牙工作。转到Xamarin上的项目>右键单击>选项>选中蓝牙框,然后选择位置权限>确定 - >在设备上重建