现在的位置: 首页 > 综合 > 正文

蓝牙

2013年01月26日 ⁄ 综合 ⁄ 共 7968字 ⁄ 字号 评论关闭

翻译自Android Developer,方便感兴趣的同学阅读。原址:http://developer.android.com/guide/topics/connectivity/bluetooth.html

Android平台支持一系列的蓝牙网络,蓝牙是一种允许多个蓝牙设备间交换数据的技术。Android的应用框架提供了一些蓝牙API访问蓝牙的所有功能。这些API允许应用程序无线连接到其他蓝牙设备,支持点到点或多点连接。

使用蓝牙API,一个应用程序可以拥有如下功能:

  • 扫描其他蓝牙设备;
  • 查询周围的蓝牙设备并进行配对;
  • 创建RFCOMM信道;(RFCOMM自己百度吧)
  • 通过发现服务,连接到其他设备;
  • 发送数据到其他拥有蓝牙的设备,或者从其他设备接收数据;
  • 管理多个蓝牙连接。

本文档描述怎样使用典型的蓝牙(当前主要使用的蓝牙,还有一种耗电量低的蓝牙类型)。经典的蓝牙设备适合于电量敏感设备之间数据流的传输,例如不同的android设备之间。为了满足蓝牙设备的低功耗要求,Android 4.3(API Level 18)提供了支持蓝牙低功耗技术的API。想知道更多,查看蓝牙低功耗Bluetooth
Low Energy

基本类The Basics)


本文档详细描述如何使用Android提供的蓝牙设备API完成蓝牙设备间通讯主要的四个常用操作:设置蓝牙、发现已经配对的蓝牙或者可用的附近的蓝牙设备、已经连接的设备、设备间传输数据。

所有的蓝牙相关的API都在包android.bluetooth里面。下面是你在创建蓝牙连接时会用到的一些类和接口的简介:

