转载处 http://blog.csdn.net/vnanyesheshou/article/details/51554852
1 蓝牙基本操作
随着可穿戴设备的流行,研究蓝牙是必不可少的一门技术了。
总结了下蓝牙开发使用的一些东西分享一下。
蓝牙权限
首先需要AndroidManifest.xml文件中添加操作蓝牙的权限。<uses-permissionandroid:name="android.permission.BLUETOOTH" />
允许程序连接到已配对的蓝牙设备。
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" />
允许程序发现和配对蓝牙设备。
BluetoothAdapter
操作蓝牙主要用到的类 BluetoothAdapter类,使用时导包
import android.bluetooth.BluetoothAdapter;
源码具体位置frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
BluetoothAdapter 代表本地设备的蓝牙适配器。该BluetoothAdapter可以执行基本的蓝牙任务,例如启
动设备发现,查询配对的设备列表,使用已知的MAC地址实例化一个BluetoothDevice类,并创建一个
BluetoothServerSocket监听来自其他设备的连接请求。
获取蓝牙适配器
- BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
开启蓝牙
- if(!mBluetoothAdapter.isEnabled()){
-
- Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivityForResult(enabler, REQUEST_ENABLE);
-
-
- }
获取本地蓝牙信息
-
- String name = mBluetoothAdapter.getName();
-
- String address = mBluetoothAdapter.getAddress();
- Log.d(TAG,"bluetooth name ="+name+" address ="+address);
-
- Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
- Log.d(TAG, "bonded device size ="+devices.size());
- for(BluetoothDevice bonddevice:devices){
- Log.d(TAG, "bonded device name ="+bonddevice.getName()+" address"+bonddevice.getAddress());
- }
搜索设备
mBluetoothAdapter.startDiscovery();
停止搜索
mBluetoothAdapter.cancelDiscovery();
搜索蓝牙设备,该过程是异步的,通过下面注册广播接受者,可以监听是否搜到设备。
- IntentFilter filter = new IntentFilter();
-
- filter.addAction(BluetoothDevice.ACTION_FOUND);
-
- filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- registerReceiver(mBluetoothReceiver, filter);
监听扫描结果
通过广播接收者查看扫描到的蓝牙设备,每扫描到一个设备,系统都会发送此广播(BluetoothDevice.ACTION_FOUNDE)。其中参数intent可以获取蓝牙设备BluetoothDevice。
该demo中是连接指定名称的蓝牙设备,BLUETOOTH_NAME为"Galaxy Nexus",如果扫描不到,记得改这个蓝牙名称。
- private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver(){
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- Log.d(TAG,"mBluetoothReceiver action ="+action);
- if(BluetoothDevice.ACTION_FOUND.equals(action)){
-
- BluetoothDevice scanDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if(scanDevice == null || scanDevice.getName() == null) return;
- Log.d(TAG, "name="+scanDevice.getName()+"address="+scanDevice.getAddress());
-
- String name = scanDevice.getName();
- if(name != null && name.equals(BLUETOOTH_NAME)){
- mBluetoothAdapter.cancelDiscovery();
-
- mProgressDialog.setTitle(getResources().getString(R.string.progress_connecting));
- mBlthChatUtil.connect(scanDevice);
- }
- }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
-
- }
- }
-
- };
设置蓝牙可见性
有时候扫描不到某设备,这是因为该设备对外不可见或者距离远,需要设备该蓝牙可见,这样该才能被搜索到。
可见时间默认值为120s,最多可设置300。
- if (mBluetoothAdapter.isEnabled()) {
- if (mBluetoothAdapter.getScanMode() !=
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- Intent discoverableIntent = new Intent(
- BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- discoverableIntent.putExtra(
- BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
- startActivity(discoverableIntent);
- }
- }
2 服务端
android 蓝牙之间可以通过SDP协议建立连接进行通信,通信方式类似于平常使用socket。
首先创建BluetoothServerSocket ,BluetoothAdapter中提供了两种创建BluetoothServerSocket 方式,如下图所示为创建安全的RFCOMM Bluetooth socket,该连接是安全的需要进行配对。而通过listenUsingInsecureRfcommWithServiceRecord创建的RFCOMM Bluetooth socket是不安全的,连接时不需要进行配对。
其中的uuid需要服务器端和客户端进行统一。
- private class AcceptThread extends Thread {
-
- private final BluetoothServerSocket mServerSocket;
- public AcceptThread() {
- BluetoothServerSocket tmp = null;
-
- try {
- tmp = mAdapter.listenUsingRfcommWithServiceRecord(
- SERVICE_NAME, SERVICE_UUID);
-
- } catch (IOException e) {
- Log.e(TAG, "listen() failed", e);
- }
- mServerSocket = tmp;
- }
-
- public void run() {
- BluetoothSocket socket = null;
-
- while (mState != STATE_CONNECTED) {
- try {
-
-
- socket = mServerSocket.accept();
- } catch (IOException e) {
- Log.e(TAG, "accept() failed", e);
- break;
- }
-
- if (socket != null) {
- synchronized (BluetoothChatUtil.this) {
- switch (mState) {
- case STATE_LISTEN:
- case STATE_CONNECTING:
-
- connected(socket, socket.getRemoteDevice());
- break;
- case STATE_NONE:
- case STATE_CONNECTED:
-
- try {
- socket.close();
- } catch (IOException e) {
- Log.e(TAG, "Could not close unwanted socket", e);
- }
- break;
- }
- }
- }
- }
- if (D) Log.i(TAG, "END mAcceptThread");
- }
-
- public void cancel() {
- if (D) Log.d(TAG, "cancel " + this);
- try {
- mServerSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of server failed", e);
- }
- }
- }
mServerSocket通过accept()等待客户端的连接(阻塞),直到连接成功或失败。
3 客户端
客户端主要用来创建RFCOMM socket,并连接服务端。
先扫描周围的蓝牙设备,如果扫描到指定设备则进行连接。mBlthChatUtil.connect(scanDevice)连接到设备,
连接过程主要在ConnectThread线程中进行,先创建socket,方式有两种,
如下代码中是安全的(createRfcommSocketToServiceRecord)。另一种不安全连接对应的函数是createInsecureRfcommSocketToServiceRecord。
- private class ConnectThread extends Thread {
- private BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
- public ConnectThread(BluetoothDevice device) {
- mmDevice = device;
- BluetoothSocket tmp = null;
-
- try {
- mmSocket = device.createRfcommSocketToServiceRecord
- (SERVICE_UUID);
- } catch (IOException e) {
- Log.e(TAG, "create() failed", e);
- mmSocket = null;
- }
- }
-
- public void run() {
- Log.i(TAG, "BEGIN mConnectThread");
- try {
-
- mmSocket.connect();
- } catch (IOException e) {
- connectionFailed();
- try {
- mmSocket.close();
- } catch (IOException e2) {
- e2.printStackTrace();
- }
- return;
- }
-
- connected(mmSocket, mmDevice);
- }
-
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of connect socket failed", e);
- }
- }
- }
接着客户端socket主动连接服务端。连接过程中会自动进行配对,需要双方同意才可以连接成功。
4 数据传输
客户端与服务端连接成功后都会调用connected(mmSocket, mmDevice),创建一个ConnectedThread线程()。
该线程主要用来接收和发送数据。客户端和服务端处理方式一样。该线程通过socket获得输入输出流。
private InputStream mmInStream = socket.getInputStream();
private OutputStream mmOutStream =socket.getOutputStream();
发送数据
- public void write(byte[] buffer) {
- try {
- mmOutStream.write(buffer);
-
- mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer)
- .sendToTarget();
- } catch (IOException e) {
- Log.e(TAG, "Exception during write", e);
- }
- }
接收数据线程循环进行接收数据。
- public void run() {
-
- while (true) {
- try {
- byte[] buffer = new byte[1024];
-
- int bytes = mmInStream.read(buffer);
-
- Message msg = mHandler.obtainMessage(MESSAGE_READ);
- Bundle bundle = new Bundle();
- bundle.putByteArray(READ_MSG, buffer);
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- } catch (IOException e) {
- Log.e(TAG, "disconnected", e);
- connectionLost();
- break;
- }
- }
- }
demo下载:http://www.demodashi.com/demo/10676.html