蓝牙开发基本概念了解:
RFCOMM协议
RFCOMM是一个简单传输协议,其目的是针对如何在两个不同设备上的应用之间保证一条完整的通信路径,并在它们之间保持一通信段。
RFCOMM是为了兼容传统的串口应用,同时取代有线的通信方式,蓝牙协议栈需要提供与有线串口一致的通信接口而开发出的协议。RFCOMM协议提供对基于L2CAP协议的串口仿真,基于ETSI07.10。可支持在两个BT设备之间同时保持高达60路的通信连接。
MAC硬件地址
MAC(MediaAccess Control,介质访问控制)MAC地址是烧录在网卡NIC里的.MAC地址,也叫硬件地址,是由48比特长(6字节),16进制的数字组成。
蓝牙的建立过程是一个复杂的过程,即使有过相当一段工作和使用经验的人,如果不仔细去了解还是理解不全。
平时我们用蓝牙耳机听音乐,和不同的设备共享文件,打电话等,都有一个配对--连接--传输数据的过程。
配对,其实就是一个认证的过程。
为什么不配对便无法建立连接?
蓝牙设备之间的通信主要包括了以下几个步骤:
0.打开蓝牙开关
1.设置蓝牙设备可见性(主叫模式)
2.搜索蓝牙设备(比较常见的方式是用ListView列举出已搜索到的蓝牙设备)
3.绑定(配对)蓝牙设备
4.连接蓝牙设备
5.数据交互
6.断开蓝牙连接
7.断开蓝牙绑定(配对)
8.关闭蓝牙开关
PS:在这里可以大家思考下,就拿手机与智能终端(比如蓝牙血压计),谁是Client谁是Server角色?为什么呢?
下面列举出常见类:
BluetoothAdapter类:代表了一个本地的蓝牙适配器。它是所有蓝牙交互的的入口点。利用它你可以发现其他蓝牙设备,查询绑定了的设备,使用已知的MAC地址实例化一个蓝牙设备和建立一个BluetoothServerSocket(作为服务器端)来监听来自其他设备的连接。
BluetoothDevice类:代表了一个远端的蓝牙设备,使用它请求远端蓝牙设备连接或者获取远端蓝牙设备的名称、地址、种类和绑定状态(其信息是封装在BluetoothSocket中)。
BluetoothSocket类:代表了一个蓝牙套接字的接口(类似于TCP中的套接字),它是应用程序通过输入、输出流与其他蓝牙设备通信的连接点。
BlueboothServerSocket类:代表打开服务连接来监听可能到来的连接请求(属于server端),为了连接两个蓝牙设备必须有一个设备作为服务器打开一个服务套接字。当远端设备发起连接连接请求的时候,并且已经连接到了的时候,BlueboothServerSocket类将会返回一个BluetoothSocket。
操作蓝牙的权限:
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permissionandroid:name="android.permission.BLUETOOTH" />
Framework层:
packages/apps/Settings/src/com/android/settings/。这里是蓝牙UI的入口,基本上有关蓝牙UI上的处理都是在这个目录的bluetooth文件夹下实现的。frameworks/base/core/java/android/bluetooth。这个文件基本属于API的类型,向上层UI提供了所需要的API。
Jni层:frameworks/base/core/jni。(这里还没有深入去看过)
最好的入门示例:E:\android-sdks\samples\android-17\BluetoothChat
借用例子中的部分代码:
获取本地蓝牙适配器:如果返回null则表明该设备不支持蓝牙功能;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
在界面中请求用户打开蓝牙;
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
静默的后台打开蓝牙;
BluetoothAdapter.enable();
搜索蓝牙设备(们):
private void ensureDiscoverable() {
if(D) Log.d(TAG, "ensure discoverable");
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
静默的后台搜索:
BluetoothAdapter.startDiscover();
查找蓝牙设备,此时注册一个广播接收器用于接收查找的结果
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
广播接收到的结果,这里仅注册了ACTION_FOUND与ACTION_DISCOVERY_FINISH。
实际上可以注册更多内容,详情可以进入BluetoothDevice类中查看。
// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
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);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}else{/**you can create bond here.*/}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
// TODO ...
}
}
}
};
连接蓝牙设备并建立RFCCOM
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID_INSECURE);
}
mmSocket.connect();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
需要注意的事项:
不要在Discovery过程中,尝试去配对、连接蓝牙设备。
Because discovery is a heavyweight procedure for the Bluetooth adapter, this method should always be called before attempting to connect to a remote device withandroid.bluetooth.BluetoothSocket.connect()
. Discovery is not managed by the Activity, but is run as a system service, so an application should always call cancel discovery even if it did not directly request a discovery, just to be sure.
稍后附上几个经典的demo:
待补充……