搜档网
当前位置:搜档网 › ANDROID蓝牙编程

ANDROID蓝牙编程

ANDROID蓝牙编程
ANDROID蓝牙编程

ANDROID蓝牙编程

用BluetoothAdapter类,你能够在Android设备上查找周边的蓝牙设备然后配对(绑定),蓝牙通讯是基于唯一地址MAC来相互传输的,考虑到安全问题Bluetooth通讯时需要先配对。然后开始相互连接,连接后设备将会共享同一个RFCOMM通道以便相互传输数据,目前这些实现在Android 2.0或更高版本SDK 上实现。

一、查找发现 findding/discovering devices

对于Android查找发现蓝牙设备使用BluetoothAdapter类的startDiscovery()方法就可以执行一个异步方式获取周边的蓝牙设备,因为是一个异步的方法所以我们不需要考虑线程被阻塞问题,整个过程大约需要12秒时间,这时我们紧接着注册一个 BroadcastReceiver 对象来接收查找到的蓝牙设备信息,我们过滤ACTION_FOUND这个 Intent动作来获取每个远程设备的详细信息,通过附加参数在Intent字段EXTRA_DEVICE 和 EXTRA_CLASS, 中包含了每个BluetoothDevice 对象和对象的该设备类型 BluetoothClass ,示例代码

private final BroadcastReceiver cwjReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (BluetoothDevice.ACTION_FOUND.equals(action)) {

BluetoothDevice device =

intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

myArrayAdapter.add(device.getName() + " android123 " + device.getAddress()); //获取设备名称和mac地址

}

}

};

// 注册这个 BroadcastReceiver

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(cwjReceiver, filter);

最后android123提醒大家需要注意的是,记住在Service或Activity中重写onDestory()方法,使用unregisterReceiver方法反注册这个BroadcastReceiver对象保证资源被正确回收。

一些其他的状态变化有 ACTION_SCAN_MODE_CHANGED 额外参数

EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE以及

SCAN_MODE_CONNECTABLE_DISCOVERABLE、 SCAN_MODE_CONNECTABLE和

SCAN_MODE_NONE, 蓝牙模块

二、配对绑定 bnded/paired device

在Android中配对一个蓝牙设备可以调用BluetoothAdapter类的getBondedDevices()方法可以获取已经配对的设备,该方法将会返回一个BluetoothDevice数组来区分每个已经配对的设备,示例代码如下:

Set pairedDevices =

cwjBluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) //如果获取的结果大于0,则开始逐个解析

{

for (BluetoothDevice device : pairedDevices) {

myArrayAdapter.add(device.getName() + " android123 " +

device.getAddress()); //获取每个设备的名称和MAC地址添加到数组适配器myArrayAdapter中。

}

}

蓝牙模块

很多网友不明白如何让自己的手机被其他蓝牙设备发现如何设置,下面我们就

一起来说说

三、允许发现 enabling discoverability

如果需要用户确认操作,不需要获取底层蓝牙服务实例,可以通过一个Intent

来传递ACTION_REQUEST_DISCOVERABLE参数,这里通过

startActivityForResult来强制获取一个结果,重写startActivityForResult()方法获取执行结果,返回结果有RESULT_OK和RESULT_CANCELLED分别代表开

启和取消(失败),当然最简单的方法是直接执行,示例代码如下

Intent cwjIntent = new

Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

cwjIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(cwjIntent);

接下来系统会提示用户是否允许,对话框如下

从Android 2.0开始提供最全面的蓝牙开发接口,API Level为5的系统才能调用,目前Android Bluetooth API包含了主要以下几类:BluetoothAdapter BluetoothDevice、BluetoothSocket 、BluetoothServerSocket 和BluetoothClass 它们均在android.bluetooth这个包中出现。

我们调用时除了需要考虑API Level至少为5外,还需注意添加相应的权限,比如使用通讯需要在androidmanifest.xml加入

android:name="android.permission.BLUETOOTH" />,而开关蓝牙需要android.permission.BLUETOOTH_ADMIN权限。

三、建立通讯 establishing

对于建立一个蓝牙通讯,必须经过以下四个步骤:获取本地蓝牙设备、查找远程设备、配对(已配对设备将会忽略这步的细节)、连接设备和传输数据.

