Android通过蓝牙发送命令失败

2024-01-01

我将实现从 Android 平板电脑向嵌入蓝牙 IC 芯片 Andrino HC-06 的电子设备发送命令的模块,以便通过蓝牙配置我的设备。执行时,发送时设备似乎没有可观察到的响应22 23 54 01 C8。 它显示以下超时异常 预计设备将重新启动并返回许多消息。将这些 eta 命令发送到我的设备进行远程控制时,我应该了解哪些更多信息?

日志猫消息

05-23 18:19:44.866: E/BluetoothChatService(512): java.io.IOException: bt socket closed, read return: -1
05-23 18:19:44.866: E/BluetoothChatService(512):    at android.bluetooth.BluetoothSocket.read(BluetoothSocket.java:429)
05-23 18:19:44.866: E/BluetoothChatService(512):    at android.bluetooth.BluetoothInputStream.read(BluetoothInputStream.java:96)
05-23 18:19:44.866: E/BluetoothChatService(512):    at java.io.InputStream.read(InputStream.java:162)
05-23 18:19:44.866: E/BluetoothChatService(512):    at com.example.android.BluetoothChat.BluetoothChatService$ConnectedThread.run(BluetoothChatService.java:485)

下面是我的代码

private void sendMessage(String message) {
        // Check that we're actually connected before trying anything
        if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
                    .show();
            return;
        }

        // Check that there's actually something to send
        if (message.length() > 0) {
            // Get the message bytes and tell the BluetoothChatService to write
            byte[] send = message.getBytes();
            mChatService.write(send);
            // Reset out string buffer to zero and clear the edit text field
            mOutStringBuffer.setLength(0);
            mOutEditText.setText(mOutStringBuffer);
        }
    }

发送命令

public void write(byte[] buffer) {
        try {
            boolean connected = false;
            BluetoothSocket sock = null;
            InputStream in = null ;
            OutputStream out = null ;
            BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:14:01:12:28:12");
            Method m =  zee.getClass().getMethod("createRfcommSocket",
                    new Class[] { int.class });
            sock = (BluetoothSocket) m.invoke(zee, Integer.valueOf(1));
            sock.connect();
            in = sock.getInputStream();
            out = sock.getOutputStream();


            char[] test = { 0x22 , 0x21 , 0x03 , 0x00 , 0xc9};

            for(int k=0; k < test.length; k++){
                new DataOutputStream(sock.getOutputStream()).writeByte(test[k]);
            }


            byte [] bfferX  = new String(test).getBytes("UTF-8");*/

            mmOutStream.write(buffer);
            mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
        } catch (IOException e) {
            Log.e(TAG, "Exception during write", e);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

我想设备已经配对并且 Android 设备执行发现。 为什么你认为这是一个超时问题?该异常表明通信套接字已关闭。也许你成功地创造了一个BluetoothSocket http://developer.android.com/reference/android/bluetooth/BluetoothSocket.html并“意外”关闭它(也许在刷新之后,您关闭了与套接字相关的输出或输入流)。

由于您正在遵循 Android BluetoothChat 示例,因此您应该:

1) 执行发现并监听可用设备:

private final BroadcastReceiver deviceFoundBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action) && mState==STATE_DISCOVERING) {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            new ConnectThread(device).start();
        }
    }
};

2)连接设备:

private class ConnectThread extends Thread {
    private BluetoothSocket mmSocket;
    private BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        BluetoothSocket tmp = null;
        mmDevice = device;
        try {
            tmp = InsecureBluetooth.createRfcommSocketToServiceRecord(mmDevice, YOUR_UUID, false);
        } 
        catch (IOException e) { }
        mmSocket = tmp;
    }

    @Override
    public void run() {
        try {
            btAdapter.cancelDiscovery(); // be sure discovery is cancelled
            mmSocket.connect(); // blocking call, returns only on a successful connection or an exception
            connected(mmSocket, mmSocket.getRemoteDevice()); 
            new ConnectedThread(mmSocket, mmDevice.getAddress()).start(); // start connected thread
        } 
        catch (IOException e) {}
    }

    public void cancel() {}
}

3) 检索用于与配对设备通信的输入和输出流(需要通信时不要关闭流):

private class ConnectedThread extends Thread {
    private BluetoothSocket mmSocket;
    private String macAddress;

    public ConnectedThread(BluetoothSocket socket, String macAddress) {
        this.macAddress = macAddress;
        this.mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        try { 
            mmInStream = mmSocket.getInputStream(); 
            mmOutStream = mmSocket.getOutputStream();
        } 
        catch (IOException e) {}
    }

