Android蓝牙开发开源框架 代码案例

    这篇文章我早早就想写了,一直忘记了。之前一开始开发Android就搞蓝牙开发,好头大!研究了半个月才能搞定。现在自己整理出了蓝牙开发框架,这框架比较简单,不过希望能帮助蓝牙开发的朋友们。当然个人技术很菜,不足之处请指导。

    蓝牙开步骤:

        1.了解,蓝牙API共有五个类,其中需要撑握三个类:

            BluetoothAdapter(蓝牙适配器):该类主要获取蓝牙信息,比较打开蓝牙、获取本机mac地址、配对的蓝牙信息、等等;
            BluetoothDevice(蓝牙设备):如果连接非安卓设备,该类主要是初始服务端连接蓝牙(把本机看作客户端),如果连接安卓设备,看谁先发连接谁就是客户端;
            BluetoothSocket(蓝牙通信):如果对Socket有了解的,就比较好理解了,就是当连接成功时,可以下午通信。
            注:这里讲的不够详解,可以去官方网了解。

         2.连接

            2.1 找目标MAC地址,可以从BluetoothAdapter可以获取已经配对过的蓝牙地址,选择要连接的蓝牙地址(mac)。
            2.2 根据MAC生成对象,通过:BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mac);得到一个BluetoothDevice,相当于找到了连接的对象;
            2.3连接,BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid);连接非Android设备要用固定UUID:
                UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");如果Android设备之间连接要自定义。
            2.4发起连接,socket.connect(); 阻止anr事件,要在异步处理连接。

        3.通信

            通信从socket可得输出流和输入流:stream = socket.getInputStream(); output = socket.getOutputStream();
            要注意思的是,当蓝牙发数据过来并不是一次性可以从输入流得到,一条数据有可以分几次发送过来。所以要做缓冲区!

        4.解析数据,这个没什么好说的,根据协议解析返回数据(不懂的可以加我QQ:755022831)

下面代码展示:

使用:
package com.cyy.bluetest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.cyy.bluetooth.BlueConnetHandler;
import com.cyy.bluetooth.BlueDeviceControl;
import com.cyy.bluetooth.BlueToothCallBack;

public class MainActivity extends Activity implements OnClickListener {

	private TextView tv;
	private BlueConnetHandler handler;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		findViewById(R.id.bn).setOnClickListener(this);
		tv = (Button) findViewById(R.id.tv);

	}

	private void blue() {
		BlueDeviceControl control = new BlueDeviceControl();
		control.openBlue();// 打开蓝牙

		handler = new BlueConnetHandler(new BlueToothCallBack() {

			@Override
			public void getDate(String date) {
				tv.setText("连接数据: " + date);
			}

			@Override
			public void connect(boolean state) {
				tv.setText("连接: " + state);
			}
		}, "mac地址");

		handler.sendEmptyMessage(BlueConnetHandler.CONNECT);
	}

	@Override
	public void onClick(View v) {
		if (handler.getStateConnect() != 0) {
			tv.setText("已在连接中.....");
		} else {
			tv.setText("连接中.....");
			blue();
		}
	}
}

BlueDeviceControl对BluetoothAdapter一个封装:

package com.cyy.bluetooth;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.SharedPreferences;

public class BlueDeviceControl {
	private BluetoothAdapter adapter;

	/** 构造方法 */
	public BlueDeviceControl() {
		adapter = BluetoothAdapter.getDefaultAdapter();
	}

	/** 设备是否支持蓝牙 */
	public boolean isBlueToothSupported() {
		return adapter != null;
	}

	/** 打开蓝牙 */
	public void openBlue() {
		if (adapter != null && !adapter.isEnabled()) {
			adapter.enable();
		}
	}

	/** 关闭蓝牙 */
	public void closeBlue() {
		if (adapter != null && adapter.isEnabled()) {
			adapter.disable();
		}
	}

	/** 返回已配对的蓝牙设备 */
	public String[] getPartners() {
		Set<BluetoothDevice> set = adapter.getBondedDevices();
		String list[] = new String[set.size()];
		int i = 0;
		for (BluetoothDevice device : set) {
			list[i] = device.getAddress();
			i++;
		}
		return list;

	}

	/** 返回已配对的蓝牙设备 */
	public ArrayList<Map<String, String>> allPartners() {
		ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();
		Set<BluetoothDevice> set = adapter.getBondedDevices();
		for (BluetoothDevice device : set) {
			Map<String, String> map = new HashMap<String, String>();
			map.put("name", device.getName());
			map.put("address", device.getAddress());
			list.add(map);
		}
		return list;
	}

	/** 自动连接上次连接过的蓝牙地址 */
	public String getAdress(Context context) {
		SharedPreferences prference;
		String BLUE_PREF_NAME = "BLUE_PREF_NAME";
		String ADDRESS = "address";
		prference = context.getSharedPreferences(BLUE_PREF_NAME, 0);
		String tmp = prference.getString(ADDRESS, "00:0E:EA:CE:C9:64");
		return tmp;
	}

	/** 保存蓝牙地址,SharedPreferences保存 */
	public void saveAdress(Context context, String mac) {
		if (context != null) {
			SharedPreferences prference;
			String BLUE_PREF_NAME = "BLUE_PREF_NAME";
			String ADDRESS = "address";
			prference = context.getSharedPreferences(BLUE_PREF_NAME, 0);
			prference.edit().putString(ADDRESS, mac).commit();
		}
	}
}

