第一步:声明Bluetooth Permissions

    <!-- 设置蓝牙访问权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

第二步:获取BluetoothAdapter,判断该设备是否支持蓝牙

        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
// 说明该设备不支持蓝牙
}

第三步:检查当前的蓝牙是否开启

if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
// 不做提示,强行打开
// mAdapter.enable();
}

如果是第一种方式:会出现提示弹窗

A dialog will appear requesting user permission to enable Bluetooth, as shown in Figure 1. If the user responds "Yes," the system will begin to enable Bluetooth and focus will return to your application once the process completes (or fails).

If enabling Bluetooth succeeds, your Activity will receive the RESULT_OK result code in the onActivityResult() callback. If Bluetooth was not enabled due to an error (or the user responded "No") then the result code will be RESULT_CANCELED.

    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
// 蓝牙已经开启
Log.d("h_bl", "蓝牙已经开启完毕");
String bluetoothName = bluetoothAdapter.getName(); // 获取本地蓝牙名称
String bluetoothAddress = bluetoothAdapter.getAddress(); // 获取本地蓝牙地址
tv_bluetoothName.append(bluetoothName);
tv_bluetoothAddress.append(bluetoothAddress);
} else {
Log.d("h_bl", "蓝牙开启失败");
}
}
super.onActivityResult(requestCode, resultCode, data);
}

其中,

private int REQUEST_ENABLE_BT = 1; // 蓝牙打开的请求码

Optionally, your application can also listen for the ACTION_STATE_CHANGED broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed. This broadcast contains the extra fields EXTRA_STATE and EXTRA_PREVIOUS_STATE, containing the new and old Bluetooth states, respectively. Possible values for these extra fields areSTATE_TURNING_ONSTATE_ONSTATE_TURNING_OFF, and STATE_OFF. Listening for this broadcast can be useful to detect changes made to the Bluetooth state while your app is running.

可选的,你的应用可以监听ACTION_STATE_CHANGED广播intent,当系统蓝牙状态改变将会发起这个广播,这个广播包含了EXTRA_STATE和EXTRA_PREVIOUS_STATE额外的字段,包含了新的和旧的蓝牙状态分别的,可能 有STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF和STATE_OFF可能的值,监听广播能够 对于检测蓝牙状态改变是有用的。  --- 用来判断蓝牙是否开启完毕

第3.1步:检查当前的蓝牙是否开启完毕

// 蓝牙状态改变的广播
private final BroadcastReceiver bluetoothState = new BroadcastReceiver() { @Override
public void onReceive(Context context, Intent intent) {
String stateExtra = BluetoothAdapter.EXTRA_STATE;
int state = intent.getIntExtra(stateExtra, -1);
switch (state) {
case BluetoothAdapter.STATE_TURNING_ON: // 蓝牙打开中 break;
case BluetoothAdapter.STATE_ON: // 蓝牙打开完成 break;
case BluetoothAdapter.STATE_TURNING_OFF: // 蓝牙关闭中 break;
case BluetoothAdapter.STATE_OFF: // 蓝牙关闭完成 break;
} }
};
// 蓝牙状态改变的广播
IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(bluetoothState,new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); // 蓝牙状态改变的广播

Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability, below.

提示:启用程序会自动启用蓝牙。如果你打算开启设备的可见性,可以跳过上面的2步。阅读关于启用可发现,下面。   --- 设置蓝牙的可见性,就把Intent添加值,看第五步

第四步:寻找其他设备

Using the BluetoothAdapter, you can find remote Bluetooth devices either through device discovery or by querying the list of paired (bonded) devices.

Device discovery is a scanning procedure that searches the local area for Bluetooth enabled devices and then requesting some information about each one (this is sometimes referred to as "discovering," "inquiring" or "scanning"). However, a Bluetooth device within the local area will respond to a discovery request only if it is currently enabled to be discoverable. If a device is discoverable, it will respond to the discovery request by sharing some information, such as the device name, class, and its unique MAC address. Using this information, the device performing discovery can then choose to initiate a connection to the discovered device.

