Android13-蓝牙-常见问题

Android 13 蓝牙常见问题及解决方案

1. 权限问题

问题1:BLUETOOTH_SCAN/BLUETOOTH_CONNECT 权限缺失

java 复制代码
// 错误日志
E/BluetoothAdapter: Permission denial: Need BLUETOOTH_SCAN permission
E/BluetoothLeScanner: Need BLUETOOTH_SCAN permission to start scan

// 解决方案
// AndroidManifest.xml
<manifest>
    <!-- Android 12L (API 32) 及以下 -->
    <uses-permission android:name="android.permission.BLUETOOTH"
                     android:maxSdkVersion="31" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
                     android:maxSdkVersion="31" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="31" />
    
    <!-- Android 13 (API 33) 及以上 -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    
    <!-- 如果扫描需要位置信息 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     android:maxSdkVersion="32" />
</manifest>

// 运行时权限请求
private void requestBluetoothPermissions() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        String[] permissions;
        
        if (needsBackgroundLocation) {
            permissions = new String[]{
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.ACCESS_FINE_LOCATION
            };
        } else {
            permissions = new String[]{
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT
            };
        }
        
        ActivityCompat.requestPermissions(
            this,
            permissions,
            REQUEST_BLUETOOTH_PERMISSIONS
        );
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // Android 6-11 需要位置权限
        ActivityCompat.requestPermissions(
            this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
            REQUEST_LOCATION_PERMISSION
        );
    }
}

问题2:NEARBY_WIFI_DEVICES 权限

java 复制代码
// Android 13 新增的附近设备权限
// AndroidManifest.xml
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                 android:usesPermissionFlags="neverForLocation" />

// 运行时请求(可选)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    if (ContextCompat.checkSelfPermission(this, 
            Manifest.permission.NEARBY_WIFI_DEVICES) 
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(
            this,
            new String[]{Manifest.permission.NEARBY_WIFI_DEVICES},
            REQUEST_NEARBY_DEVICES_PERMISSION
        );
    }
}

2. 扫描问题

问题3:后台扫描被限制

java 复制代码
// 错误:后台扫描返回空结果或停止工作
// 解决方案:使用前台服务或特权扫描
public class BluetoothForegroundService extends Service {
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "BluetoothScanChannel";
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForeground(NOTIFICATION_ID, createNotification());
        startBluetoothScan();
        return START_STICKY;
    }
    
    private Notification createNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID,
                "Bluetooth Scanning",
                NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
        
        return new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("蓝牙扫描中")
            .setContentText("正在扫描附近的蓝牙设备...")
            .setSmallIcon(R.drawable.ic_bluetooth)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .build();
    }
    
    private void startBluetoothScan() {
        BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter()
            .getBluetoothLeScanner();
        
        ScanSettings settings = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
            // Android 13: 设置回调类型以避免被限制
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            // 使用 startScanForIntent 获得更长的扫描时间
            .build();
        
        // 使用特权扫描API(如果可用)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            PendingIntent pendingIntent = createScanPendingIntent();
            scanner.startScanForIntent(pendingIntent, settings, new ArrayList<>());
        } else {
            scanner.startScan(new ArrayList<>(), settings, scanCallback);
        }
    }
}

问题4:扫描过滤器不工作

java 复制代码
// 解决方案:正确配置扫描过滤器
private List<ScanFilter> createEffectiveScanFilters() {
    List<ScanFilter> filters = new ArrayList<>();
    
    // 1. 服务UUID过滤(最有效)
    ParcelUuid serviceUuid = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
    filters.add(new ScanFilter.Builder()
        .setServiceUuid(serviceUuid)
        .build());
    
    // 2. 设备名称过滤(部分设备可能不广播名称)
    filters.add(new ScanFilter.Builder()
        .setDeviceName("MyDevice")
        .build());
    
    // 3. 制造商数据过滤
    byte[] manufacturerData = {0x01, 0x02, 0x03};
    byte[] manufacturerDataMask = {0xFF, 0xFF, 0xFF};
    filters.add(new ScanFilter.Builder()
        .setManufacturerData(0x004C, manufacturerData, manufacturerDataMask)
        .build());
    
    // 4. 服务数据过滤
    ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
    byte[] serviceData = {0x01, 0x02};
    byte[] serviceDataMask = {0xFF, 0xFF};
    filters.add(new ScanFilter.Builder()
        .setServiceData(serviceDataUuid, serviceData, serviceDataMask)
        .build());
    
    return filters;
}