BluetoothAdapter
表示本地的蓝牙适配器(无线蓝牙)。BluetoothAdapter是所有蓝牙交互的入口。通过适配器,你可以发现其他蓝牙设备、查询有效范围内或者已经适配的蓝牙设备列表、使用MAC地址初始化一个BluetoothDevice、创建监听来自其他蓝牙设备的BluetoothServiceSocket对象。
BluetoothDevice
表示一个远程蓝牙设备。通过该类,通过BluetoothSocket请求一个远程设备连接,或者查询设备的信息,例如,设备名、地址、类、状态等。
BluetoothSocket
表示蓝牙Socket(类似于TCP Socket)的接口。应用程序通过该类来与其他蓝牙设备交换数据,使用输入流和输出流的方式。
BluetoothServerSocket
表示一个开放的服务接口,用来监听进入的请求(类似TCP的ServerSocket)。为了连接两个Android设备,一个设备必须使用该类打开一个服务端口。当一个远程蓝牙设备发送一个请求到这个设备的时候,而且同意该请求时,BluetoothServerSocket将会返回一个已连接的BluetoothSocket
BluetoothClass
描述蓝牙设备的常用特色和功能。这是一个只读的设备集合,该集合定义了设备主要和次要的设备类和他提供的服务。然而,它并不是可靠的描述了设备支持的所有的蓝牙参数和服务,但是作为某种设备类型的提示很有用(原句:However, this does not reliably describe all Bluetooth
profiles and services supported by the device, but is useful as a hint to the device type.翻译的不太对,求指点)
BluetoothProfile
(Bluetooth规范中定义了Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。)
表示蓝牙协议的接口。蓝牙协议定义了负责设备间基于蓝牙通讯的具体无线接口。比如蓝牙免提设备等。想要知道跟多的蓝牙设备类型,查看Working with Profiles
BluetoothHeadset
提供对在移动电话中使用的蓝牙头戴式设备的支持(比如蓝牙耳机)。该类包含了蓝牙头戴式设备和免提设备(v1.5)。
BluetoothA2dp
Defines how high quality audio can be streamed from one device to another over a Bluetooth connection. "A2DP" stands for Advanced Audio Distribution Profile.
定义了通过蓝牙连接,两个设备间可以传输多高质量的音频。“A2DP”表示高级音频传输规范。(Advanced Audio Distribution Profile
BluetoothHealth
表示健康设备规范代理,可以控制蓝牙设备。(类似于健康蓝牙称、蓝牙手表等穿戴式设备,检测心跳之类的设备)
BluetoothHealthCallback
实现BluetoothHealth回调的抽象类。为了接受到应用程序的登记状态和蓝牙信道的状态,你必须继承并实现回调函数来对这些状态进行处理。
BluetoothHealthAppConfiguration
三方的蓝牙应用程序需要进行此设置来与远程的蓝牙健康设备进行通信。
BluetoothProfile.ServiceListener
通知BluetoothProfile进程间通信的接口,当他们与服务器连接上或者中断连接(也就是内部服务已经在某个设备上运行了,翻译不对啊)

蓝牙授权 Bluetooth Permissions


为了在你的应用程序中使用蓝牙,你必须声明蓝牙权限BLUETOOTH
你需要这个权限来执行任何蓝牙通讯,例如请求一个连接、接收一个连接、传输数据。

如果你需要你的应用程序能够发现周围的设备或者修改蓝牙设置,你还必须声明BLUETOOTH_ADMIN权限。

大部分应用程序需要此唯一的权限来实现搜索本地蓝牙设备的功能。该权限还可以授权应用程序在用户要求下修改蓝牙设置。注意:如果你在应用中引入了BLUETOOTH_ADMIN权限,那么你必须同样要声明引用BLUETOOTH权限。

在应用中声明这些权限如下所示:

<manifest ... >
  
<uses-permission android:name="android.permission.BLUETOOTH" />
  ...
</manifest>

 <uses-permission>中查看更多如何在应用中声明权限的信息。

Setting Up Bluetooth


图1 开启蓝牙对话框.

设置蓝牙

在你的应用可以通过蓝牙通讯之前,你必须确认蓝牙在设备上可用,如果可用,还需要保证蓝牙已经打开了。

如果该设备不支持蓝牙,那么你必须在应用中关掉所有蓝牙相关的特色功能。如果支持,但是没有打开,你可以子啊应用中请求用户打开蓝牙。该步骤可以使用BluetoothAdapter在两步之内完成。

  1. 获取蓝牙适配器

    所有的蓝牙活动都需要一个BluetoothAdapter
    使用静态的
    getDefaultAdapter()方法获取蓝牙适配器(BluetoothAdapter)。该方法将返回一个蓝牙适配器(BluetoothAdapter),该对象代表设备自己的蓝牙适配器(蓝牙无线连接)。有一个针对整个系统的蓝牙适配器,你可以使用这个对象与其交互。如果getDefaultAdapter()返回null,那么该设备不支持蓝牙,到此结束了。代码如下:

 BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

if (mBluetoothAdapter == null) {
    
// Device does not support Bluetooth设备不支持蓝牙,就是说没有蓝牙
}

  1.  开启蓝牙
    下一步,你需要开启蓝牙。调用函数isEnabled()检查当前蓝牙是否开启。
    如果返回false,那么说明蓝牙是关闭的。如果请求开启蓝牙,使用带动作
    ACTION_REQUEST_ENABLE的意图,调用startActivityForResult()函数。这个操作将通过系统设置(而不用中断自己的应用)发出开启蓝牙的请求。代码如下:
    if (!mBluetoothAdapter.isEnabled()) {
        
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult
    (enableBtIntent, REQUEST_ENABLE_BT);
    }

    一个要求用户授权的对话框将显示出来,如图1所示。如果用户点击“Yes”,系统将会开启蓝牙,并且界面将会回到你的应用程序中。

    传递给函数 startActivityForResult()的常量通常定义为一个大于零的整数,
    系统将返回该值,在函数onActivityResult()中,包含在变量
    requestCode中。

    如果开启蓝牙成功,你的活动将在回调函数onActivityResult()中,收到表示成功的返回码RESULT_OK。如果由于某个错误(比如用户选择“No”,拒绝了授权),导致蓝牙并没有开启,那么将会返回错误码RESULT_CANCELED

还有另外的途径,你的应用可以监听带有动作ACTION_STATE_CHANGED(蓝牙状态改变)的广播意图,这个意图在蓝牙状态改变的时候被系统广播。该广播包含两个属性EXTRA_STATEEXTRA_PREVIOUS_STATE,相对应的包含了蓝牙的新状态和旧状态。这两个属性的可能值为STATE_TURNING_ONSTATE_ONSTATE_TURNING_OFF或者STATE_OFF。在你的应用程序运行的时候,接收该广播,可以很方便的获取到蓝牙状态的改变。

提示:开启可发现功能,将自动启动蓝牙。如果你决定一直开启设备的可发现功能在执行蓝牙活动之前,你可以跳过第二步。阅读下面与enabling
discoverability
相关的内容,获取跟多信息。

搜寻设备(Finding Devices)

使用蓝牙适配器(BluetoothAdapter),你可以通过寻找设备或者从已配对的设备列表中,找到远端的蓝牙设备。

搜寻设备是一个扫描流程,它会寻找附近的打开了蓝牙的设备,并且从这些设备中获取一些信息(我们也称之为发现、询问、扫描)。然而,只有当某蓝牙设备被设置成可发现时,才能够被其他蓝牙设备搜寻到。当一台蓝牙设备被设置为可发现时,它才会对附近的蓝牙扫描请求回应,回应信息包含设备名、类、唯一的MAC地址。通过这些信息,两台设备之间才能够初始化设备间的连接。

一旦与远程设备的连接第一次建立,一个配对请求就会自动显示在用户面前。当一台设备配对后,设备的基本信息(设备名、类、MAC地址等)机会被保存下来,而且可以使用蓝牙API了。使用已知的远程设备的MAC地址(在配对的时候就远程地址已经保存了),可以在任何时候初始化一个连接而不用再次搜寻了(译者注:我们假设设备还在有效范围内,另外一种情况是设备超出了有效范围,但是同样会在蓝牙设备的列表中)。

记住,被配对和被连接是不同的。被配对意味着两台设备都知晓另外一台设备的存在,有用来互相授权的相同的分享链接码(可能就是配对码了?),而且还可以建立连接两者的加密连接。被连接表示设备间分享同一个RFCOMM信道,并且可以互相传送数据(译者注:比如传个mp3啥的)。目前的Android平台的蓝牙API要求在建立RFCOMM信道之前先配对(配对动作会在你使用蓝牙API初始化一个加密连接的时候自动调用)。

下面的小结将描述如何发现已配对的设备,或者使用搜索设备功能发现新设备。

注意:Android蓝牙设备默认是不可发现的。用户可以在系统设置里面设定限定时间的设备可发现属性,或者应用程序可以要求用户授权在该应用内蓝牙都是可发现的。下面将会讨论如何使设备可发现(enable
discoverability
)。

询问已配对设备(Querying paired devices)

在执行搜索设备之前,最好先查询已配对设备列表,看看我们要连接的设备是否已经在列表中。可以通过函数getBondedDevices()来达到这个目的。
这个函数将返回一系列包含已配对蓝牙设备(
BluetoothDevice)的列表。例如,你可以查询所有已配对过的设备,并使用ArrayAdapter来显示出来,如下代码所示:

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// 如果有已配对过的设备
if (pairedDevices.size() > 0) {
    
// 循环该列表
    
for (BluetoothDevice device : pairedDevices) {
        //将名称和地址加入一个数组适配器,并显示在一个列表视图中
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    
}
}

为了初始化一个连接,我们唯一需要的是从BluetoothDevice 中获取的MAC地址。在这个例子中,地址被作为数组适配器的一部分被显示给用户了。MAC地址后面可以用来精确的初始化一个连接。在Connecting
Devices
节中,你可以学到更多关于如何创建连接的知识。

搜索设备(Discovering devices)

简单的调用函数startDiscovery()就可以开始搜索附近的蓝牙设备了。该过程是一个异步过程,并且当搜索过程成功启动之后,就会立即返回一个布尔值的变量。该搜索过程通常包含12秒钟的查询扫描inquiry
scan
,不懂翻啊,随后包含一个返回所有蓝牙设备名称的呼叫扫描(page scan,不懂翻啊)。

当发现一个设备之后,系统就会发送广播,所以你的应用程序必须包含一个含有ACTION_FOUND意图的广播接收器来接收信息。对每个已发现设备来说,系统会广播ACTION_FOUND意图。该意图还携带有额外的值域:EXTRA_DEVICEEXTRA_CLASS。分别对应包含一个蓝牙设备(BluetoothDevice )和一个蓝牙类(BluetoothClass)。比如,下面的代码就显示如何注册一个广播接收器,来处理设备发现时系统发送的广播。

 
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    
public void onReceive(Context context, Intent intent) {
        
String action = intent.getAction();
        
// When discovery finds a device
        
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            
// Get the BluetoothDevice object from the Intent
            
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            
// Add the name and address to an array adapter to show in a ListView
            mArrayAdapter
.add(device.getName() + "\n" + device.getAddress());
        
}
    
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver
(mReceiver, filter); //
Don't forget to unregister during onDestroy

为了初始化一个连接,我们需要从BluetoothDevice对象中取得MAC地址。在这个例子中,MAC地址作为显示给用户的部分数据,被保存在数组适配器中了。该MAC地址随后被用来初始化连接。Connecting
Devices
节中,你可以学到更多关于如何创建连接的知识。

注意:执行搜索操作对于蓝牙适配器来说是一个非常耗时的操作,而且会消耗很多资源。一旦你找到了需要连接的设备,在视图连接之前,最好立刻停止搜索,停止搜索可以使用cancelDiscovery()函数。同样地,如果你同一个设备已经连接上,如果再开启搜索,将会减少已有连接的可用带宽,所以当连接的时候,最好不要执行扫描操作。

使设备可发现(Enabling discoverability)

使设备可发现(也就是说允许设备被扫描到)

如果你想允许设备被扫描到,调用startActivityForResult(Intent,
int)
函数,设置其中的意图的动作为ACTION_REQUEST_DISCOVERABLE。该函数将通过系统设置将设备变为可被发现(该操作不需要退出你的应用界面),并保持12秒钟的该状态。可以通过该意图中额外的值域EXTRA_DISCOVERABLE_DURATION 定义不同的可被发现时间。应用程序可以设置的最大时间为3600秒(1小时),
值0表示设备一直可被发现。任何大于3600秒或者小于0的值,都会被默认为120秒。比如下面的代码将会设置时间为300秒:

Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent
.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity
(discoverableIntent);
Figure 2: 开启授权允许发现对话框。

当设置这个时间的时候,如图2的对话框会弹出提示用户。如果用户选择“Yes”,设备将变为可发现状态并保持300秒。你的应用程序中的当前活动将会回调函数onActivityResult(),返回的值就是设备设置的可发现时间。如果用户选择“No”,或者有一个错误发生时,返回值就是RESULT_CANCELED

注意:如果蓝牙为开启,那么设置设备为可发现的时候就会自动开启蓝牙。(一般是在应用程序中才会有这个流程,系统设置中都是先开启蓝牙,再设置可被发现的)

在指定时间内,设备都会保持可被发现状态。如果你想在该状态发生改变的时候收到通知,只需要使用包ACTION_SCAN_MODE_CHANGED含动作的意图注册一个广播接收器即可。该意图包含额外的值域 EXTRA_SCAN_MODEEXTRA_PREVIOUS_SCAN_MODE,这两个分别告诉新的和旧的扫描模式。扫描模式的可能值有SCAN_MODE_CONNECTABLE_DISCOVERABLE(两台设备都是可发现状态)

抱歉!评论已关闭.