BlueConnectThread蓝牙连接线程:

package com.cyy.bluetooth;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;

public class BlueConnectThread extends Thread {
	private Handler handler;

	// 连接非安卓设备固定UUID
	private final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	private BluetoothDevice device;
	private BluetoothSocket socket;
	private OutputStream output;
	private String mac;

	public BlueConnectThread(Handler handler) {
		this.handler = handler;
	}

	@Override
	public void run() {
		InputStream stream;
		try {
			socket.connect();
			stream = socket.getInputStream();
			output = socket.getOutputStream();
			BufferedInputStream input = new BufferedInputStream(stream);
			Message message = handler.obtainMessage(
					BlueConnetHandler.CONNECT_SUCCEED, mac);
			message.sendToTarget();

			int length;
			byte[] bytes = new byte[100];
			while ((length = input.read(bytes)) != -1) {
				byte[] cacheByte = new byte[length];
				System.arraycopy(bytes, 0, cacheByte, 0, length);
				message = handler.obtainMessage(BlueConnetHandler.GET_DATA, cacheByte);
				message.sendToTarget();
			}
		} catch (IOException e) {
			Message message = handler.obtainMessage(BlueConnetHandler.CONNECT_FAIL);
			message.sendToTarget();
			System.out.println(e.toString());
		}

	}
	
	public boolean sendMsg(String msg) {
		if (output != null) {
			try {
				output.write(msg.getBytes("UTF-8"));
				return true;
			} catch (UnsupportedEncodingException e) {
				System.out.println(e.toString());
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		}
		return false;
	}

	public void setMac(String mac) {
		this.mac = mac;
		try {
			// 判断是不是有效蓝牙地址,如果地址无效IllegalArgumentException异常
			device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mac);
			// 更改socket信道
			socket = device.createRfcommSocketToServiceRecord(uuid);
		} catch (IllegalArgumentException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}
	}
}

BlueConnetHandler数据处理

package com.cyy.bluetooth;

import java.nio.ByteBuffer;

import android.os.Handler;
import android.os.Message;

public class BlueConnetHandler extends Handler {
	private BlueToothCallBack callBack;
	// 默认,可以自定义测试目标mac地址
	private String mac = "00:0E:EA:CE:C9:53";
	// 缓冲区1024字节,如果接收的内容多,可以适当增大缓冲区
	private ByteBuffer blueData = ByteBuffer.allocate(1024);

	public static final int CONNECT = 0x111111;
	public static final int GET_DATA = 0x111111 + 1;
	public static final int CONNECT_FAIL = 0x111111 + 2;
	public static final int CONNECT_SUCCEED = 0x111111 + 3;
	private static final int RESET = 0x111111 + 4;
	private static final int time = 10 * 1000;
	private int stateConnect = 0;// 连接状态,默认未开始连接
	private BlueConnectThread thread;

	public BlueConnetHandler(BlueToothCallBack callBack) {
		this.callBack = callBack;
	}
	
	public BlueConnetHandler(BlueToothCallBack callBack, String mac) {
		this.callBack = callBack;
		this.mac = mac;
	}

	@Override
	public void handleMessage(Message msg) {
		super.handleMessage(msg);

		switch (msg.what) {
		case CONNECT:
			if (thread == null || !thread.isAlive()) {
				stateConnect = CONNECT;
				thread = new BlueConnectThread(this);
				thread.setMac(mac);
				thread.start();
			}
			break;

		case CONNECT_FAIL:
			stateConnect = CONNECT_FAIL;
			dealACallBack(false);
			// 设置连接失败后继续重新连接,10秒后重启
			this.sendEmptyMessageDelayed(CONNECT, time);
			break;

		case CONNECT_SUCCEED:
			stateConnect = CONNECT_SUCCEED;
			mac = (String) msg.obj;
			callBack.connect(true);
			dealACallBack(true);
			break;

		case GET_DATA:// 从蓝牙获取到一些数据,通常一组数据分几次发送过来
			byte[] bytes = (byte[]) msg.obj;
			blueData.put(bytes);
			this.removeMessages(RESET);
			this.sendEmptyMessageDelayed(RESET, 100);
			break;

		case RESET: // 从蓝牙获取一组数据后发送出去
			decodeReSet();
			break;

		default:
			break;
		}
	}

	private void dealACallBack(boolean isConnect) {
		if (null != callBack) {
			callBack.connect(isConnect);
		}
	}

	/** 根据蓝牙协议解析数据。然后重置data */
	private void decodeReSet() {
		blueData.flip();
		// String data = bytes2String(blueData.array());
		// 简单地处理,具体还要根据协议来解析数据
		String data = new String(blueData.array());
		if (callBack != null) {
			callBack.getDate(data);
		}
		
		blueData.clear();
	}

	/** 16进制字节数组转换成十进制字符串 */
	private String bytes2String(byte[] bytes) {
		long sum = 0;
		for (int i = 0; i < bytes.length; i++) {
			long cache = bytes[i] & 0xff;
			for (int j = 0; j < i; j++) {
				cache = cache << 4 << 4;
			}
			sum += cache;
		}
		return sum + "";
	}

	public int getStateConnect() {
		return stateConnect;
	}
	
	public boolean sendMsg(String msg) {
		if (thread != null) {
			return thread.sendMsg(msg);
		}
		return false;
	}
}

代码开源 SVN:http://code.taobao.org/svn/blueconnect/trunk

csdn下载



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。