3. 连接和配对问题

问题5:连接失败或随机断开

java 复制代码
// 解决方案:增强的连接管理
public class RobustBluetoothConnector {
    private static final int MAX_RETRY_COUNT = 3;
    private static final long RETRY_DELAY_MS = 1000;
    
    public void connectWithRetry(BluetoothDevice device, Context context) {
        int retryCount = 0;
        
        while (retryCount < MAX_RETRY_COUNT) {
            try {
                if (connectDevice(device, context)) {
                    return; // 连接成功
                }
            } catch (SecurityException e) {
                // Android 13 权限问题
                Log.e(TAG, "Security exception: " + e.getMessage());
                handleSecurityException(context);
                break;
            } catch (IOException e) {
                Log.e(TAG, "Connection failed: " + e.getMessage());
                retryCount++;
                
                if (retryCount < MAX_RETRY_COUNT) {
                    try {
                        Thread.sleep(RETRY_DELAY_MS);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        
        Log.e(TAG, "Failed to connect after " + MAX_RETRY_COUNT + " attempts");
    }
    
    private boolean connectDevice(BluetoothDevice device, Context context) 
            throws IOException {
        
        // Android 13: 检查连接权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ContextCompat.checkSelfPermission(context, 
                    Manifest.permission.BLUETOOTH_CONNECT) 
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("BLUETOOTH_CONNECT permission required");
            }
        }
        
        // 使用不同的传输方式尝试连接
        BluetoothGatt gatt;
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 使用低功耗传输
            gatt = device.connectGatt(context, false, gattCallback, 
                    BluetoothDevice.TRANSPORT_LE);
        } else {
            gatt = device.connectGatt(context, false, gattCallback);
        }
        
        return gatt != null;
    }
    
    // 连接状态监控
    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Log.i(TAG, "Connected to GATT server");
                
                // Android 13: 立即发现服务
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    // 设置连接优先级
                    gatt.requestConnectionPriority(
                        BluetoothGatt.CONNECTION_PRIORITY_HIGH);
                }
                
                gatt.discoverServices();
                
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.w(TAG, "Disconnected from GATT server");
                
                // 自动重连逻辑
                scheduleReconnection(gatt.getDevice());
            }
        }
        
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.i(TAG, "Services discovered successfully");
                
                // 设置特征通知
                enableCharacteristicNotifications(gatt);
            }
        }
    };
}

问题6:配对请求不弹出

java 复制代码
// 解决方案:使用新的配对API
public class BondingManager {
    
