You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Codename One Bluetooth扩展扫描异常及权限方法缺失求助

Codename One蓝牙扫描失败问题解决(Android+iOS适配)

一、核心问题分析

  • 权限配置遗漏:Android API 31+需要单独的BLUETOOTH_SCAN权限,现有代码未正确处理
  • 代码错误:存在重复的actionPerformed方法,回调中evt1.getSource()类型转换逻辑错误
  • iOS适配缺失:未添加蓝牙权限描述,且iOS系统限制MAC地址获取

二、Android权限配置修正

1. 配置文件添加权限

在codenameone_settings.properties中添加Android权限声明:

# Android 12+蓝牙扫描权限
android.xpermissions=<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
# 如果扫描需要基于位置(比如发现非广播设备),补充定位权限
android.xpermissions=<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2. 代码中动态检查权限

由于找不到文档提及的hasPermissionBtScan方法,直接使用Codename One通用权限API处理:

// 仅针对Android 12+检查扫描权限
if (Display.getInstance().getPlatformName().equals("Android") && Display.getInstance().getOSVersion() >= 31) {
    String scanPermission = "android.permission.BLUETOOTH_SCAN";
    if (!Permissions.isPermissionGranted(scanPermission)) {
        Permissions.requestPermissions(permissionEvent -> {
            if (permissionEvent.isGranted()) {
                startBTScan(); // 权限通过后启动扫描
            } else {
                updateAction("扫描权限被拒绝,无法继续");
            }
        }, scanPermission);
        return;
    }
}

三、代码错误修复

1. 删除重复代码

你的代码中重复实现了actionPerformed方法,需删除冗余部分,保证逻辑唯一。

2. 修正回调数据获取

startScan回调的ActionEvent.getSource()实际返回的是BluetoothScanResult对象,而非JSONObject,调整代码如下:

private void startBTScan() {
    updateAction("启动扫描...");
    try {
        bt.startScan(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt1) {
                try {
                    BluetoothScanResult result = (BluetoothScanResult) evt1.getSource();
                    String deviceAddress = result.getAddress();
                    String[] deviceUUIDs = result.getUUIDs();

                    // 更新UI显示设备信息
                    updateAction("发现设备:" + result.getName() + " | 地址:" + deviceAddress);
                    
                    // 存储新设备
                    if (!devices.containsKey(deviceAddress)) {
                        devices.put(deviceAddress, result);
                        updateAction("已发现设备总数:" + devices.size());
                        updateUI();
                    }

                    // 处理UUID(如果设备广播了UUID)
                    if (deviceUUIDs != null && deviceUUIDs.length > 0) {
                        for (String uuid : deviceUUIDs) {
                            updateAction("设备UUID:" + uuid);
                        }
                    }
                } catch (Exception ex) {
                    Log.e(ex);
                    updateAction("扫描回调错误:" + ex.getMessage());
                }
            }
        }, null, true, Bluetooth.SCAN_MODE_LOW_POWER, Bluetooth.MATCH_MODE_STICKY,
                Bluetooth.MATCH_NUM_MAX_ADVERTISEMENT, Bluetooth.CALLBACK_TYPE_ALL_MATCHES);
    } catch (IOException ex) {
        Log.e(ex);
        updateAction("启动扫描失败:" + ex.getMessage());
    }
}

四、iOS适配注意事项

1. 添加权限描述

在codenameone_settings.properties中注入iOS权限说明:

ios.plistInject=<key>NSBluetoothAlwaysUsageDescription</key><string>需要蓝牙权限扫描和连接设备</string>
ios.plistInject=<key>NSBluetoothPeripheralUsageDescription</key><string>需要蓝牙权限与周边设备通信</string>

2. MAC地址兼容性

iOS 10及以上版本禁止直接获取MAC地址,建议使用设备UUID或名称作为标识,代码中不要依赖result.getAddress()返回的MAC值(iOS上该值会是固定占位符)。

五、完整修正后的代码片段

hi.add(new Button(new Command("start scan") {
    @Override
    public void actionPerformed(ActionEvent evt) {
        updateAction("准备启动扫描");
        try {
            updateAction("蓝牙权限状态:" + bt.hasPermission());
            updateAction("定位服务状态:" + bt.isLocationEnabled());
        } catch (IOException e) {
            Log.e(e);
            updateAction("权限检查失败:" + e.getMessage());
            return;
        }

        // Android 12+扫描权限检查
        if (Display.getInstance().getPlatformName().equals("Android") && Display.getInstance().getOSVersion() >= 31) {
            String scanPermission = "android.permission.BLUETOOTH_SCAN";
            if (!Permissions.isPermissionGranted(scanPermission)) {
                Permissions.requestPermissions(permissionEvent -> {
                    if (permissionEvent.isGranted()) {
                        startBTScan();
                    } else {
                        updateAction("扫描权限被拒绝,无法继续");
                    }
                }, scanPermission);
                return;
            }
        }

        // 启动扫描
        startBTScan();
    }

    private void startBTScan() {
        updateAction("启动扫描...");
        try {
            bt.startScan(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt1) {
                    try {
                        BluetoothScanResult result = (BluetoothScanResult) evt1.getSource();
                        String deviceAddress = result.getAddress();
                        String[] deviceUUIDs = result.getUUIDs();

                        updateAction("发现设备:" + result.getName() + " | 地址:" + deviceAddress);
                        
                        if (!devices.containsKey(deviceAddress)) {
                            devices.put(deviceAddress, result);
                            updateAction("已发现设备总数:" + devices.size());
                            updateUI();
                        }

                        if (deviceUUIDs != null && deviceUUIDs.length > 0) {
                            for (String uuid : deviceUUIDs) {
                                updateAction("设备UUID:" + uuid);
                            }
                        }
                    } catch (Exception ex) {
                        Log.e(ex);
                        updateAction("扫描回调错误:" + ex.getMessage());
                    }
                }
            }, null, true, Bluetooth.SCAN_MODE_LOW_POWER, Bluetooth.MATCH_MODE_STICKY,
                    Bluetooth.MATCH_NUM_MAX_ADVERTISEMENT, Bluetooth.CALLBACK_TYPE_ALL_MATCHES);
        } catch (IOException ex) {
            Log.e(ex);
            updateAction("启动扫描失败:" + ex.getMessage());
        }
    }
}));

内容的提问来源于stack exchange,提问作者Giovanbattista Di Nuzzo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 20:14:49