(Native Module) Android扫描蓝牙设备返回空数组

问题描述 投票:0回答:2

我已经被困了一个星期,我想制作一个可以通过蓝牙连接到其他安卓设备但无法发现任何设备的应用程序,因为它只返回空数组。

这是我用来发现其他安卓蓝牙设备的代码:

public class BluetoothScannerModule extends ReactContextBaseJavaModule {
    private BluetoothAdapter bluetoothAdapter;
    private List<BluetoothDevice> discoveredDevices = new ArrayList<>();

    public BluetoothScannerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        reactContext.registerReceiver(receiver, filter);
    }

    @NonNull
    @Override
    public String getName() {
        return "BluetoothScannerModule";
    }

    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device != null && !discoveredDevices.contains(device)) {
                    discoveredDevices.add(device);
                }
            }
        }
    };

    @ReactMethod
    public void scanDevices(Callback callback) {
        discoveredDevices.clear();
        if (bluetoothAdapter == null) {
            callback.invoke("Bluetooth not supported");
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            callback.invoke("Bluetooth not enabled");
            return;
        }
        if (ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                ActivityCompat.requestPermissions(getCurrentActivity(), new String[]{Manifest.permission.BLUETOOTH_SCAN}, 2);
                return;
            }
        }
        bluetoothAdapter.startDiscovery();
        try {
            Thread.sleep(5000); // scan for 5 seconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bluetoothAdapter.cancelDiscovery();
        WritableArray devicesArray = Arguments.createArray();
        for (BluetoothDevice device : discoveredDevices) {
            WritableMap deviceMap = Arguments.createMap();
            deviceMap.putString("name", device.getName());
            deviceMap.putString("address", device.getAddress());
            deviceMap.putInt("bondState", device.getBondState());
            devicesArray.pushMap(deviceMap);
        }
        callback.invoke(null, devicesArray);
    }
}

并像这样登录到 React Native 以查看设备列表:

BluetoothScannerModule.scanDevices((error, devices) => {
          if (error) {
            console.error(error);
            return;
          }
          console.log(devices);
        })

编辑代码

在本机模块中:

@ReactMethod
    public void scanDevices(Callback callback) {
        discoveredDevices.clear();
        if (bluetoothAdapter == null) {
            callback.invoke("Bluetooth not supported");
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            callback.invoke("Bluetooth not enabled");
            return;
        }
        if (ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                ActivityCompat.requestPermissions(getCurrentActivity(), new String[]{Manifest.permission.BLUETOOTH_SCAN}, 2);
                return;
            }
        }
        bluetoothAdapter.startDiscovery();

        callback.invoke(null,"Discovery started");
    }

    @ReactMethod
    public void stopScan(Callback callback) {
        if (ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                ActivityCompat.requestPermissions(getCurrentActivity(), new String[]{Manifest.permission.BLUETOOTH_SCAN}, 2);
                return;
            }
        }
        bluetoothAdapter.cancelDiscovery();
        WritableArray devicesArray = Arguments.createArray();
        for (BluetoothDevice device : discoveredDevices) {
            WritableMap deviceMap = Arguments.createMap();
            deviceMap.putString("name", device.getName());
            deviceMap.putString("address", device.getAddress());
            deviceMap.putInt("bondState", device.getBondState());
            devicesArray.pushMap(deviceMap);
        }
        callback.invoke(null, devicesArray);
    }

在 React Native 中:

type Device = {
  name: string | null;
  address: string;
  bondState: number;
};

const [devices, setDevices] = useState<Device[]>([]);

const startDiscovery = () => {
    BluetoothScannerModule.scanDevices((error: string | null, result: string) => {
    if (error) {
      console.log(error);
    } else {
      console.log(result);
    }
  });
};

const cancelDiscovery = () => {
  BluetoothScannerModule.stopScan((error: string | null, result: Device[]) => {
    if (error) {
      console.log(error);
    } else {
      setDevices(result);
    }
  });
};

const renderDevice = ({ item }: { item: Device }) => (
  <View>
    <Text>{item.name ?? 'Unnamed device'}</Text>
    <Text>{item.address}</Text>
    <Text>Bond state: {item.bondState}</Text>
  </View>
);

...

<Button
   title='Start Scan'
   color="#841584"
   accessibilityLabel="Learn more about this purple button"
   onPress={startDiscovery}
/>
<Button
   title='Stop Scan'
   color="#841584"
   accessibilityLabel="Learn more about this purple button"
   onPress={cancelDiscovery}
/>
<FlatList data={devices} renderItem={renderDevice} />

安卓清单

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
android react-native android-bluetooth
2个回答
0
投票

Android 文档 说发现过程通常需要 12 秒。但是你在 5 秒后调用

cancelDiscovery
。所以这行不通。

此外,当您在这 5 秒中调用

Thread.sleep(5000)
时,无法调用
onReceive
BroadcastReceiver
。因为
onReceive
运行在主线程上。你必须删除
Thread.sleep(5000)
.

您可能还需要先决条件

ACCESS_FINE_LOCATION
BLUETOOTH_ADMIN
。你也可能需要设置
usesPermissionFlags="neverForLocation"
。请阅读链接中的文档。


0
投票

您是否在清单文件中启用/添加了 android 权限?请求授予许可并在清单文件中声明该许可都很重要。 BLUETOOTH_SCANBLUETOOTH_ADMIN 等权限和 ACCESS_FINE_LOCATION 等位置权限,位置权限对于发现附近的设备很重要。此外,在开始扫描之前还应启用手机的位置和蓝牙。如果你想连接到一个设备,那么你还需要BLUETOOTH_CONNECTBLUETOOTH_ADVERTISE

我建议在按下按钮时停止扫描,因为在大多数应用程序中,您想要扫描设备直到连接到一个设备。并扫描一段时间,例如 10 到 15 秒。

尝试将这些权限放在您的 AndroidManifest.xml 文件中,放在包名称所在行之后的顶部。并保留代码,否则它将无法工作。

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.BLUETOOTH"  />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

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

© www.soinside.com 2019 - 2024. All rights reserved.