    public void bondDevice(BluetoothDevice device, Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // Android 13 新的配对方法
            bondWithNewApi(device, context);
        } else {
            // 传统配对方法
            bondWithLegacyApi(device);
        }
    }
    
    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
    private void bondWithNewApi(BluetoothDevice device, Context context) {
        // 检查权限
        if (ContextCompat.checkSelfPermission(context, 
                Manifest.permission.BLUETOOTH_CONNECT) 
                != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "BLUETOOTH_CONNECT permission required");
            return;
        }
        
        // 使用CompanionDeviceManager进行配对
        CompanionDeviceManager cdm = context.getSystemService(
            CompanionDeviceManager.class);
        
        if (cdm != null) {
            // 创建配对请求
            AssociationRequest request = new AssociationRequest.Builder()
                .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
                .setSingleDevice(false)
                .build();
            
            // 启动配对
            cdm.associate(request, 
                new CompanionDeviceManager.Callback() {
                    @Override
                    public void onDeviceFound(IntentSender chooserLauncher) {
                        try {
                            context.startIntentSender(chooserLauncher, 
                                null, 0, 0, 0);
                        } catch (IntentSender.SendIntentException e) {
                            Log.e(TAG, "Failed to send intent", e);
                        }
                    }
                    
                    @Override
                    public void onFailure(CharSequence error) {
                        Log.e(TAG, "Pairing failed: " + error);
                    }
                }, 
                null);
        } else {
            // 回退到传统方法
            bondWithLegacyApi(device);
        }
    }
    
    private void bondWithLegacyApi(BluetoothDevice device) {
        try {
            // 使用反射调用createBond方法(兼容旧版本)
            Method method = device.getClass().getMethod("createBond");
            method.invoke(device);
        } catch (Exception e) {
            Log.e(TAG, "Failed to create bond", e);
        }
    }
    
    // 配对状态广播接收器
    private final BroadcastReceiver pairingReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            
            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(
                    BluetoothDevice.EXTRA_DEVICE);
                int bondState = intent.getIntExtra(
                    BluetoothDevice.EXTRA_BOND_STATE, 
                    BluetoothDevice.BOND_NONE);
                int previousBondState = intent.getIntExtra(
                    BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, 
                    BluetoothDevice.BOND_NONE);
                
                handleBondStateChange(device, bondState, previousBondState);
            }
        }
    };
}

4. GATT 操作问题

问题7:特征读写失败

java 复制代码
// 解决方案:增强的GATT操作管理
public class GattOperationManager {
    private static final int OPERATION_TIMEOUT_MS = 10000;
    private static final int MAX_RETRIES = 3;
    
    private final Map<Integer, GattOperation> pendingOperations = 
        new ConcurrentHashMap<>();
    private final Handler handler = new Handler(Looper.getMainLooper());
    
    public void writeCharacteristicWithRetry(BluetoothGatt gatt,
                                           BluetoothGattCharacteristic characteristic,
                                           byte[] value) {
        GattOperation operation = new GattOperation(
            GattOperation.Type.WRITE_CHARACTERISTIC,
            characteristic,
            value);
        
        executeOperationWithRetry(gatt, operation);
    }
    
