標籤: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;@Overrideprotected 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() {@Overridepublic void getDate(String date) {tv.setText("串連資料: " + date);}@Overridepublic void connect(boolean state) {tv.setText("串連: " + state);}}, "mac地址");handler.sendEmptyMessage(BlueConnetHandler.CONNECT);}@Overridepublic 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;// 串連非安卓裝置固定UUIDprivate 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;}@Overridepublic 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;}@Overridepublic 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下載
Android藍芽開發開源架構 代碼案例