Once a connection is made with a remote device for the first time, a pairing request is automatically presented to the user. When a device is paired, the basic information about that device (such as the device name, class, and MAC address) is saved and can be read using the Bluetooth APIs. Using the known MAC address for a remote device, a connection can be initiated with it at any time without performing discovery (assuming the device is within range).

Remember there is a difference between being paired and being connected. To be paired means that two devices are aware of each other's existence, have a shared link-key that can be used for authentication, and are capable of establishing an encrypted connection with each other. To be connected means that the devices currently share an RFCOMM channel and are able to transmit data with each other. The current Android Bluetooth API's require devices to be paired before an RFCOMM connection can be established. (Pairing is automatically performed when you initiate an encrypted connection with the Bluetooth APIs.)

The following sections describe how to find devices that have been paired, or discover new devices using 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.

使用BluetoothAdapter,你能够打开可见性的设备(搜索到的蓝牙设备)和已经配对的的设备列表。

设备发现是一个扫描程序,搜索本地区具有蓝牙功能的设备,然后请求一些信息(这是有时被称为“发现中”,“查询中”或“扫描中”)。然而,只有局域网内的蓝牙设备处于能够被发现的状态中,才能响应别的设备发送的发现请求。如果一个设备是可以被发现的,它会响应发现请求并共享一些信息,比如设备名称、类别,并以唯一的MAC地址。使用此信息,该设备执行发现,然后选择启动一个初始化连接到设备。

当第一次去连接远程设备的时候,会提交一个配对请求给用户确认。当设备配对时,一些基本的信息会被保存,并可以通过APIs去读取这些信息(such as the device name, class, and MAC address)。使用一个已知的MAC地址去连接设备的时候,无论该设备是否处于发现状态,都可以去连接。(但设备是在范围内)。

记住配对和连接之间的区别。已经配对的意味着两个设备是互相认识对方的存在,已经有了一个用来认证的共享的key,然后可以建立一个加密的连接。而连接是说设备已经建立了RFCOMM通道,并可以交换数据。现在的Android Bluetooth APIs 需要在建立RFCOMM通道之前,需要先配对。(使用Bluetooth APIs初始化加密连接的时候,会自动匹配。)

下面的章节将介绍如何找到已配对的设备,或者使用设备发现发现新设备。
Note: Android设备默认是不可发现的。用户可以通过系统设置使设备能在有限的时间内被发现,或 应用程序可以要求用户在没有离开该应用的时候使蓝牙可见。

4.1 找到已经配对的设备

Before performing device discovery, its worth querying the set of paired devices to see if the desired device is already known. To do so, call getBondedDevices(). This will return a Set of BluetoothDevices representing paired devices. For example, you can query all paired devices and then show the name of each device to the user, using an ArrayAdapter:

在执行“发现设备”之前,先获取到已经配对设备的set是很有值得的。调用getBondedDevices()即可,会返回一组已配对的set。例如,你可以查询已配对的设备,并利用ArrayAdapter去显示它们的名字。

        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
Toast.makeText(getApplicationContext(), "没有找到已匹对的设备!", Toast.LENGTH_SHORT).show();
}

All that's needed from the BluetoothDevice object in order to initiate a connection is the MAC address. In this example, it's saved as a part of an ArrayAdapter that's shown to the user. The MAC address can later be extracted in order to initiate the connection. You can learn more about creating a connection in the section about Connecting Devices.

通过BluetoothDevice的MAC地址去初始化连接,这里只是显示给用户看。MAC可以被提取,然后去初始化连接。你可以在 Connecting Devices章节学习到更多创建连接。

4.2 发现设备

调用startDiscovery()函数后,系统将扫描12秒,返回找到的蓝牙设备。我们需用广播来接收。

