因此,我从Playstore下载了一个BLE扫描仪,它可以正常工作并找到所有设备。
我知道没有示例代码很难说,但我已经尝试了很多次,而且我不确定是否错过了一些非常基本的东西。
正如评论中所讨论的那样,如果您的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;
}
}
requestBlePermissions()
方法体似乎请求位置权限而不是蓝牙权限。 - Rule<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);
}
}
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001);
我正在使用 Cordova 插件 cordova-plugin-ble-central,它与 Android 非常兼容。该插件需要以下权限:
ACCESS_COARSE_LOCATION
BLUETOOTH
BLUETOOTH_ADMIN
希望这能帮到你,
你尝试过从开发者网站获取的Android BLE示例代码吗?
https://developer.android.com/samples/BluetoothLeGatt/index.html
请确保 UUID 并在需要时对此示例代码进行必要的更改,以便与 Android 应用程序通信。我对应用程序开发也非常新手,但是我设法将BLE GATT示例适配到我的Android 8设备上。我希望它也适用于你的设备:
对于 Xamarin,API>=24 我找到了解决方法,可能不太直观,您需要 COARSE_LOCATION 权限才能让蓝牙正常工作。在 Xamarin 项目中,右键单击 > 选项 > 勾选蓝牙和位置权限的框 > 确定 --> 在设备上重新构建
我认为摩托罗拉设备存在问题。摩托罗拉设备将位置和GPS合并为一个称为“位置”的单一选项。在其他设备上,只要您的应用程序可以访问位置,蓝牙扫描就可以正常工作,但如果您使用摩托罗拉设备,则还需要启用位置(GPS)。这很奇怪也很令人困惑。
对于 Android 10,您还需要 ACCESS_BACKGROUND_LOCATION 权限
Kotlin 代码
if (ContextCompat.checkSelfPermission(
baseContext,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(
this@MainActivity,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
12)
}
ACCESS_BACKGROUND_LOCATION
权限。只有ACCESS_FINE_LOCATION
权限就足够了。这个Android开发者页面只提到了FINE权限,我刚刚检查了一下,没有BACKGROUND权限也可以使用BLE。 - Fabio Goncalves