在Android平台中首先我们需要查找本地活动的蓝牙适配器,通过BluetoothAdapter类的getDefaultAdapter() 方法获得一个系统默认可用的蓝牙设备,示例代码如下

BluetoothAdapter cwjBluetoothAdapter =

BluetoothAdapter.getDefaultAdapter();

if (cwjBluetoothAdapter == null) {

// Android开发网提示大家本机没有找到蓝牙硬件或驱动存在问题

}

当然有了这步仍然不能建立连接,因为我们还不知道手机中的蓝牙功能是否被开启,可以通过cwjBluetoothAdapter的.isEnabled方法来判断,如果没有开启,我们可以通过下面的代码提醒用户启用:

if (!cwjBluetoothAdapter.isEnabled()) {

Intent TurnOnBtIntent = new

Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(TurnOnBtIntent, REQUEST_ENABLE_BT);

}

这时用户会收到类似下面的窗口:

我们通过startActivityForResult()方法发起的Intent将会在onActivityResult()回调方法中获取用户的选择,比如用户单击了Yes开启,那么将会收到RESULT_OK 的结果,如果RESULT_CANCELED则代表用户不愿意开启蓝牙,当然android123提醒大家还可以通过其他方式来开启,比如说用BluetoothDevice获取蓝牙服务接口对象,是用enable()方法来开启,无需询问用户,这时就需要用到 android.permission.BLUETOOTH_ADMIN权限。

如何判断系统蓝牙的状态呢? 建立BroadcastReceiver对象,接收

ACTION_STATE_CHANGED动作,在EXTRA_STATE和 EXTRA_PREVIOUS_STATE包含了现在状态和过去的状态,最终的结果定义是STATE_TURNING_ON正在开启,STATE_ON已经开启, STATE_TURNING_OFF正在关闭和 STATE_OFF已经关闭,如果有什么不明白的可以在我们的论坛中交流。

Android 蓝牙中的 RFCOMM

一RFCOMM通道:

RFCOMM协议

一个基于欧洲电信标准协会ETSI07.10规程的串行线性仿真协议。此协议提供RS232控制和状态信号,如基带上的损坏,CTS以及数据信号等,为上层业务(如传统的串行线缆应用)提供了传送能力。

RFCOMM是一个简单传输协议,其目的是针对如何在两个不同设备上的应用之间保证一条完整的通信路径,并在它们之间保持一通信段。

RFCOMM协议概述

RFCOMM通信段

RFCOMM是为了兼容传统的串口应用,同时取代有线的通信方式,蓝牙协议栈需要提供与有线串口一致的通信接口而开发出的协议。RFCOMM协议提供对基于L2CAP协议的串口仿真,基于ETSI07.10。可支持在两个BT设备之间同时保持高达60路的通信连接。

目的:

在两个不同设备(通信设备的两端)上的应用之间保证一条完整的通信路径,并在他们之间保持一通信段。下图是一条完整的通信路径。

RFCOMM只针对直接互连设备之间的连接,或者是设备与网络接入设备之间的互连。通信两端设备必须兼容于RFCOMM协议,有两类设备:DTE (Data Terminal Endpoint,通信终端,如PC,PRINTER)和DCE (Data Circuit Endpoint,通信段的一部分,如Modem)。此两类设备不作区分。

RFCOMM服务

RFCOMM仿真RS232串口,仿真过程包括非数据通路状态的传输,RFCOMM内置空Modem仿真标准框架。

RFCOMM中的仿真RS-232通路

多串口仿真

两个采用RFCOMM通信的BT设备有可能同时打开多个串口,RFCOMM支持同时打开60个端口。

认识二:MAC硬件地址