    @Override
    public void run() {
        // perform communication
    }
}

InsecureBluetooth 类用于“避免”配对阶段,并且基于斯坦福大学的代码和平 http://stanford.edu/~tpurtell/InsecureBluetooth.java:

@TargetApi(10)
public class InsecureBluetooth {
    static private class InUse extends RuntimeException { }

    public static BluetoothServerSocket listenUsingRfcommWithServiceRecord(BluetoothAdapter adapter, String name, UUID uuid, boolean encrypt) throws IOException {
        if(Build.VERSION.SDK_INT<10) {

            try {
                Class c_rfcomm_channel_picker = null;
                Class[] children = BluetoothAdapter.class.getDeclaredClasses();
                for(Class c : children) {
                    Log.e("TO", "class " + c.getCanonicalName());
                    if(c.getCanonicalName().equals(BluetoothAdapter.class.getName() + ".RfcommChannelPicker")) {
                        c_rfcomm_channel_picker = c;
                        break;
                    }
                }
                if(c_rfcomm_channel_picker == null)
                    throw new RuntimeException("can't find the rfcomm channel picker class");

                Constructor constructor = c_rfcomm_channel_picker.getDeclaredConstructor(UUID.class);
                if(constructor == null)
                    throw new RuntimeException("can't find the constructor for rfcomm channel picker");
                Object rfcomm_channel_picker = constructor.newInstance(new Object[] {uuid});
                Method m_next_channel = c_rfcomm_channel_picker.getDeclaredMethod("nextChannel", new Class[] {});
                m_next_channel.setAccessible(true);

                BluetoothServerSocket socket = null;

                int channel;
                int errno;
                while (true) {
                    channel = (Integer)m_next_channel.invoke(rfcomm_channel_picker, new Object[] {});

                    if (channel == -1) {
                        throw new IOException("No available channels");
                    }

                    try {
                        socket = listenUsingRfcomm(channel, encrypt);
                        break;
                    } catch(InUse e) {
                        continue;
                    }
                }

                Field f_internal_service = adapter.getClass().getDeclaredField("mService");
                f_internal_service.setAccessible(true);
                Object internal_service = f_internal_service.get(adapter);

                Method m_add_rfcomm_service_record = internal_service.getClass().getDeclaredMethod("addRfcommServiceRecord", new Class[] {String.class, ParcelUuid.class, int.class, IBinder.class});
                m_add_rfcomm_service_record.setAccessible(true);

                int handle = (Integer)m_add_rfcomm_service_record.invoke(internal_service, new Object[] { name, new ParcelUuid(uuid), channel, new Binder() } );

                if (handle == -1) {
                    try {
                        socket.close();
                    } catch (IOException e) {}
                    throw new IOException("Not able to register SDP record for " + name);
                }
                Field f_internal_handler = null;
                try {
                    f_internal_handler = adapter.getClass().getDeclaredField("mServiceRecordHandler");
                } catch(Exception e) {
                    f_internal_handler = adapter.getClass().getDeclaredField("mHandler");
                }
                f_internal_handler.setAccessible(true);
                Object internal_handler = f_internal_handler.get(adapter);

                Method m_set_close_handler = socket.getClass().getDeclaredMethod("setCloseHandler", new Class[] {Handler.class, int.class});
                m_set_close_handler.setAccessible(true);

                m_set_close_handler.invoke(socket, new Object[] { internal_handler, handle});
                return socket;
            } catch (Exception e) {}
        }
        else {
            return adapter.listenUsingInsecureRfcommWithServiceRecord(name, uuid);
        }

    }