For each device, the system will broadcast the ACTION_FOUND Intent. This Intent carries the extra fields EXTRA_DEVICE and EXTRA_CLASS, containing a BluetoothDevice and a BluetoothClass, respectively. For example, here's how you can register to handle the broadcast when devices are discovered:

每发现一个设备,系统就会发送ACTION_FOUND Intent.的广播,这个Intent携带额外的字段EXTRA_DEVICE and EXTRA_CLASS,包含a BluetoothDevice and a 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

其中,需要调用

// 扫描蓝牙设备
btAdapter.startDiscovery();

警告:Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery() before attempting a connection。

Caution: Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources. Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery() before attempting a connection. Also, if you already hold a connection with a device, then performing discovery can significantly reduce the bandwidth available for the connection, so you should not perform discovery while connected.

连接设备之前,要调用cancelDiscovery(),以便节约资源。并且不要执行连接的时候,去执行发现操作。

另外,需要取消广播:

    @Override
protected void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy();
}

第五步:设备的可发现时间设定,默认是120S。

Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

The maximum duration an app can set is 3600 seconds, and a value of 0 means the device is always discoverable. Any value below 0 or above 3600 is automatically set to 120 secs)

一个应用程序可以设置最大持续时间为3600秒,填写 0 的值表示设备总是发现。任何值低于0或高于3600自动设置为120秒。

会提示弹窗

Note: If Bluetooth has not been enabled on the device, then enabling device discoverability will automatically enable Bluetooth.

如果蓝牙尚未启用的设备,并使设备可发现将自动启用蓝牙。

The device will silently remain in discoverable mode for the allotted time. If you would like to be notified when the discoverable mode has changed, you can register a BroadcastReceiver for the ACTION_SCAN_MODE_CHANGED Intent. This will contain the extra fields EXTRA_SCAN_MODE andEXTRA_PREVIOUS_SCAN_MODE, which tell you the new and old scan mode, respectively. Possible values for each areSCAN_MODE_CONNECTABLE_DISCOVERABLESCAN_MODE_CONNECTABLE, or SCAN_MODE_NONE, which indicate that the device is either in discoverable mode, not in discoverable mode but still able to receive connections, or not in discoverable mode and unable to receive connections, respectively.

You do not need to enable device discoverability if you will be initiating the connection to a remote device. Enabling discoverability is only necessary when you want your application to host a server socket that will accept incoming connections, because the remote devices must be able to discover the device before it can initiate the connection.

可以接受“发现模式”的改变的广播,会接收到ACTION_SCAN_MODE_CHANGED Intent,包含额外的字段EXTRA_SCAN_MODE andEXTRA_PREVIOUS_SCAN_MODE,描述了新的和旧的扫描模式。其值可能是SCAN_MODE_CONNECTABLE_DISCOVERABLESCAN_MODE_CONNECTABLE, or SCAN_MODE_NONE。分别代表设备处于在发现模式;不可发现模式但仍能接收连接;不可发现模式和无法接收连接。

你不需要非得使设备可见,如果你初始化去连接到远程设备的时候。当你作为主机 host a server socket,让别的设备连接进来的时候,就必须是处于可见模式!因为远程设备要发现主机,才可以初始化连接。

