如何搜索Beacon?Android 7.0/6.0.1无法发现Beacon问题求助
兄弟,你这个问题我之前帮不少开发者排查过,核心原因基本是Android 6.0开始的动态权限机制、Beacon库版本兼容性,或者Fragment作为BeaconConsumer时的生命周期绑定时机不对。下面给你一步步拆解解决方案:
1. 先搞定动态权限(最关键!)
Android 6.0(API23)开始,BLE扫描必须要位置权限,而且得动态申请——哪怕你在Manifest里加了权限,系统也不会自动授权。
首先在AndroidManifest.xml里把必须的权限加全:
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 如果是Android 12+,还要加这三个权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
然后在你的Fragment里,必须在初始化BeaconManager之前申请位置权限:
private static final int PERMISSION_REQUEST_LOCATION = 1001; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 先检查权限 if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_LOCATION); } else { // 权限已授权,初始化BeaconManager setupBeaconManager(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_LOCATION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { setupBeaconManager(); } else { Toast.makeText(requireContext(), "不给位置权限的话,没法扫描Beacon哦", Toast.LENGTH_SHORT).show(); } } } private void setupBeaconManager() { beaconManager = BeaconManager.getInstanceForApplication(requireContext()); // 这里继续你的Beacon配置,比如添加BeaconParser beaconManager.bind(this); }
2. 调整BeaconManager的绑定/解绑时机
Fragment作为BeaconConsumer时,绑定时机不能太早(比如onCreateView里),最好在Fragment完全附着到Activity之后再绑定。另外,一定要在Fragment销毁时解绑,避免内存泄漏:
@Override public void onDestroy() { super.onDestroy(); if (beaconManager != null && beaconManager.isBound(this)) { beaconManager.unbind(this); } }
3. 升级Beacon库版本
你遇到的“could not find callback wrapper”错误,很大概率是旧版本的Beacon库(比如AltBeacon的Android-Beacon-Library)在Android 6.0+系统上的兼容性bug。赶紧把库升级到最新稳定版,比如在build.gradle(Module级别)里:
implementation 'org.altbeacon:android-beacon-library:2.21.4'
这个版本修复了大量高版本Android系统的兼容性问题,亲测有效。
4. 检查Beacon格式配置
虽然你在4.4.4上能正常运行,但还是确认下BeaconParser的格式是否正确,比如如果是iBeacon,要这样配置:
beaconManager.getBeaconParsers().add(new BeaconParser() .setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
如果是其他格式的Beacon,要对应修改Layout字符串。
5. 检查蓝牙状态
最后,别忘了在扫描前确认蓝牙是开启的,可以加个检查逻辑:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, 1002); }
按照上面的步骤走,应该能解决你在Android 6.0/7.0上的问题。核心就是权限要到位、库版本要新、生命周期绑定要正确。
内容的提问来源于stack exchange,提问作者Paulo Pérez