    private static BluetoothServerSocket listenUsingRfcomm(int port, boolean encrypt, boolean reuse) throws IOException, InUse {
        BluetoothServerSocket socket = null;
        try {
            Constructor<BluetoothServerSocket> constructor = BluetoothServerSocket.class.getDeclaredConstructor(int.class, boolean.class, boolean.class, int.class);
            if(constructor == null)
                throw new RuntimeException("can't find the constructor");
            constructor.setAccessible(true);
            Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
            f_rfcomm_type.setAccessible(true);
            int rfcomm_type = (Integer)f_rfcomm_type.get(null);

            Field f_e_addr_in_use = BluetoothSocket.class.getDeclaredField("EADDRINUSE");
            f_e_addr_in_use.setAccessible(true);
            int e_addr_in_use = (Integer)f_e_addr_in_use.get(null);

            socket = constructor.newInstance(new Object[] { rfcomm_type, false, encrypt, port } );

            Field f_internal_socket = socket.getClass().getDeclaredField("mSocket");
            f_internal_socket.setAccessible(true);
            Object internal_socket = f_internal_socket.get(socket);
            Method m_bind_listen = internal_socket.getClass().getDeclaredMethod("bindListen", new Class[] {});
            m_bind_listen.setAccessible(true);
            Object result = m_bind_listen.invoke(internal_socket, new Object[] {});

            int errno = (Integer)result;
            if(reuse && errno == e_addr_in_use) {
                throw new InUse();
            } else if (errno != 0) {
                try {
                    socket.close();
                } catch (IOException e) {}
                internal_socket.getClass().getMethod("throwErrnoNative", new Class[] {int.class}).invoke(internal_socket, new Object[] { errno });
            }
            return socket;
        } catch (Exception e) {}
    }

    public static BluetoothServerSocket listenUsingRfcomm(int port, boolean encrypt) throws IOException {
        return listenUsingRfcomm(port, encrypt, false);
    }