Android Developer -- Bluetooth篇 开发实例之一 扫描设备的更多相关文章

  1. Android Developer -- Bluetooth篇 开发实例之四 API详解

    http://www.open-open.com/lib/view/open1390879771695.html 这篇文章将会详细解析BluetoothAdapter的详细api, 包括隐藏方法, 每 ...

  2. Android Developer -- Bluetooth篇 开发实例之三 管理连接

    Managing a Connection When you have successfully connected two (or more) devices, each one will have ...

  3. Android Developer -- Bluetooth篇 开发实例之二 连接设备

    连接设备 In order to create a connection between your application on two devices, you must implement bot ...

  4. Bluetooth篇 开发实例之九 和蓝牙模块通信

    首先,我们要去连接蓝牙模块,那么,我们只要写客户端的程序就好了,蓝牙模块就相当于服务端. 连接就需要UUID. #蓝牙串口服务SerialPortServiceClass_UUID = ‘{00001 ...

  5. Bluetooth篇 开发实例之八 匹配

    自己写的App匹配蓝牙设备,不需要通过系统设置去连接. 匹配和通信是两回事. 用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对和解除配对,但是这两项功能的函数没有在SDK ...

  6. Bluetooth篇 开发实例之七 匹配&UUID

    匹配和通信是两回事. 1.用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对和解除配对,但是这两项功能的函数没有在SDK中给出.但是可以通过反射来获取. 知道这两个API的 ...

  7. Bluetooth篇 开发实例之十 官网的Bluetooth Chat sample app.

    运行的时候,会报错: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Action ...

  8. Android Developer -- Bluetooth篇 概述

    Bluetooth 安卓平台支持蓝牙网络协议栈,它允许设备与其他蓝牙设备进行无线交换数据.应用程序框架通过安卓蓝牙APIs提供访问蓝牙功能.这些APIs使应用程序通过无线连接到其他蓝牙设备,使点对点和 ...

  9. Bluetooth篇 开发实例之十一 官网的Bluetooth Chat sample的bug

    当没有匹配的设备和没有找到可用设备的时候. // If there are paired devices, add each one to the ArrayAdapter if (pairedDev ...

随机推荐

  1. RelativeLayout布局属性

    Android RelativeLayout属性 // 相对于给定ID控件 android:layout_above 将该控件的底部置于给定ID的控件之上; android:layout_below ...

  2. Error “can't use subversion command line client : svn” Probably the path to Subversion executable is wrong

    错误提示如图. 大概意思就是SVN路径不对 解决方法如下: 首先下载Subversion 1.8.13(1.8) 下载链接(https://www.visualsvn.com/downloads/) ...

  3. 系统编程--高级IO

    1.非阻塞I/O 非阻塞I/O使我们可以调用不会永远阻塞的I/O操作,例如open,read和write.如果这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去.对于一个给定的描述符 ...

  4. Spring 学习笔记(六)—— AOP的简单理解

    系统中的业务可以分为核心关注点和横切关注点. 核心关注点时业务处理的主要流程,而横切关注点是与核心业务无关但更为通用的业务. 各个横切关注点离散地穿插于核心业务之中,导致系统地每一个模块都与这些业务具 ...

  5. android 继承ListView实现滑动删除功能.

    在一些用户体验较好的应用上,可以经常遇见   在ListView中  向左或向右滑动便可删除那一项列表. 具体实现  则是继承ListView实现特定功能即可. (1). 新建 delete_butt ...

  6. iOS runLoop 理解

    目录 概述 run loop modes 一.概述 run loop叫事件处理循环,就是循环地接受各种各样的事件.run loop是oc用来管理线程里异步事件的工具.一个线程通过run loop可以监 ...

  7. Lambda表达式使用2

    1.概述 本篇主要介绍lambda中常用的收集器,收集器的作用就是从数据流中生成需要的数据接口. 最常用的就是Collectors.toList(),只要将它传递给collect()函数,就能够使用它 ...

  8. 【CZY选讲·Yjq的棺材】

    题目描述 Yjq想要将一个长为宽为的矩形棺材(棺材表面绝对光滑,所以棺材可以任意的滑动)拖过一个L型墓道. 如图所示,L型墓道两个走廊的宽度分别是和,呈90°,并且走廊的长度远大于. 现在Hja ...

  9. Educational Codeforces Round 42 (Rated for Div. 2) C

    C. Make a Square time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  10. idea创建maven项目需要注意的问题

    idea创建maven项目之后,我从deployment中看到报部署错误的问题,下图是解决问题的办法如下图所示: