Android 13下PairWiimote适配修复求助:Wiimote配对异常
修复PairWiimote在Android 13上的配对故障
问题核心分析
Android 13对蓝牙权限、后台蓝牙操作做了更严格的限制,同时蓝牙协议栈的行为变化导致原应用的Socket读取逻辑和配对后初始化流程失效,出现read failed, socket might closed or timeout, read ret: -1错误;Wiimote指示灯无限闪烁说明配对后未完成设备握手。
分步修复方案
1. 补充Android 13+蓝牙权限
Android 12及以上新增BLUETOOTH_CONNECT和BLUETOOTH_SCAN危险权限,必须在Manifest声明并运行时申请:
- 在
AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> - 在配对操作前添加权限请求逻辑:
private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1; private void checkBluetoothPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { String[] permissions = { Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }; if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, permissions[1]) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, REQUEST_BLUETOOTH_PERMISSIONS); } else { startPairing(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) { if (grantResults.length > 0 && allPermissionsGranted(grantResults)) { startPairing(); } else { Toast.makeText(this, "需要蓝牙权限才能完成配对", Toast.LENGTH_SHORT).show(); } } } private boolean allPermissionsGranted(int[] grantResults) { for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { return false; } } return true; }
2. 将蓝牙Socket操作移至前台服务
Android 13限制后台进程的蓝牙Socket连接,容易被系统回收导致读取失败。需要把配对后的Socket交互逻辑移到前台服务中:
- 创建前台服务类:
public class WiimotePairingService extends Service { private static final int NOTIFICATION_ID = 1001; private BluetoothSocket mSocket; private InputStream mInStream; private OutputStream mOutStream; private Thread mReadThread; @Override public int onStartCommand(Intent intent, int flags, int startId) { Notification notification = new NotificationCompat.Builder(this, "wiimote_pairing") .setContentTitle("Wiimote配对中") .setContentText("正在与Wiimote建立连接") .setSmallIcon(R.drawable.ic_launcher) .build(); startForeground(NOTIFICATION_ID, notification); BluetoothDevice device = intent.getParcelableExtra("bluetooth_device"); initSocket(device); return START_STICKY; } private void initSocket(BluetoothDevice device) { try { mSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); mSocket.connect(); mInStream = mSocket.getInputStream(); mOutStream = mSocket.getOutputStream(); mReadThread = new Thread(this::readSocketData); mReadThread.start(); sendInitCommands(); } catch (IOException e) { e.printStackTrace(); stopSelf(); } } private void readSocketData() { byte[] buffer = new byte[1024]; int bytes; while (!Thread.currentThread().isInterrupted() && mSocket.isConnected()) { try { bytes = mInStream.read(buffer); if (bytes > 0) { processReceivedData(buffer, bytes); } } catch (IOException e) { e.printStackTrace(); break; } } cleanup(); } private void sendInitCommands() throws IOException { mOutStream.write(new byte[]{0x52, 0x00, 0x01}); mOutStream.flush(); } private void processReceivedData(byte[] buffer, int length) { // 参考原应用逻辑处理Wiimote响应,判断是否完成初始化 } private void cleanup() { try { if (mInStream != null) mInStream.close(); if (mOutStream != null) mOutStream.close(); if (mSocket != null) mSocket.close(); } catch (IOException e) { e.printStackTrace(); } stopForeground(true); stopSelf(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } } - 在Manifest中注册服务:
<service android:name=".WiimotePairingService" android:foregroundServiceType="connectedDevice" /> - 启动服务替代原配对逻辑:
Intent serviceIntent = new Intent(this, WiimotePairingService.class); serviceIntent.putExtra("bluetooth_device", selectedDevice); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); }
3. 调整Wiimote初始化指令时序
Wiimote无限闪烁说明配对后未完成握手,Android 13蓝牙协议栈对指令时序要求更严格:
- 按规范顺序发送初始化指令:
- 发送
0x52 0x00 0x01设置报告模式(按键+加速度) - 发送
0x52 0x10 0x00读取Wiimote状态
- 发送
- 指令间增加100ms左右延迟,避免协议栈处理不及时导致指令丢失
4. 调试定位问题
- 使用Android Studio的Bluetooth Profiler捕获配对过程的蓝牙数据包,对比Android 10和13的交互差异,定位未响应的指令
- 在Socket操作节点添加日志:
Log.d("WiimotePair", "Socket connected: " + mSocket.isConnected()); Log.d("WiimotePair", "Received data length: " + bytes);
内容的提问来源于stack exchange,提问作者He_ Maxed
相关产品推荐
相关产品推荐