    private void executeOperationWithRetry(BluetoothGatt gatt, 
                                          GattOperation operation) {
        int retryCount = 0;
        
        while (retryCount < MAX_RETRIES) {
            try {
                if (executeOperation(gatt, operation)) {
                    return; // 操作成功
                }
            } catch (Exception e) {
                Log.w(TAG, "Operation failed, retrying...", e);
                retryCount++;
                
                if (retryCount < MAX_RETRIES) {
                    try {
                        Thread.sleep(1000); // 等待1秒后重试
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        
        Log.e(TAG, "Operation failed after " + MAX_RETRIES + " retries");
    }
    
    private boolean executeOperation(BluetoothGatt gatt, 
                                    GattOperation operation) {
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicBoolean success = new AtomicBoolean(false);
        
        // 设置回调
        BluetoothGattCallback callback = new BluetoothGattCallback() {
            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic,
                                            int status) {
                if (characteristic.getUuid().equals(
                    operation.characteristic.getUuid())) {
                    success.set(status == BluetoothGatt.GATT_SUCCESS);
                    latch.countDown();
                }
            }
        };
        
        // 注册临时回调
        registerTemporaryCallback(gatt, callback);
        
        // 执行操作
        boolean initiated = false;
        switch (operation.type) {
            case WRITE_CHARACTERISTIC:
                operation.characteristic.setValue(operation.value);
                initiated = gatt.writeCharacteristic(operation.characteristic);
                break;
            case READ_CHARACTERISTIC:
                initiated = gatt.readCharacteristic(operation.characteristic);
                break;
        }
        
        if (!initiated) {
            Log.e(TAG, "Failed to initiate operation");
            return false;
        }
        
        // 等待操作完成
        try {
            boolean notTimeout = latch.await(OPERATION_TIMEOUT_MS, 
                TimeUnit.MILLISECONDS);
            
            if (!notTimeout) {
                Log.w(TAG, "Operation timeout");
                return false;
            }
            
            return success.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
}

问题8:MTU 协商失败

java 复制代码
// 解决方案:MTU协商增强
public class MtuNegotiator {
    private static final int DEFAULT_MTU = 23;
    private static final int MAX_MTU = 512;
    private static final int MTU_REQUEST_TIMEOUT_MS = 5000;
    
    public void negotiateMtu(BluetoothGatt gatt) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            requestMtuWithRetry(gatt, MAX_MTU);
        }
    }
    
    private void requestMtuWithRetry(BluetoothGatt gatt, int mtu) {
        final CountDownLatch latch = new CountDownLatch(1);
        final AtomicInteger negotiatedMtu = new AtomicInteger(DEFAULT_MTU);
        
        BluetoothGattCallback mtuCallback = new BluetoothGattCallback() {
            @Override
            public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    negotiatedMtu.set(mtu);
                    Log.i(TAG, "MTU negotiated: " + mtu);
                } else {
                    Log.w(TAG, "MTU negotiation failed: " + status);
                }
                latch.countDown();
            }
        };
        
        // 注册回调
        registerTemporaryCallback(gatt, mtuCallback);
        
        // 请求MTU
        boolean requested = gatt.requestMtu(mtu);
        if (!requested) {
            Log.e(TAG, "Failed to request MTU");
            return;
        }
        
        // 等待MTU协商完成
        try {
            boolean notTimeout = latch.await(MTU_REQUEST_TIMEOUT_MS, 
                TimeUnit.MILLISECONDS);
            
            if (!notTimeout) {
                Log.w(TAG, "MTU negotiation timeout");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 如果MTU协商失败,尝试较小的值
        if (negotiatedMtu.get() == DEFAULT_MTU && mtu > 100) {
            Log.i(TAG, "Retrying with smaller MTU: " + (mtu / 2));
            requestMtuWithRetry(gatt, mtu / 2);
        }
    }
}

5. 后台限制问题

问题9:后台服务被杀死

java 复制代码
// 解决方案:使用JobScheduler或WorkManager
public class BluetoothBackgroundWorker {
    
    public static void schedulePeriodicScan(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
            
            ComponentName serviceComponent = new ComponentName(
                context, BluetoothScanJobService.class);
            
            JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent);
            
            // 设置触发条件
            builder.setPeriodic(15 * 60 * 1000); // 每15分钟
            builder.setPersisted(true); // 重启后保持
            
            // Android 13: 设置必要的网络类型
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
            }
            
            // 设置电池不敏感
            builder.setRequiresBatteryNotLow(false);
            builder.setRequiresCharging(false);
            
            int result = jobScheduler.schedule(builder.build());
            
            if (result == JobScheduler.RESULT_SUCCESS) {
                Log.i(TAG, "Job scheduled successfully");
            } else {
                Log.e(TAG, "Job scheduling failed");
            }
        } else {
            // 使用AlarmManager兼容旧版本
            scheduleWithAlarmManager(context);
        }
    }
    
    // 使用WorkManager的替代方案
    public static void scheduleWithWorkManager(Context context) {
        Constraints constraints = new Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresBatteryNotLow(false)
            .build();
        
        PeriodicWorkRequest scanWork = new PeriodicWorkRequest.Builder(
            BluetoothScanWorker.class,
            15, TimeUnit.MINUTES)  // 每15分钟
            .setConstraints(constraints)
            .setBackoffCriteria(
                BackoffPolicy.LINEAR,
                PeriodicWorkRequest.MIN_BACKOFF_MILLIS,
                TimeUnit.MILLISECONDS)
            .build();
        
        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "bluetooth_scan",
            ExistingPeriodicWorkPolicy.KEEP,
            scanWork);
    }
}

6. 特定设备兼容性问题

问题10:与特定设备连接失败

cpp 复制代码
// Native层解决方案:设备特定兼容性处理
// system/bt/btif/src/btif_dm.cc
void handle_device_specific_quirks(const RawAddress& bd_addr) {
    std::string address_str = bd_addr.ToString();
    
    // 检查设备特定问题
    if (is_samsung_device(address_str)) {
        // 三星设备特定修复
        apply_samsung_quirks(bd_addr);
    } else if (is_xiaomi_device(address_str)) {
        // 小米设备特定修复
        apply_xiaomi_quirks(bd_addr);
    } else if (is_apple_device(address_str)) {
        // Apple设备特定修复
        apply_apple_quirks(bd_addr);
    }
    
    // Android 13: 应用通用兼容性修复
    if (is_android_t_or_above()) {
        apply_android13_compatibility_fixes(bd_addr);
    }
}

// 应用设备特定修复
static void apply_samsung_quirks(const RawAddress& bd_addr) {
    // 1. 调整连接参数
    BTM_SetDefaultLinkSupervisionTimeout(bd_addr, 8000); // 8秒超时
    
    // 2. 禁用某些功能
    uint16_t link_policy = BTM_DEFAULT_LINK_POLICY;
    link_policy &= ~BTM_LINK_POLICY_ENABLE_SNIFF_MODE; // 禁用嗅探模式
    BTM_SetLinkPolicy(bd_addr, &link_policy);
    
    // 3. 调整配对参数
    tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
    if (p_dev_rec) {
        p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
        p_dev_rec->pairable_mode = BTM_PAIRABLE_MODE_ON;
    }
}

// 应用Android 13通用修复
static void apply_android13_compatibility_fixes(const RawAddress& bd_addr) {
    // 1. 强制使用安全连接
    if (controller_get_interface()->supports_secure_connections()) {
        tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
        if (p_dev_rec) {
            p_dev_rec->secure_connections_only = true;
        }
    }
    
    // 2. 调整扫描参数
    BTM_BleSetScanParams(
        BTM_BLE_SCAN_MODE_LOW_LATENCY,
        50,   // scan_interval
        50,   // scan_window
        BTM_BLE_SCAN_PHY_1M,
        BTM_BLE_SCAN_TYPE_ACTIVE);
    
    // 3. 设置隐私模式
    BTM_BleSetPrivacyMode(bd_addr, BTM_PRIVACY_MODE_DEVICE);
}

7. 调试和日志收集

问题11:调试信息不足

bash 复制代码
# ADB 调试命令
# 启用蓝牙详细日志
adb shell setprop persist.bluetooth.btsnoopenable true
adb shell setprop persist.bluetooth.btsnooppath /sdcard/btsnoop_hci.log
adb shell setprop persist.bluetooth.btsnoopsize 0xffffffff

# 启用蓝牙HCI日志
adb shell setprop persist.bluetooth.btsnooplogmode full
adb shell setprop log.tag.Bluetooth VERBOSE
adb shell setprop log.tag.BluetoothHci VERBOSE

# 获取蓝牙状态
adb shell dumpsys bluetooth_manager
adb shell dumpsys bluetooth_manager --proto | protoc --decode_raw

# 获取配对设备列表
adb shell cmd bluetooth_manager getBondedDevices

# 启用蓝牙协议栈跟踪
adb shell setprop debug.bluetooth.trace_level 5
adb shell setprop debug.bluetooth.gatt.trace_level 5
adb shell setprop debug.bluetooth.btif.trace_level 5

# Android 13 新增调试命令
adb shell cmd bluetooth_manager setLogLevel verbose
adb shell cmd bluetooth_manager enableCrashLogging
adb shell cmd bluetooth_manager enableMetricsLogging

问题12:崩溃和ANR分析

java 复制代码
// 添加异常处理
public class BluetoothCrashHandler implements Thread.UncaughtExceptionHandler {
    private final Thread.UncaughtExceptionHandler defaultHandler;
    