MAC(Medium/MediaAccess Control, 介质访问控制)MAC地址是烧录在NetworkInterfaceCard(网卡,NIC)里的.MAC地址,也叫硬件地址,是由48比特长(6字节),16进制的数字组成.0-23位叫做组织唯一标志符(organizationally unique,是识别LAN(局域网)节点的标识.24-47位是由厂家自己分配。其中第40位是组播地址标志位。网卡的物理地址通常是由网卡生产厂家烧入网卡的EPROM(一种闪存芯片,通常可以通过程序擦写),它存储的是传输数据时真正赖以标识发出数据的电脑和接收数据的主机的地址。

也就是说,在网络底层的物理传输过程中,是通过物理地址来识别主机的,它一般也是全球唯一的。比如,著名的以太网卡,其物理地址是 48bit(比特位)的整数,如:44-45-53-54-00-00,以机器可读的方式存入主机接口中。以太网地址管理机构(除了管这个外还管别的)

(IEEE)(IEEE:电气和电子工程师协会)将以太网地址,也就是48比特的不同组合,分为若干独立的连续地址组,生产以太网网卡的厂家就购买其中一组,具体生产时,逐个将唯一地址赋予以太网卡。

形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。

步骤一:Setting Up Bluetooth

通过BluetoothAdapter得到蓝牙的Activity

发送蓝牙连接意图

通过e onActivityResult()得到蓝牙连接意图

步骤二: Finding Devices

通过得到开启蓝牙用户名和MAC地址

配对蓝牙

步骤三:连接蓝牙

就像java的聊天系统一样用一个蓝牙手机当服务器,一个当客户端,在用一个类当做连接的管理类就行了

Android蓝牙API介绍:BluetoothAdapter类

使用BluetoothAdapter类,你能够在Android设备上查找周边的蓝牙设备然后配对(绑定),蓝牙通讯是基于唯一地址MAC来相互传输的,考虑到安全问题Bluetooth通讯时需要先配对。然后开始相互连接,连接后设备将会共享同一个RFCOMM通道以便相互传输数据,目前这些实现在Android 2.0或更高版本SDK 上实现。

一、查找发现 findding/discovering devices

对于Android查找发现蓝牙设备使用BluetoothAdapter类的startDiscovery()方法就可以执行一个异步方式获取周边的蓝牙设备,因为是一个异步的方法所以我们不需要考虑线程被阻塞问题,整个过程大约需要12秒时间,这时我们紧接着注册一个 BroadcastReceiver 对象来接收查找到的蓝牙设备信息,我们过滤ACTION_FOUND这个 Intent动作来获取每个远程设备的详细信息,通过附加参数在Intent字段EXTRA_DEVICE 和 EXTRA_CLASS, 中包含了每个BluetoothDevice 对象和对象的该设备类型 BluetoothClass ,示例代码

private final BroadcastReceiver cwjReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (BluetoothDevice.ACTION_FOUND.equals(action)) {

BluetoothDevice device =

intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

myArrayAdapter.add(device.getName() + " android123 " +

device.getAddress()); //获取设备名称和mac地址

}

}

};

// 注册这个 BroadcastReceiver

IntentFilter filter = new

IntentFilter(BluetoothDevice.ACTION_FOUND);

registerReceiver(cwjReceiver, filter);

最后android123提醒大家需要注意的是,记住在Service或Activity中重写onDestory()方法,使用unregisterReceiver方法反注册这个BroadcastReceiver对象保证资源被正确回收。

一些其他的状态变化有 ACTION_SCAN_MODE_CHANGED 额外参数

EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE以及

SCAN_MODE_CONNECTABLE_DISCOVERABLE、 SCAN_MODE_CONNECTABLE和

SCAN_MODE_NONE,

二、配对绑定 bnded/paired device

在Android中配对一个蓝牙设备可以调用BluetoothAdapter类的getBondedDevices()方法可以获取已经配对的设备,该方法将会返回一个BluetoothDevice数组来区分每个已经配对的设备,示例代码如下:

Set pairedDevices = cwjBluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) //如果获取的结果大于0,则开始逐个解析

{

for (BluetoothDevice device : pairedDevices) {

myArrayAdapter.add(device.getName() + " android123 " +

device.getAddress()); //获取每个设备的名称和MAC地址添加到数组适配器myArrayAdapter中。

}

}

很多网友不明白如何让自己的手机被其他蓝牙设备发现如何设置,下面我们就一起来说说

三、允许发现 enabling discoverability

如果需要用户确认操作,不需要获取底层蓝牙服务实例,可以通过一个Intent来传递ACTION_REQUEST_DISCOVERABLE 参数,这里通过startActivityForResult来强制获取一个结果,重写startActivityForResult()方法获取执行结果,返回结果有RESULT_OK和RESULT_CANCELLED分别代表开启和取消(失败),当然最简单的方法是直接执行,示例代码如下

Intent cwjIntent = new

Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

cwjIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);

startActivity(cwjIntent);

接下来系统会提示用户是否允许,对话框如下:

从Android 2.0开始提供最全面的蓝牙开发接口,API Level为5的系统才能调用,目前Android Bluetooth API包含了主要以下几类:BluetoothAdapter

BluetoothDevice、BluetoothSocket 、BluetoothServerSocket 和BluetoothClass 它们均在android.bluetooth这个包中出现。

我们调用时除了需要考虑API Level至少为5外,还需注意添加相应的权限,比如使用通讯需要在androidmanifest.xml加入,而开关蓝牙需要android.permission.BLUETOOTH_ADMIN权限。

三、建立通讯 establishing

对于建立一个蓝牙通讯,必须经过以下四个步骤:获取本地蓝牙设备、查找远程设备、配对(已配对设备将会忽略这步的细节)、连接设备和传输数据.

在Android平台中首先我们需要查找本地活动的蓝牙适配器,通过BluetoothAdapter类的getDefaultAdapter() 方法获得一个系统默认可用的蓝牙设备,示例代码如下

BluetoothAdapter cwjBluetoothAdapter =

BluetoothAdapter.getDefaultAdapter();

if (cwjBluetoothAdapter == null) {

// Android开发网提示大家本机没有找到蓝牙硬件或驱动存在问题

}

当然有了这步仍然不能建立连接,因为我们还不知道手机中的蓝牙功能是否被开启,可以通过cwjBluetoothAdapter的.isEnabled方法来判断,如果没有开启,我们可以通过下面的代码提醒用户启用:

if (!cwjBluetoothAdapter.isEnabled()) {

Intent TurnOnBtIntent = new

Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(TurnOnBtIntent, REQUEST_ENABLE_BT);

}

这时用户会收到类似下面的窗口:

我们通过startActivityForResult()方法发起的Intent将会在onActivityResult()回调方法中获取用户的选择,比如用户单击了Yes开启,那么将会收到RESULT_OK 的结果,如果RESULT_CANCELED则代表用户不愿意开启蓝牙,当然android123提醒大家还可以通过其他方式来开启,比如说用BluetoothDevice获取蓝牙服务接口对象,是用enable()方法来开启,无需询问用户,这时就需要用到 android.permission.BLUETOOTH_ADMIN权限。

如何判断系统蓝牙的状态呢? 建立BroadcastReceiver对象,接收ACTION_STATE_CHANGED动作,在EXTRA_STATE和 EXTRA_PREVIOUS_STATE包含了现在状态和过去的状态,最终的结果定义是STATE_TURNING_ON正在开启,STATE_ON已经开启, STATE_TURNING_OFF正在关闭和 STATE_OFF已经关闭,如果有什么不明白的可以在我们的论坛中交流。

Android蓝牙技术

对于一般的软件开发人员来说,蓝牙是很少用到的,尤其是Android的蓝牙开发,国内的例子很少 Android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试至少需要两部手机,所以制约了很多技术人员的开发,刚巧这段时间公司有蓝牙开发的需求,我看了很多国内、国外的资料,又研究了一下J2ME的蓝牙开发(为了找找思路),虽然我想要的功能还没实现(我曾经在很多论坛里问了很多遍,苦于没有高人解答..),我要实现的功能是连接一个硬件设备,凡是跟硬件沾上边的,都让软件人员开发头疼..

好了,废话不说了,鉴于很多开发人员现在也有蓝牙开发的需求,也为了大家少走些弯路,先将我积攒的一点点在Android蓝牙开发经验与大家分享一下!首先,要操作蓝牙,先要在AndroidManifest.xml里加入权限

然后,看下api,Android所有关于蓝牙开发的类都在android.bluetooth包下,如下图,只有8个类

而我们需要用到了就只有几个而已:

1.BluetoothAdapter 顾名思义,蓝牙适配器,直到我们建立bluetoothSocket 连接之前,都要不断操作它

BluetoothAdapter里的方法很多,常用的有以下几个:

cancelDiscovery() 根据字面意思,是取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不再继续搜索

disable()关闭蓝牙

enable()打开蓝牙,这个方法打开蓝牙不会弹出提示,更多的时候我们需要问下用户是否打开,一下这两行代码同样是打开蓝牙,不过会提示用户:Intemtenabler=newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enabler,reCode);//同startActivity(enabler);

getAddress()获取本地蓝牙地址

getDefaultAdapter()获取默认BluetoothAdapter,实际上,也只有这一种方法获取BluetoothAdapter

getName()获取本地蓝牙名称

getRemoteDevice(String address)根据蓝牙地址获取远程蓝牙设备

getState()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)

isDiscovering()判断当前是否正在查找设备,是返回true

isEnabled()判断蓝牙是否打开,已打开返回true,否则,返回false

listenUsingRfcommWithServiceRecord(String name,UUID uuid)根据名称,UUID创建并返回BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步

startDiscovery()开始搜索,这是搜索的第一步

2.BluetoothDevice看名字就知道,这个类描述了一个蓝牙设备

createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket

这个方法也是我们获取BluetoothDevice的目的——创建BluetoothSocket

这个类其他的方法,如getAddress(),getName(),同BluetoothAdapter

3.BluetoothServerSocket如果去除了Bluetooth相信大家一定再熟悉不过了,既然是Socket,方法就应该都差不多,

这个类一种只有三个方法

两个重载的accept(),accept(inttimeout)两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过[attach]3[/at期之后),都会阻塞线程,应该放在新线程里运行!

还有一点需要注意的是,这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端与客户端的两个BluetoothSocket的连接

close()这个就不用说了吧,翻译一下——关闭!

4.BluetoothSocket,跟BluetoothServerSocket相对,是客户端

一共5个方法,不出意外,都会用到

close(),关闭

connect()连接

getInptuStream()获取输入流

getOutputStream()获取输出流

getRemoteDevice()获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备

Android建立蓝牙RFCOMM通信

前面两篇文章中我们提到了有关Android平台蓝牙的配对、发现、启用等操作,本文开始通过BluetoothSocket类建立有关蓝牙通讯的套接字。从Android 2.0开始支持这一特性,蓝牙和LAN一样通过MAC地址来识别远程设备,建立完通

讯连接RFCOMM通道后以输入、输出流方式通讯。

一、连接设备

蓝牙通讯分为server服务器端和client客户端,它们之间使用BluetoothSocket 类的不同方法来获取数据,

1. 作为服务器

如果一个设备需要和两个或多个设备连接时,就需要作为一个server来传输,在android中提供了 BluetoothServerSocket类来处理用户发来的信息,服务器端套接字在接受(accepted) 一个客户发来的BluetoothSocket时作出相应的响应。示例代码如下:

private class AcceptThread extends Thread {

private final BluetoothServerSocket cwjServerSocket;

public AcceptThread() {

BluetoothServerSocket tmp = null; //使用一个临时对象代替,因为cwjServerSocket定义为final

try {

tmp = myAdapter.listenUsingRfcommWithServiceRecord(NAME, CWJ_UUID); //服务仅监听

} catch (IOException e) { }

cwjServerSocket = tmp;

}

public void run() {

BluetoothSocket socket = null;

while (true) { //保持连接直到异常发生或套接字返回

try {

socket = cwjServerSocket.accept(); //如果一个连接同意

} catch (IOException e) {

break;

}

if (socket != null) {

manageConnectedSocket(socket); //管理一个已经连接的RFCOMM通道在单独的线程。

cwjServerSocket.close();

break;

}

}

}

public void cancel() { //取消套接字连接,然后线程返回

try {

cwjServerSocket.close();

} catch (IOException e) { }

}

}

在这里android开发网提醒大家需要注意的是服务器一般处理多个任务不嫩阻塞,必须使用异步的方法这里我们开了一个线程,目前Android的虚拟机上层没有提供I/O模型,这里我们以后会讲解高负载情况下性能优化解决方案。

2. 作为客户端

以便初始化一个连接到远程设备,首先必须获取本地的BluetoothDevice 对象,相关的方法在我们 Android蓝牙API之BluetoothAdapter类的两篇文章中有讲到,这里不再赘述,相关的示例代码如下:

private class ConnectThread extends Thread {

private final BluetoothSocket cwjSocket;

private final BluetoothDevice cwjDevice;

public ConnectThread(BluetoothDevice device) {

BluetoothSocket tmp= null;

cwjDevice= device;

try {

tmp= device.createRfcommSocketToServiceRecord(CWJ_UUID); //客户端创建

} catch (IOException e) { }

cwjSocket= tmp;

}

public void run() {

myAdapter.cancelDiscovery(); //取消发现远程设备,这样会降低系统性能

try {

cwjSocket.connect();

} catch (IOException connectException) {

try {

cwjSocket.close();

} catch (IOException closeException) { }

return;

}

manageConnectedSocket(cwjSocket); //管理一个已经连接的RFCOMM通道在单独的线程。

}

public void cancel() {

try {

cwjSocket.close();

} catch (IOException e) { }

}

}

经过上面的介绍我们可以看到在Android平台上使用蓝牙通讯相对比较方便和简单,有关数据的具体通讯我们将在下次Android蓝牙API之BluetoothSocket类(2) 讲到manageConnectedSocket的具体实现。

通过前几次的讲解,很多网友相信对Android蓝牙相关开发可以很好的掌握了,通过BluetoothServerSocket可以方便的创建一个蓝牙服务器,使用BluetoothSocket类可以很好的处理连接,今天我们继续上次的内容说下Android下如何管理蓝牙套接字的连接,今天仍然使用 BluetoothSocket类,处理具体的数据流。

在Java上处理数据流很简单,提供了InputSream、OutputSream和字节数组的之间的转化。今天android123将和大家一起说下处理上次遗留的manageConnectedSocket方法的细节,由于蓝牙传输中可能存在中断,所以为了防止阻塞需要开一个工作者线程,相关的示例代码

private class ConnectedThread extends Thread {

private final BluetoothSocket cwjSocket;

private final InputStream cwjInStream;

private final OutputStream cwjOutStream;

public ConnectedThread(BluetoothSocket socket) {

cwjSocket = socket;

InputStream tmpIn = null; //上面定义的为final这是使用temp临时对象

OutputStream tmpOut = null;

try {

tmpIn = socket.getInputStream(); //使用getInputStream作为一个流处理

tmpOut = socket.getOutputStream();

} catch (IOException e) { }

cwjInStream = tmpIn;

cwjOutStream = tmpOut;

}

public void run() {

byte[] buffer = new byte[1024];

int bytes;

while (true) {

try {

bytes = cwjInStream.read(buffer);

mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget(); //传递给UI线程

} catch (IOException e) {

break;

}

}

}

public void write(byte[] bytes) {

try {

cwjOutStream.write(bytes);

} catch (IOException e) { }

}

public void cancel() {

try {

cwjSocket.close();

} catch (IOException e) { }

}

}

对于具体的连接,我们看到在Android平台上使用了Java标准的输入、输出流操作,BluetoothSocket 提供的getInputStream()和getOutputStream()方法可以很好的处理我们具体的数据

android蓝牙开发——发现设备

使用BluetoothAdapter,你能够通过设备发现(device discovery)或者通过查询配对设备的列表来发现远程蓝牙设备。

设备发现(Device discovery)是搜查本地启动蓝牙的设备,然后请求该设备一些信息的一个扫描过程(有时,这被称为“discovering”,“inquiring”或者“scannig”)。但是,本地蓝牙设备只有在启动蓝牙的时候才会对发现请求作出响应。如果一个设备被发现,它将通过共享一些信息,如设备名称、类别和唯一的MAC地址,来对发现请求作出响应。使用这些信息,执行设备发现请求动作的设备就能够初始化一个连接,对被发现的设备发出连接请求。

如果一个远程设备第一次请求连接,那么接收到连接请求的设备会自动发送一个配对请求。如果一个设备已经被配对,那么关于该设备的基本信息(设备名称、类别和MAC地址)将会被保存,并且能用Bluetooth APIs读取。知道了一个远程设备的MAC地址之后,就可以使用该MAC地址在任何时间初始化一个连接,无需再执行device discovery(假设该设备在距离范围之内)。

在被配对和被连接之间是有区别的。被配对意味着两个设备彼此知道对方的存在,有一个连接key被用于认证,能够建立一条加密的连接。被连接意味着设备当前共享一个RFCOMM渠道并且能够传输数据给对方。Android Bluetooth APIs 要求设备在建立RFCOMM连接之前要先配对。配对是在你使用Bluetooth APIs 建立一个加密连接的时候自动执行的。

下面的章节将描述发现已经配对的设备,或者,使用device discovery发现新的设备。

Note: Android-powered devices are not discoverable by default. A user can make the device discoverable for a limited time through the system settings, or an application can request that the user enable discoverability without leaving the application. How to enable discoverability is discussed below.

查询配对设备

在执行device discovery之前,最好在已配对的设备列表中查看所要发现的设备是否已经存在。通过调用getBondedDevices()函数可以获得代表已经配对的设备的BluetoothDevice集合。例如,你可以查询所有已经配对的设备,然后通过一个ArrayAdapter添加和显示每个设备的名字给用户:

view plain

1.Set pairedDevices = mBluetoothAdapt

er.getBondedDevices();

2.// If there are paired devices

3.if (pairedDevices.size() > 0) {

4. // Loop through paired devices

5.for (BluetoothDevice device : pairedDevices) {

6.// Add the name and address to an array adapter to s

how in a ListView

7.mArrayAdapter.add(device.getName() + "/n" + device.g

etAddress()); }}

为了建立一个连接,需要才能够BluetoothDevice对象中获取的是MAC地址。在这个例子中,MAC地址作为显示给用户的ArrayAdapter的一部分存储。只要有需要,可以把MAC地址提取出来。

发现设备

调用startDiscovery()开始设备发现的过程,这个过程是异步的,startDiscovery()方法会立即返回一个boolean的值表示启动是否成功。这个发现过程通常包括大约12秒的查询扫描,之后是在发现的设备中查询其蓝牙名称。

你的应用程序中必须注册一个ACTION_FOUND Intent的BroadcastReceiver,用于接收发现一个蓝牙设备时发出的信息。对于每一个设备,系统将广播ACTION_FOUND的Intent。这个Intent包含了一些附加数据域

——EXTRA_DEVICE和EXTRA_CLASS,分别包含BluetoothDevice类和BluetoothClass类的实例。

下面代码展示了如何注册设备发现时的广播处理函数:

view plain

1.// Create a BroadcastReceiver for ACTION_FOUND

2.private final BroadcastReceiver mReceiver = new Broa

dcastReceiver() { public void onReceive(Context c

ontext, Intent intent)

3.{

4. String action = intent.getAction();

5.// When discovery finds a device

6.if (BluetoothDevice.ACTION_FOUND.equals(action))

{

7.// Get the BluetoothDevice object from the Intent

8. BluetoothDevice device = intent.getParcelableExtr

a( BluetoothDevice.EXTRA_DEVICE);

9.// Add the name and address to an array adapter to s

how in a ListView mArrayAdapter.add(devic

e.getName() + "/n" + device.getAddress());

10. }

11. }};

12.// Register the BroadcastReceiverIntentFilter

13. filter = new IntentFilter(BluetoothDevice.ACTION_F

OUND);

14.registerReceiver(mReceiver, filter);

15.// Don't forget to unregister during onDestroy

为了初始化一个连接,我们需要从BluetoothDevice对象中获取MAC地址。

注意:执行设备发现这个过程,需要花费蓝牙适配器大量资源,是一个重量级过程。如果你发现一个设备并要连接它,最好先调用cancelDiscovery()方法来停止设备发现过程。如果你已经有一个连接,那么执行设备发现过程或导致连接的带宽大幅度减少,所以当你已经有连接的时候最好就不要执行设备发现过程了。

启动发现功能

如果你想要你的设备能被其他设备发现,调用startActivityForResult(Intent,int),传递一个ACTION_REQUEST_DISCOVERABLE action Intent给它。这将发送一个请求给系统设置以启动可被发现模式。可被发现模式一般默认持续120秒,你可以通过给Intent添加一个EXTRA_DISCOVERABLE_DURATION Intent extra来更改可被发现模式的持续时间,这个时间最大是300秒。

请看代码示例:

view plain

1.Intent discoverableIntent = newIntent(BluetoothAdapt

er.ACTION_REQUEST_DISCOVERABLE);

2.discoverableIntent.putExtra(BluetoothAdapter.EXTRA_D

ISCOVERABLE_DURATION, 300);

3.startActivity(discoverableIntent);

Figure 2: The enabling discoverability dialog.

一个对话框将会出现,请求用户权限来启动设备的可被发现模式,如Figure 2

所示。如果用户点击“Yes”,那么设备在设定的时间内将是可被发现的。你的Activity将调用onActivityResult()回调函数。如果用户点击“No”,那么将产生一个错误,结果码将是Activity.RESULT_CANCELLED。

相关主题