这是他的问题。我开发了一款适用于iOS的应用程序来控制BLE LED设备(以及其他一些东西)。一切都很好,很顺利。现在我想为Android开发相同的应用程序,我已经在扫描BLE设备时失败了。我尝试了一些教程和示例代码,但无论我做什么,我都找不到任何设备。我在Moto G4 Play上工作。蓝牙工作,我可以在设置中配对设备,但它不能使用我尝试过的任何示例代码/教程。 例如这一个: https://github.com/kaviles/BLE_Tutorials
我按原样构建这个应用程序,它找不到任何东西。
所以我从Playstore下载了一台BLE扫描仪,可以正常工作并查找所有设备。
我知道在没有任何示例代码的情况下很难说,但我已经尝试过这么多,而且我不确定我是否会错过一些完全基本的东西。
答案 0 :(得分:3)
正如评论中所讨论的,如果您的targetSdk是23+或其他,则必须相应地设置权限。位置服务必须在。
API 23 +的清单权限:
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Сообщение не соответствуют схеме сервиса СМЭВ.</faultstring>
<detail>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.4.a: Invalid content was found starting with element 'ns:SenderProvidedRequestData1'. One of '{"urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1":SenderProvidedRequestData}' is expected.</InvalidContent>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.3: Element 'ns:CallerInformationSystemSignature' cannot have character [children], because the type's content type is element-only.</InvalidContent>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.4.b: The content of element 'ns:CallerInformationSystemSignature' is not complete. One of '{WC["http://www.w3.org/2000/09/xmldsig#"]}' is expected.</InvalidContent>
</detail>
</SOAP-ENV:Fault>
检查蓝牙权限:
<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;
}
答案 1 :(得分:3)
感谢您的好解释。现在我感到非常愚蠢,因为我真的不知道如何让这个工作。
这是我的清单:
<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);
}
}
答案 2 :(得分:1)
对于Android 10,您还需要ACCESS_BACKGROUND_LOCATION权限
科林代码
if (ContextCompat.checkSelfPermission(
baseContext,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(
this@MainActivity,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
12)
}
答案 3 :(得分:0)
您是否尝试过使用开发者网站的Android BLE示例代码。
https://developer.android.com/samples/BluetoothLeGatt/index.html
如果需要,请确保UUID并进行必要的更改以与此应用程序代码中的Android应用程序进行通信。
答案 4 :(得分:0)
我使用的是Cordova插件cordova-plugin-ble-central,适用于Android。插件需要以下权限:
ACCESS_COARSE_LOCATION
BLUETOOTH
BLUETOOTH_ADMIN
希望这有帮助,
答案 5 :(得分:0)
对于Xamarin,API&gt; = 24 我想出了如何使它工作,你需要COARSE_LOCATION权限才能让蓝牙工作,这可能并不直观。转到Xamarin上的项目&gt;右键单击&gt;选项&gt;选中蓝牙框和位置权限&gt;好的 - &gt;在设备上重建
答案 6 :(得分:0)
我对应用程序开发也很陌生,但我设法将BLE GATT示例改编为我的Android 8设备。我希望它也对您有用:
答案 7 :(得分:0)
如果您使用https://github.com/kaviles/BLE_Tutorials构建项目 在MainActivity中获取适配器后,只需添加以下行即可:
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001);
答案 8 :(得分:0)
我认为Motorola设备有问题。摩托罗拉设备将位置和gps组合为一个称为“位置”的选项。在其他设备中,ble扫描仅在您的应用有权访问位置时才起作用,仅此而已,但如果您拥有Motorola,我们还需要启用位置(gps)。这很奇怪而且令人困惑。