    private static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, int port, UUID uuid, boolean encrypt) throws IOException {

        try {
            BluetoothSocket socket = null;
            Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
                    int.class, int.class, boolean.class, boolean.class, BluetoothDevice.class, int.class, ParcelUuid.class);
            if(constructor == null)
                throw new RuntimeException("can't find the constructor for socket");

            constructor.setAccessible(true);
            Field f_rfcomm_type = BluetoothSocket.class.getDeclaredField("TYPE_RFCOMM");
            f_rfcomm_type.setAccessible(true);
            int rfcomm_type = (Integer)f_rfcomm_type.get(null);
            socket = constructor.newInstance(new Object[] { rfcomm_type, -1, false, true, device, port, uuid != null ? new ParcelUuid(uuid) : null} );
            return socket;
        } catch (Exception e) {}
    }

    public static BluetoothSocket createRfcommSocketToServiceRecord(BluetoothDevice device, UUID uuid, boolean encrypt) throws IOException{
        if(Build.VERSION.SDK_INT<10) {
            return createRfcommSocketToServiceRecord(device, -1, uuid, encrypt);
        }
        else {
            return device.createInsecureRfcommSocketToServiceRecord(uuid);
        }
    }

    public static BluetoothSocket createRfcommSocket(BluetoothDevice device, int port, boolean encrypt) throws IOException {
        return createRfcommSocketToServiceRecord(device, port, null, encrypt);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android通过蓝牙发送命令失败 的相关文章

  • 带阴影的弯曲 Android 工具栏

    我需要为工具栏或卡片视图提供弯曲的底视图 我尝试过的 bg toolbar xml
  • 任务“:app:dexDebug”执行失败

    我目前正在处理我的项目 我决定将我的 Android Studio 更新到新版本 但在我导入项目后 它显示如下错误 Information Gradle tasks app assembleDebug app preBuild UP TO
  • 合并两个位图图像(并排)

    任何人都可以帮助将两个位图图像合并为单个位图 在android中 并排 谢谢 尤瓦拉吉 您可以使用Canvas 查看这篇文章 http www jondev net articles Combining 2 Images in Androi
  • 检查双精度值的等于和不等于条件

    我在比较两者时遇到困难double values using and 我创建了 6 个双变量并尝试进行比较If健康 状况 double a b c d e f if a b c d e f My code here in case of t
  • 在 Android 中的活动、服务和应用程序之间传递变量

    有人可以给我提供以下活动 服务 应用程序组合的示例吗 我拥有这三个 但我已经把我的应用程序弄得一团糟 试图在这个地方传递一堆变量 现在我不知道发生了什么 请注意 我是 Android 新手 最近我一直在努力解决这个问题 因为有很多方法可以实
  • MI设备中即使应用程序被杀死,如何运行后台服务

    您好 我正在使用 alaram 管理器运行后台服务 它工作正常 但对于某些 mi 设备 后台服务无法工作 我使用了服务 但它无法工作 如何在 mi 中运行我的后台服务 MI UI有自己的安全选项 所以你需要的不仅仅是上面提到的粘性服务 你需
  • 下载图像并显示它

    应用程序的主要目的是下载和显示图像 但是当我尝试启动应用程序时它崩溃了 这是我的代码 private DownloadImageTask task protected void onCreate Bundle savedInstanceSt
  • 如何将单选按钮状态保存到已保存/共享首选项?

    我可以在保存的首选项中保存字符串 但很难保存单选按钮 public class PersonalDetailsf extends Activity private SharedPreferences sharedPreferences pr
  • Locale.getDefault().getCountry() 返回空字符串

    我正在尝试使用国家 地区代码获取用户语言 例如en US es es 但是当我使用Locale getDefault getCountry 它返回空字符串 虽然它给了我正确的语言Locale getDefault getLanguage N
  • 当参数具有默认值时,为什么无法使用导航组件将参数传递给片段?

    我正在使用导航组件 但我不明白为什么如果定义了参数 则将参数传递给下面的方法时会出现错误 我正在使用 SafeArgs 只有当我为此参数定义默认值时才会出现此错误 有人可以解释一下为什么会发生这种情况以及如何解决它吗 这是导航图的部分代码
  • Facebook LoginActivity 未正确显示

    我有一个使用 Facebook 登录的应用程序 我有 FacebookSDK 并且使用 com facebook LoginActivity 问题是 在 10 英寸平板电脑上 当显示软键盘时 活动无法正确显示 我使用的是 Samsung G
  • 手动启用时 Firebase Crashlytics 不报告崩溃

    Crashlytics 在没有选择加入报告的情况下也能正常工作 但一旦我根据规定设置了选择加入报告 它就会停止报告任何内容tutorial https firebase google com docs crashlytics customi
  • Android:如何监控WiFi信号强度

    当信号强度发生变化时我会收到通知 我尝试创建以下方法并在 onCreate 中调用它 private void initializeWiFiListener Log i TAG executing initializeWiFiListene
  • 更改android中禁用按钮的颜色

    有没有办法通过样式或其他形式更改 android 中禁用按钮的颜色 我目前有以下内容 可绘制 button default xml
  • 如何在 WebView 中添加 JavaScript 函数并稍后在提交 reCAPTCHA 时从 HTML 调用它

    我在 WebView 中添加一个 JavaScript 函数 如下所示 Kotlin val webView findViewById R id webview as WebView webView getSettings setJavaS
  • 带有空白白屏的 WebView

    我在 DialogFragment 中有一个 webview 它使用以下方式显示文档和 PDF它可以进行几次尝试 但如果用户尝试频繁打开和关闭对话框 webview 将显示空白屏幕 我已经尝试了所有的线程link1 https stacko
  • 如何更改锁屏自定义文本(所有者信息)?

    我写了程序代码 String message This is test Settings System putString context getContentResolver Settings Secure LOCK PATTERN EN
  • OpenGL ES 2.0 屏幕闪烁

    我面临着一个大问题 我正在使用带有 Android 4 0 3 的 Transformer tf101 选项卡 我的应用程序使用自定义 OpenGL ES 2 0 表面 我正在用纹理渲染多个平面 该纹理大约发生变化 每秒 20 次 并通过传
  • gradle-experimental:0.1.0 buildConfigField

    谁知道怎么定义buildConfigField在实验性的 gradle 插件中 android productFlavors create demo applicationId com anthonymandra rawdroid buil
  • Android:获取最新意图

    如何获取发送到活动的最后一个意图 的文档onNewIntent 建议我需要做这样的事情 class MyActivity public void onNewIntent Intent intent setIntent intent reac

随机推荐

  • 从 Javascript 触发回发

    好的 我知道这个问题已经被问了很多次 并且我在网上找到了大量有关此问题的信息 不幸的是 这些似乎都不适合我 基本上 我运行一些 JavaScript 来响应用户事件 JavaScript 获取一些信息 一个 int 然后我想将其返回到服务器
  • Google Map API v3 ~ 只需关闭信息窗口?

    尝试简单地关闭信息窗口 我已经有了一系列标记 所以像这样的东西会很好 谢谢 MyMarkers i infowindow close 随着v3 API http code google com apis maps documentation
  • 在一列或多列中查找独特的单词?

    我正在考虑在我的 ASP NET 网站中实现标签 在研究了几种算法之后 我倾向于拥有几个包含一个或多个标签词的数据库列 然后 我将使用全文搜索来查找具有指定标签的行 所有这一切看起来都非常简单 除了一件事 我需要能够生成可用标签列表 用户可
  • R - 按组有条件地对多列进行升序或降序排序

    我以前没有遇到过这个问题 我想根据条件对组内的多列进行升序或降序排序 library dplyr data lt mtcars gt select mpg cyl disp If cyl lt 4 我想排序mpg disp 按该优先级 按升
  • BB10 Cascade 命令行开发

    如果您了解 Qt 那么 BB10 的编程现在应该会容易得多 所以我决定尝试一下 并且我一直在阅读以下内容 https developer blackberry com cascades documentation getting start
  • 在图形环境中,术语“橡皮筋”是什么意思?

    在不同的地方 我都看到过在指代图形绘制时使用的术语 橡皮筋 在这种情况下 人们似乎建议使用 XOR 进行绘图 我的印象是该术语指的是一种用于避免重新绘制整个框架的特定绘图技术 然而 我还没有找到任何可以准确定义 橡皮筋 一词含义的内容 只是
  • 构造函数作为委托 - 在 C# 中可能吗?

    我有一个如下所示的课程 class Foo public Foo int x 我需要将委托传递给某个方法 如下所示 delegate Foo FooGenerator int x 是否可以直接将构造函数作为FooGenerator值 无需输
  • JavaScript getter 和 setter - 递归问题

    JavaScript 的 setter 和 getter 中的 字符有何意义 例如 我有以下代码 可以正常工作 var user get name return this name set name value this name valu
  • 具有通配符属性名称和特定属性值的 C# 和 XPath

    我可以使用 XPath 查找具有名称以特定字符集开头且属性值包含特定值的属性的所有元素吗 例如
  • 调用验证后容器不会调整自身大小

    通过手动交换组件后add and remove 我调用validate 在容器上 根据文档 validate 方法用于使容器布置它的 再次子组件 当该容器的 子组件被修改 添加到容器或从容器中删除 或者 布局相关信息已更改 容器已被 显示
  • 使用 WordApi 1.3 时 context.application 未定义

    使用 WordApi 1 3 应该可以使用新的创建文档方法 https github com OfficeDev office js docs blob WordJs 1 3 Openspec reference word applicat
  • Clojure 模型-视图-控制器 (MVC) 设计

    我正在使用 Java Swing 在 Clojure 中编写桌面 GUI 应用程序 通常 在使用 Java 时 我会根据 MVC 设计模式并使用观察者模式来设计应用程序 通过这种方式 视图与模型分离 并且两者的更改不会相互影响 从而使进一步
  • 在每种情况下使用带有值范围的 switch 语句?

    在Java中 是否可以编写一个switch语句 其中每个case包含多个值 例如 尽管显然以下代码不起作用 switch num case 1 5 System out println testing case 1 to 5 break c
  • PyCUDA/CUDA:不确定性启动失败的原因?

    任何关注 CUDA 的人可能都会看到我对我所参与的项目提出的一些疑问 但对于那些没有见过的人 我将进行总结 抱歉提前问了一个很长的问题 三个内核 一个基于一些输入变量生成数据集 处理位组合 因此可以呈指数增长 另一个解决这些生成的线性系统
  • 如何使用 Spray.io 构建 RESTful API?

    当我使用 Spray io 开发 RESTful API 时 我应该如何构建我的应用程序 我已经看到了这个答案 https stackoverflow com a 14653989 396002关于如何拆分 Spray 应用程序 但我对此不
  • 什么时候不应该使用分号?

    Or 什么不是 T SQL 语句 除了解决歧义之外 T SQL 语法不需要分号来终止语句 尽管如此 伊齐克 本 甘 http www sqlmag com blog puzzled by t sql blog 15 tsql semicol
  • 我在 VBA 中的代码使索引超出范围,但我确信数组的长度正确[重复]

    这个问题在这里已经有答案了 我需要设置val1 and val2分配给变量的数字total 无论我改变变量什么totalto 0 8 表示索引越界 我还打印了我用 MsgBox 引用的每个列表的长度 它显示为 8 我尝试将索引更改为该范围内
  • Rails 将无效路由重定向到 root

    如果我的网站是www foo com如果用户输入www foo com blahblahblah它会说 blahblahblah是一个无效的路径 显然 但我希望它重定向到 root path 以便控制器可以处理 URL 页面www foo
  • 发布版本中的 Swift 链接器错误可通过添加代码修复

    在 Xcode 8 中 我的一个 Swift 项目在调试模式下工作 但在发布模式下无法链接 Undefined symbols for architecture x86 64 Swift UnsafeMutableBufferPointer
  • Android通过蓝牙发送命令失败

    我将实现从 Android 平板电脑向嵌入蓝牙 IC 芯片 Andrino HC 06 的电子设备发送命令的模块 以便通过蓝牙配置我的设备 执行时 发送时设备似乎没有可观察到的响应22 23 54 01 C8 它显示以下超时异常 预计设备将