Android上利用SDK的BluetoothAPI实现传送文件

来源:互联网 发布:java三层架构怎么搭建 编辑:程序博客网 时间:2024/05/18 00:04

从Android 2.0版的SDK开始,公开了蓝牙相关的API接口,而之前的1.5~1.6未公开蓝牙API的系统,实际上也仅仅是未公开API而已,有可能是带有蓝牙服务的,通过一些Hack手段是能够获取到被隐藏的API的,这部分不在本文讨论范围之内。从SDK中公开的API来看,功能相当简单,并没有提供传输文件的直接支持,也就意味着要在Android上编码实现传送文件,还是要花一番功夫的。

  蓝牙传输文件是通过OBEX协议来实现的,具体可以参见蓝牙相关的协议说明。对于传送文件而言,我们只需要实现OBEX中OBJECT PUSH的那一部分即可,好在在Android Bluetooth API的基础上实现OBEX的协议中的PUSH部分完全是可行的,下面就来详细说明一下。首先,BluetoothSocket和普通的用于网络编程的Socket有些不同,我们要实现的是一个传送文件的客户端,可以通过BluetoothDevice.

createRfcommSocketToServiceRecord (UUID uuid) 这一接口来创建BluetoothSocket,注意该接口需要传入一个UUID的参数,这一UUID将标示服务类型,可以参见SDP(Service Discover Protocol),用于传输文件的服务的UUID是{00001105-0000-1000-8000-00805F9B34FB},这样如果接收方能够支持这一服务的话,我们就可以成功创建出一个用于传输的Socket。

  成功创建Socket之后,我们就需要开始按照OBEX的协议标准来和服务端进行通讯了,传输一个文件的过程是:CONNECT->PUT->PUT….->DISCONNECT,要实现OBEX协议通讯,实际上就是要按照OBEX协议的格式来组织我们写往Socket流的二进制数据,关于OBEX协议标准可以参见相关文档,这里就不赘述,简要介绍一下OBEX协议格式,主要由包头和包体两部分组成,包头中第一个字节表示操作码,用于标示该包数据类型,不同的操作码对应的包头格式也不同。包头中含有的其他信息也都是一个【特征码+信息内容】的格式来组织的。

  下面回到我们的传输文件过程,简单的三部曲似乎没有什么特别的,这里需要注意的也就是PUT的过程,可能是分为好几次进行的。CONNECT的时候,服务端回返回一个包可用最大长度,这个长度就限定了我们发送出去的包长度,包括OBEX的协议包头。当文件大小超过这一长度限制-包头长度的时候,就需要分几次来发送文件内容了。第一次PUT的包的头部信息中必须至少包含文件名和文件大小两项,其他关于MimeType等信息都是可选的,第二次就不必再带有这些信息了,PUT包的尾部为BODY/BODY Final标志,分别为0x48、0x49,非最后一包使用0x48,否则使用0x49,注意,OBEX协议包头中的操作码和这一标志也有一个对应关系,0x02/0x82都表示Put,但只有最后一包可以使用0x82。 另外OBEX也是面向连接的,每次发包到服务端之后都应该获取服务端的响应包,并且解析响应包的内容,如果发生超时或者响应包非正常响应,都因该采取相应的异常处理流程。

  最后需要注意的就是传输文件内容完成之后,要记得发送DISCONNECT的包,否则某些情况下服务端会认为是没有成功完成发送。

后记:

后来发现一个新问题,传输的文件发送给android手机的时候,某些文件不能够传输成功.后来查看了Android的源代码,原来Android只支持4中mimetype的接收,video/*,audio/*,image/*,text/plain,所以如果你要传输的文件不属于这四种mimetype,你在代码中还是要把它伪装一下,设置mimetype为其中之一,我选择的是image/*,经测试,效果良好.