    public BluetoothCrashHandler() {
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    }
    
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        // 记录蓝牙相关崩溃
        if (isBluetoothRelatedCrash(throwable)) {
            logBluetoothCrash(throwable);
            collectBluetoothDebugInfo();
        }
        
        // 调用默认处理器
        if (defaultHandler != null) {
            defaultHandler.uncaughtException(thread, throwable);
        }
    }
    
    private boolean isBluetoothRelatedCrash(Throwable throwable) {
        StackTraceElement[] stackTrace = throwable.getStackTrace();
        
        for (StackTraceElement element : stackTrace) {
            String className = element.getClassName();
            if (className.contains("bluetooth") || 
                className.contains("Bluetooth") ||
                className.contains("Gatt") ||
                className.contains("Scan")) {
                return true;
            }
        }
        
        return false;
    }
    
    private void collectBluetoothDebugInfo() {
        try {
            // 收集蓝牙状态
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            if (adapter != null) {
                Log.e("BluetoothDebug", "State: " + adapter.getState());
                Log.e("BluetoothDebug", "Address: " + adapter.getAddress());
                Log.e("BluetoothDebug", "Name: " + adapter.getName());
            }
            
            // 收集连接状态
            BluetoothManager bluetoothManager = 
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
            List<BluetoothDevice> connectedDevices = 
                bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
            
            for (BluetoothDevice device : connectedDevices) {
                Log.e("BluetoothDebug", "Connected: " + device.getAddress());
            }
            
        } catch (Exception e) {
            Log.e("BluetoothDebug", "Failed to collect debug info", e);
        }
    }
}

8. 最佳实践总结

  1. 权限处理

    • 始终检查 BLUETOOTH_SCANBLUETOOTH_CONNECT 权限
    • 使用 NEARBY_WIFI_DEVICES 替代位置权限
    • 正确处理后台权限
  2. 连接管理

    • 实现重试机制
    • 监控连接状态变化
    • 处理后台连接限制
  3. 扫描优化

    • 使用 startScanForIntent 进行长时间扫描
    • 合理配置扫描参数
    • 处理后台扫描限制
  4. 兼容性

    • 处理不同 Android 版本的差异
    • 适配不同厂商设备的特性
    • 测试各种蓝牙版本和配置文件
  5. 错误处理

    • 实现全面的异常处理
    • 收集详细的调试信息
    • 提供用户友好的错误提示

这些解决方案可以帮助解决 Android 13 中常见的蓝牙问题,并确保应用在不同设备和系统版本上的兼容性。

相关推荐
2501_944424123 小时前
Flutter for OpenHarmony游戏集合App实战之连连看路径连线
android·开发语言·前端·javascript·flutter·游戏·php
2501_9444241211 小时前
Flutter for OpenHarmony游戏集合App实战之贪吃蛇食物生成
android·开发语言·flutter·游戏·harmonyos
2501_9371454114 小时前
神马影视8.8版2026最新版:核心技术升级与多场景适配解析
android·源码·电视盒子·源代码管理
2501_9444241215 小时前
Flutter for OpenHarmony游戏集合App实战之俄罗斯方块七种形状
android·开发语言·flutter·游戏·harmonyos
不会Android的潘潘17 小时前
受限系统环境下的 WebView 能力演进:车载平台 Web 渲染异常的根因分析与优化实践
android·java·前端·aosp
建军啊17 小时前
java web常见lou洞
android·java·前端
豆奶dudu17 小时前
安卓应用签名生成+微信开放平台安卓应用签名
android·微信开放平台
AC赳赳老秦19 小时前
Dify工作流+DeepSeek:运维自动化闭环(数据采集→报告生成)
android·大数据·运维·数据库·人工智能·golang·deepseek
2501_9444241219 小时前
Flutter for OpenHarmony游戏集合App实战之记忆翻牌配对消除
android·java·开发语言·javascript·windows·flutter·游戏