前言
在众多的消费电子类产品中,蓝牙作为一种简易的通讯方式,因此功耗小、体积小、成本低等优势,被广泛的应用于耳机、音箱、汽车及医疗器械等领域。作为一种即时技术,不需要特定的器械安装,固定的设施,而且得益于linux和Android的开源特性,被很多厂家所青睐。
此次分享摘自于项目中的蓝牙部分,主要用于实现蓝牙耳机的功能,包括电话、音乐、EQ、配对等操作。将分篇章对于android蓝牙的开发作介绍说明,并辅以代码、注释、通信协议等篇章,力求囊括android简易的开发流程。
一、Android的蓝牙系统
1. Android的蓝牙功能
Android包含了对蓝牙的协议支持,提供了访问蓝牙功能的API,因此可以很容易的实现:
1) 扫描并连接其他蓝牙设备;
2)查询本地的蓝牙适配器;
3)数据通信;
4)管理蓝牙连接;
2. Android蓝牙相关的类及权限
1)Bluetooth权限
//android的蓝牙开发首先需要在AndroidManifest.xml中开通以下权限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
2)BluetoothAdapter;
蓝牙适配器,在蓝牙Bluetoothsocket连接前,都需要不断的操作,通过此类用户可以执行基本的蓝牙操作,如初始化设备的搜索,查询,初始化一个BluetoothDevice类,创建一个BluetoothServerSocket类以监听其他设备对本机的连接请求等。
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();//建立本地适配器
startDiscovery();//开始远程设备的搜寻,注册ACTION_DISCOVERY_STARTED和ACTION_DISCOVERY_FINISHED,确认搜寻结果,返回值为true or false
cancelDiscovery();//取消当前的设备搜索进程,成功返回 true or false
disable();//关闭本地蓝牙适配器,异步调用的方法,用户通过监听ACTION_STATE_CHANGED的值来获取随后的适配器的状态,成功返回 true or false
enable();//打开本地蓝牙适配器,
//为实现友好的提示用户打开蓝牙,建议使用如下方法
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 0x01);//0x01代表result_code,可以自行设定
getAddress();//返回本地蓝牙适配器的硬件地址,string,例:00:22:44:AA:CC:DD
getName();//获取本地蓝牙适配器的蓝牙名称,即可以在别的蓝牙设备上搜索到的名字
setName();//设置蓝牙或者本地蓝牙适配器的名称
getBondedDevices();//返回已经匹配(绑定)到本地蓝牙适配器的BluetoothDevice类的对象集合;
getRemoteDevice(String address);//根据蓝牙地址获取一个BluetoothDevice对象
checkBluetoothAddress(String address);//验证蓝牙地址是否有效,字母必须全部为大写,成功返回 true or false
listenUsingRfcommWithServiceRecord(String name, UUID uuid);//根据name,uuid创建一个正在监听的安全的带有服务记录的RFCOMM蓝牙端口,并返回一个BluetoothServerSocket
3)BluetoothServerSocket
蓝牙设备之间的连接,也可以理解为服务器端与客户端的连接,其通信的过程可以理解为拥有相同的RFCOMM通道下分别拥有一个连接的BluetoothSocket,然后通过read、write字节流的方法进行通信。在服务器端,使用BluetoothServerSocket类来创建一个监听服务端口,当调用accept接受连接,会返回一个新的BluetoothSocket进行管理该连接。
accept();//阻塞直到一个连接建立,返回值:已连接的BluetoothSocket,需要在新建立的线程中执行,避免阻塞,使用try ...catch语法,异常将抛出IOException
accept(int timeout);//阻塞直到超时时间内的连接建立,返回值:已连接的BluetoothSocket,需要在新建立的线程中执行,避免阻塞,使用try ...catch语法,异常将抛出IOException
close();//关闭端口,释放资源
4)BluetoothSocket;
客户端,使用一个单独的BluetoothSocket去初始化一个外接连接和管理该连接。
connect();//连接远程蓝牙设备,由于会造成线程阻塞,因此需要新建一个线程中执行此操作,使用try...catch语法,异常将抛出IOException
getInputStream();//通过连接的端口获得输入的数据流
BluetoothSocket socket = socket.getInputStream();
getOutputStream();//通过连接的端口获得输出的数据流
BluetoothSocket socket = socket.getOutputStream();
getRemoteDevice();//获得该端口正在连接或是已经连接的远程设备
5)BluetoothDevice;
通过蓝牙搜索可以搜索到BluetoothDevice类的对象集合。
createRfcommSocketToServiceRecord(UUID uuid);//创建并返回一个BluetoothSocket
//首先通过搜索到的device建立一个客户端的socket,然后通过connect()方法尝试连接服务器端
BluetoothSocket clientSocket = device.createRfcommSocketToServiceRecord(uuid);
clientSocket.connect();
以上5个知识点是蓝牙开发中最常用的基础知识,此外还包括蓝牙搜索设备广播的建立。
//采用动态方法建立广播,根据需要可以在onCreate()或者在onResume()方法中注册广播
private BroadcastReceiver receiver;
@Override
public void onResume() {
super.onResume();
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context,Intent intent) {
String action = intent.getAction();
switch(action)
{
case BluetoothDevice.ACTION_FOUND:
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_NAME);
mlist.add(device);
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
break;
}
}
};
filter = newIntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//注册蓝牙搜索结果的receiver
mActivity.registerReceiver(receiver,filter);//加上mActivity是因为项目中为fragment与Activity进行交互,如果单纯只是为了测试或者没有fragment,也可以不用加mActivity
}
需要注意的是在使用结束后,需要在onDestroy()中注销此receiver。
3. Android蓝牙中的一些常用知识及使用
3.1 RFCOMM
作为最常用的蓝牙端口,是一个面向连接,通过蓝牙模块进行的数据流传输方式,也可称为SPP(Serial Port Profile,串行端口规范)。作为蓝牙客户端与服务器端的socket通道,在设备连接后,仅仅是bondedDevice,还没有建立通信通道。因此需要在不同的设备的应用程序间建立一个可以通信的路径。
3.2 UUID
Universally Unique Identifier,通用识别码,其目的是让分布式系统中的所有元素,都能有唯一的识别资讯,从而不再需要透过中央控制端来辨别资讯的指定。因此,每个人都可以建立与其他人不冲突的UUID来进行沟通,数据的传输,也不需要在考虑数据库建立时的名字重复问题。理论上只要两台设备的UUID一致,即可建立socket。
String ble_uuid = “00000001-0000-1000-8000-00805F9B34AB”;
UUID uuid = UUID.fromString(ble_uuid);
System.out.println("UUID is " + uuid);
3.3 A2DP
之所以提到A2DP,是因为项目中主要是用来实现蓝牙耳机的功能(包括音频、免提电话、播放音乐、设定EQ等)。A2DPProfile定义了高质量音频数据传输的协议和过程,包括立体声和单声道数据的传输。这里的高质量音频指的是单声道(Mono)和立体声(Sterco)的音频,主要区别于蓝牙SCO链路上传输的普通语音。A2DP的典型应用是将音乐播放器的音频数据发送到耳机或音箱。而目前的A2DP值定义了点对点的音频传输。
二、蓝牙开发规划
此次蓝牙开发流程,包括对于基础知识的梳理,通信协议的介绍和撰写说明,蓝牙搜索界面,相关类的封装,通信过程的开发及代码讲解,会根据笔记的撰写进行不同程序的完善和改变。
以上知识梳理部分,如有错误还请各位大神指出,谢谢。
网友评论