Android无法找到任何BLE设备

时间:2017-02-15 13:33:58

标签: android bluetooth bluetooth-lowenergy

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

我按原样构建这个应用程序,它找不到任何东西。

所以我从Playstore下载了一台BLE扫描仪,可以正常工作并查找所有设备。

我知道在没有任何示例代码的情况下很难说,但我已经尝试过这么多,而且我不确定我是否会错过一些完全基本的东西。

9 个答案:

答案 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设备。我希望它也对您有用:

https://github.com/schollp/BluetoothLEGatt-Android8

答案 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)。这很奇怪而且令人困惑。