首页 文章

在.connect()之后如何防止Android蓝牙RFCOMM连接立即死亡?

提问于
浏览
48

这个问题已经解决了!非常感谢布拉德,丹尼斯和瘾君子!你是英雄! :)

这是工作代码 . 它连接到Zeemote并从中读取数据 .

=====代码=====

public class ZeeTest extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        try {
            for (int i = 0; i < 3; i++) {
                test();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean connected = false;
    private BluetoothSocket sock;
    private InputStream in;
    public void test() throws Exception {
        if (connected) {
            return;
        }
        BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter().
            getRemoteDevice("00:1C:4D:02:A6:55");
        Method m = zee.getClass().getMethod("createRfcommSocket",
            new Class[] { int.class });
        sock = (BluetoothSocket)m.invoke(zee, Integer.valueOf(1));
        Log.d("ZeeTest", "++++ Connecting");
        sock.connect();
        Log.d("ZeeTest", "++++ Connected");
        in = sock.getInputStream();
        byte[] buffer = new byte[50];
        int read = 0;
        Log.d("ZeeTest", "++++ Listening...");
        try {
            while (true) {
                read = in.read(buffer);
                connected = true;
                StringBuilder buf = new StringBuilder();
                for (int i = 0; i < read; i++) {
                    int b = buffer[i] & 0xff;
                    if (b < 0x10) {
                        buf.append("0");
                    }
                    buf.append(Integer.toHexString(b)).append(" ");
                }
                Log.d("ZeeTest", "++++ Read "+ read +" bytes: "+ buf.toString());
            }
        } catch (IOException e) {}
        Log.d("ZeeTest", "++++ Done: test()");
    }
    @Override
    public void onDestroy() {
        try {
            if (in != null) {
                in.close();
            }
            if (sock != null) {
                sock.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}

=====原始问题=====

我正在尝试连接到运行2.0.1固件的Moto Droid的Zeemote(http://zeemote.com/)游戏控制器 . 下面的测试应用程序确实连接到设备(LED闪烁),但之后立即断开连接 .

我正在粘贴下面的两个测试应用程序:一个实际上尝试从输入流中读取,另一个只是坐在那里,等待设备在5秒后断开连接 . 是的,我确实有第三个版本:)首先等待ACL_CONNECTED,然后打开套接字,但它的行为没有什么新东西 .

一些背景信息:我可以使用bluez工具从我的笔记本电脑连接到Zeemote(也附带日志) . 我确信Droid能够与Zeemote交谈,因为市场上的'Game Pro'可以正常使用它(但是它是一个驱动程序/服务,所以它可能使用较低级别的API?) .

我注意到'adb bugreport'既没有报告Zeuote的UUID也没有报告RFCOMM Channels ,而是针对所有其他设备(包括Moto HS815耳机,其中'sdp浏览'没有报告任何内容的另一个哑设备) . 此外,当设备启动时,Zeemote的优先级为0(其他优先级为100) .

我'm quite at a loss here, I worked on it for so long that I ran out of ideas so any help would be very much appreciated (even if you don' t知道答案:))

谢谢,马克斯

测试申请号1

这个应用程序试图从设备实际读取 .

=====代码=====

public class ZeeTest extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        try {
            test();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private BluetoothSocket sock;
    private InputStream in;
    public void test() throws IOException {
        BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter().
                      getRemoteDevice("00:1C:4D:02:A6:55");
        sock = zee.createRfcommSocketToServiceRecord(
                      UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
        Log.d("ZeeTest", "++++ Connecting");
        sock.connect();
        Log.d("ZeeTest", "++++ Connected");
        in = sock.getInputStream();
        byte[] buffer = new byte[1];
        int bytes = 0;
        int x = 0;
        Log.d("ZeeTest", "++++ Listening...");
        while (x < 2) {
            x++;
            try {
                bytes = in.read(buffer);
                Log.d("ZeeTest", "++++ Read "+ bytes +" bytes");
            } catch (IOException e) {
                e.printStackTrace();
                try { Thread.sleep(100); } catch (InterruptedException ie) {}
            }
        }
        Log.d("ZeeTest", "++++ Done: test()");
    }
    @Override
    public void onDestroy() {
        try {
            if (in != null) {
                in.close();
            }
            if (sock != null) {
                sock.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}

=====日志=====

04-19 22:27:01.147: DEBUG/ZeeTest(8619): ++++ Connecting
04-19 22:27:04.085: INFO/usbd(1062): process_usb_uevent_message(): buffer = add@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:27:04.085: INFO/usbd(1062): main(): call select(...)
04-19 22:27:04.327: ERROR/BluetoothEventLoop.cpp(4029): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:27:04.491: VERBOSE/BluetoothEventRedirector(7499): Received android.bleutooth.device.action.UUID
04-19 22:27:04.905: DEBUG/ZeeTest(8619): ++++ Connected
04-19 22:27:04.905: DEBUG/ZeeTest(8619): ++++ Listening...
04-19 22:27:05.538: WARN/System.err(8619): java.io.IOException: Software caused connection abort
04-19 22:27:05.600: WARN/System.err(8619):     at android.bluetooth.BluetoothSocket.readNative(Native Method)
...
04-19 22:27:05.717: WARN/System.err(8619): java.io.IOException: Software caused connection abort
04-19 22:27:05.717: WARN/System.err(8619):     at android.bluetooth.BluetoothSocket.readNative(Native Method)
...
04-19 22:27:05.819: DEBUG/ZeeTest(8619): ++++ Done: test()
04-19 22:27:07.155: VERBOSE/BluetoothEventRedirector(7499): Received android.bleutooth.device.action.UUID
04-19 22:27:09.077: INFO/usbd(1062): process_usb_uevent_message(): buffer = remove@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:27:09.085: INFO/usbd(1062): main(): call select(...)
04-19 22:27:09.139: ERROR/BluetoothEventLoop.cpp(4029): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55

第2号试验申请

此测试连接并等待 - 对显示自动断开问题很有用 .

=====代码=====

public class ZeeTest extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        getApplicationContext().registerReceiver(receiver,
                    new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
        getApplicationContext().registerReceiver(receiver,
                    new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
        try {
            BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter().
                            getRemoteDevice("00:1C:4D:02:A6:55");
            sock = zee.createRfcommSocketToServiceRecord(
                            UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));

            Log.d("ZeeTest", "++++ Connecting");
            sock.connect();
            Log.d("ZeeTest", "++++ Connected");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static final LogBroadcastReceiver receiver = new LogBroadcastReceiver();
    public static class LogBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("ZeeReceiver", intent.toString());
            Bundle extras = intent.getExtras();
            for (String k : extras.keySet()) {
                Log.d("ZeeReceiver", "    Extra: "+ extras.get(k).toString());
            }
        }
    }

    private BluetoothSocket sock;
    @Override
    public void onDestroy() {
        getApplicationContext().unregisterReceiver(receiver);
        if (sock != null) {
            try {
                sock.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }
}

=====日志=====

04-19 22:06:34.944: DEBUG/ZeeTest(7986): ++++ Connecting
04-19 22:06:38.202: INFO/usbd(1062): process_usb_uevent_message(): buffer = add@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:06:38.202: INFO/usbd(1062): main(): call select(...)
04-19 22:06:38.217: ERROR/BluetoothEventLoop.cpp(4029): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:06:38.428: VERBOSE/BluetoothEventRedirector(7499): Received android.bleutooth.device.action.UUID
04-19 22:06:38.968: DEBUG/ZeeTest(7986): ++++ Connected
04-19 22:06:39.061: DEBUG/ZeeReceiver(7986): Intent { act=android.bluetooth.device.action.ACL_CONNECTED (has extras) }
04-19 22:06:39.108: DEBUG/ZeeReceiver(7986):     Extra: 00:1C:4D:02:A6:55
04-19 22:06:39.538: INFO/ActivityManager(4029): Displayed activity zee.test/.ZeeTest: 5178 ms (total 5178 ms)
04-19 22:06:41.014: VERBOSE/BluetoothEventRedirector(7499): Received android.bleutooth.device.action.UUID
04-19 22:06:43.038: INFO/usbd(1062): process_usb_uevent_message(): buffer = remove@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:06:43.038: INFO/usbd(1062): main(): call select(...)
04-19 22:06:43.069: ERROR/BluetoothEventLoop.cpp(4029): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:06:43.124: DEBUG/ZeeReceiver(7986): Intent { act=android.bluetooth.device.action.ACL_DISCONNECTED (has extras) }
04-19 22:06:43.124: DEBUG/ZeeReceiver(7986):     Extra: 00:1C:4D:02:A6:55

系统日志

=====终端日志=====

$ sdptool browse
Inquiring ...
Browsing 00:1C:4D:02:A6:55 ...

$ sdptool records 00:1C:4D:02:A6:55
Service Name: Zeemote
Service RecHandle: 0x10015
Service Class ID List:
  UUID 128: 8e1f0cf7-508f-4875-b62c-fbb67fd34812
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100

$ rfcomm connect /dev/tty10 00:1C:4D:02:A6:55
Connected /dev/rfcomm0 to 00:1C:4D:02:A6:55 on channel 1
Press CTRL-C for hangup

# rfcomm show /dev/tty10
rfcomm0: 00:1F:3A:E4:C8:40 -> 00:1C:4D:02:A6:55 channel 1 connected [reuse-dlc release-on-hup tty-attached]

# cat /dev/tty10
(nothing here)

# hcidump
HCI sniffer - Bluetooth packet analyzer ver 1.42
device: hci0 snap_len: 1028 filter: 0xffffffff
< HCI Command: Create Connection (0x01|0x0005) plen 13
> HCI Event: Command Status (0x0f) plen 4
> HCI Event: Connect Complete (0x03) plen 11
< HCI Command: Read Remote Supported Features (0x01|0x001b) plen 2
> HCI Event: Read Remote Supported Features (0x0b) plen 11
< ACL data: handle 11 flags 0x02 dlen 10
    L2CAP(s): Info req: type 2
> HCI Event: Command Status (0x0f) plen 4
> HCI Event: Page Scan Repetition Mode Change (0x20) plen 7
> HCI Event: Max Slots Change (0x1b) plen 3
< HCI Command: Remote Name Request (0x01|0x0019) plen 10
> HCI Event: Command Status (0x0f) plen 4
> ACL data: handle 11 flags 0x02 dlen 16
    L2CAP(s): Info rsp: type 2 result 0
      Extended feature mask 0x0000
< ACL data: handle 11 flags 0x02 dlen 12
    L2CAP(s): Connect req: psm 3 scid 0x0040
> HCI Event: Number of Completed Packets (0x13) plen 5
> ACL data: handle 11 flags 0x02 dlen 16
    L2CAP(s): Connect rsp: dcid 0x04fb scid 0x0040 result 1 status 2
      Connection pending - Authorization pending
> HCI Event: Remote Name Req Complete (0x07) plen 255
> ACL data: handle 11 flags 0x02 dlen 16
    L2CAP(s): Connect rsp: dcid 0x04fb scid 0x0040 result 0 status 0
      Connection successful
< ACL data: handle 11 flags 0x02 dlen 16
    L2CAP(s): Config req: dcid 0x04fb flags 0x00 clen 4
      MTU 1013
(events are properly received using bluez)

=====部分adb bugreport =====

--Known devices--
00:19:A1:2D:16:EA     bonded (0) LG U830
    00001105-0000-1000-8000-00805f9b34fb RFCOMM channel = 17
00:1C:4D:02:A6:55     bonded (0) Zeemote JS1
00:0B:2E:6E:6F:00     bonded (0) Motorola HS815
    00001108-0000-1000-8000-00805f9b34fb RFCOMM channel = 1
    0000111e-0000-1000-8000-00805f9b34fb RFCOMM channel = 2
00:1F:3A:E4:C8:40     bonded (0) BRCM BT4X
    00001105-0000-1000-8000-00805f9b34fb RFCOMM channel = 9
00:18:42:EC:E2:99     bonded (0) N95
    00001105-0000-1000-8000-00805f9b34fb RFCOMM channel = 9

=====摘自启动日志=====

04-18 21:55:10.382: VERBOSE/BluetoothEventRedirector(1985): Received android.bluetooth.adapter.action.STATE_CHANGED
04-18 21:55:10.421: DEBUG/BT HSHFP(1237): Loaded priority 00:19:A1:2D:16:EA = 100
04-18 21:55:10.428: DEBUG/BT HSHFP(1237): Loaded priority 00:1C:4D:02:A6:55 = 0
04-18 21:55:10.444: DEBUG/BT HSHFP(1237): Loaded priority 00:0B:2E:6E:6F:00 = 101
04-18 21:55:10.749: DEBUG/BT HSHFP(1237): Loaded priority 00:1F:3A:E4:C8:40 = 100
04-18 21:55:10.780: DEBUG/BT HSHFP(1237): Loaded priority 00:18:42:EC:E2:99 = 100

5 回答

  • 0

    尝试更改用于创建RfcommSocket的代码:

    sock = zee.createRfcommSocketToServiceRecord(
                          UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
    

    对于此代码:

    Method m = zee.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
    sock = (BluetoothSocket) m.invoke(device, 1);
    

    还尝试在此m.invoke(device,1)中更改1-3范围内的参数值;当连接将被连接,但在您尝试阅读时中止,请再次调用方法test() . 很简单:

    for(int i=0;i<3;i++){  if(!testDone) test(); }
    
  • 5

    我合并了我编写的代码和来自[android-beginners]的代码Re:串口通过XCaffeinated的蓝牙] 1和上面的帖子 .

    尽可能创建最简单的蓝牙程序 .

    此代码的主要补充是为 connect() 抛出的异常添加更好的处理 .

    搜索“@todo”以根据您的需求进行定制 .

    我希望这能节省你一些时间!

    package com.xxx; // @todo Change to your package.   
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothSocket;
    import android.os.Bundle;
    import android.util.Log;
    
    /**
     * This is the simplest bluetooth program. It sends one message to one bluetooth
     * device. The message and the bluetooth hardware id for the device are hard
     * coded. <br>
     * <br>
     * It does <b>not</b> receive any data. It does not do any thread processing. <br>
     * <br>
     * 
     * This application will be useful to communicate with a bluetooth hardware
     * device such as a bar code reader, Lego Mindstorm, a PC with a com port
     * application, a PC with a terminal program with 'listening' to a com port, a
     * second android device with a terminal program such as <a href=
     * "http://www.tec-it.com/en/software/data-acquisition/getblue/android-smartphone/Default.aspx"
     * >GetBlue</a>. It is not a full android bluetooth application but more a proof
     * of concept that the bluetooth works.
     * 
     * <br>
     * <br>
     * 
     * This code should cut and paste into the <a
     * href="http://developer.android.com/resources/tutorials/hello-world.html>
     * 'HelloAndroid' example</a>. It does not use any screen io.
     * 
     * Add to your Android Manifest.xml file: <uses-permission
     * android:name="android.permission.BLUETOOTH" /> <uses-permission
     * android:name="android.permission.BLUETOOTH_ADMIN" />
     * 
     * For a proper bluetooth example with threading and receiving data see: <a
     * href=
     * "http://developer.android.com/resources/samples/BluetoothChat/index.html"
     * >http://developer.android.com/resources/samples/BluetoothChat/index.html</a>
     * 
     * @see <a
     *      href="http://developer.android.com/guide/topics/wireless/bluetooth.html">
     *      http://developer.android.com/guide/topics/wireless/bluetooth.html</a>
     * 
     */
    public class BlueToothTesterActivity extends Activity {
    
        /** The BluetoothAdapter is the gateway to all bluetooth functions **/
        protected BluetoothAdapter bluetoothAdapter = null;
    
        /** We will write our message to the socket **/
        protected BluetoothSocket socket = null;
    
        /** The Bluetooth is an external device, which will receive our message **/
        BluetoothDevice blueToothDevice = null;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            // Grab the BlueToothAdapter. The first line of most bluetooth programs.
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
            // if the BluetoothAdapter.getDefaultAdapter(); returns null then the
            // device does not have bluetooth hardware. Currently the emulator
            // does not support bluetooth so this will this condition will be true.
            // i.e. This code only runs on a hardware device an not on the emulator.
            if (bluetoothAdapter == null) {
                Log.e(this.toString(), "Bluetooth Not Available.");
                return;
            }
    
            // This will find the remote device given the bluetooth hardware
            // address.
            // @todo: Change the address to the your device address
            blueToothDevice = bluetoothAdapter.getRemoteDevice("00:00:00:00:00:00");
    
            for (Integer port = 1; port <= 3; port++) {
                simpleComm(Integer.valueOf(port));
            }
        }
    
        protected void simpleComm(Integer port) {
            // byte [] inputBytes = null;
    
            // The documents tell us to cancel the discovery process.
            bluetoothAdapter.cancelDiscovery();
    
            Log.d(this.toString(), "Port = " + port);
            try {
                // This is a hack to access "createRfcommSocket which is does not
                // have public access in the current api.
                // Note: BlueToothDevice.createRfcommSocketToServiceRecord (UUID
                // uuid) does not work in this type of application. .
                Method m = blueToothDevice.getClass().getMethod(
                        "createRfcommSocket", new Class[] { int.class });
                socket = (BluetoothSocket) m.invoke(blueToothDevice, port);
    
                // debug check to ensure socket was set.
                assert (socket != null) : "Socket is Null";
    
                // attempt to connect to device
                socket.connect();
                try {
                    Log.d(this.toString(),
                            "************ CONNECTION SUCCEES! *************");
    
                    // Grab the outputStream. This stream will send bytes to the
                    // external/second device. i.e it will sent it out.
                    // Note: this is a Java.io.OutputStream which is used in several
                    // types of Java programs such as file io, so you may be
                    // familiar with it.
                    OutputStream outputStream = socket.getOutputStream();
    
                    // Create the String to send to the second device.
                    // Most devices require a '\r' or '\n' or both at the end of the
                    // string.
                    // @todo set your message
                    String message = "Data from Android and tester program!\r";
    
                    // Convert the message to bytes and blast it through the
                    // bluetooth
                    // to the second device. You may want to use:
                    // public byte[] getBytes (Charset charset) for proper String to
                    // byte conversion.
                    outputStream.write(message.getBytes());
    
                } finally {
                    // close the socket and we are done.
                    socket.close();
                }
                // IOExcecption is thrown if connect fails.
            } catch (IOException ex) {
                Log.e(this.toString(), "IOException " + ex.getMessage());
                // NoSuchMethodException IllegalAccessException
                // InvocationTargetException
                // are reflection exceptions.
            } catch (NoSuchMethodException ex) {
                Log.e(this.toString(), "NoSuchMethodException " + ex.getMessage());
            } catch (IllegalAccessException ex) {
                Log.e(this.toString(), "IllegalAccessException " + ex.getMessage());
            } catch (InvocationTargetException ex) {
                Log.e(this.toString(),
                        "InvocationTargetException " + ex.getMessage());
            }
        }
    
    }
    
  • 8

    如果我理解正确,您的应用无法从设备中看到任何数据?

    一件小事:尝试没有hipns的UUID . 在我的RFCOMM应用程序中,我实际上将UUID定义为长整数常量 .

    此外,你的test()方法的编写方式让我相信test()正在 Build 连接,定义一个线程,告诉它启动并立即返回 . 换句话说,你的线程引用了一个来自线程外部的变量,这是test()方法的一部分,但是当test()死掉时,它的变量也是如此 .

    简而言之,在线程之外尝试测试并首先在那里工作 . 一种简单的方法是使用Thread.run()而不是thread.start() . .run()在前台运行它(因此阻塞test(),因此它在线程完成之前不会返回) .

    对于长期解决方案,您可能希望将蓝牙变量定义为gloibal / member变量,这样它们就不会超出范围,并且始终可供您的线程使用 .

  • 0

    试试众所周知的UUID:00001101-0000-1000-8000-00805F9B34FB

  • 25

    上面的代码不适用于带有4.0.4的Samsung Galaxy tab 2 . BTSocket.connect总是触发蓝牙配对对话框然后失败,即使输入了正确的引脚 . 从“createRfcommSocket”更改为“createInsecureRfcommSocket”解决了这个问题 . 希望这会有所帮助,我在这个问题上奋斗了3个多小时 .

相关问题