Android適配安卓6.0藍(lán)牙通訊實(shí)現(xiàn)過程
事先說明:
安卓藍(lán)牙需要定位權(quán)限申請,在安卓6.0需要用戶手動確認(rèn)權(quán)限后才能使用,各位可以自行查詢資料實(shí)現(xiàn),如果嫌麻煩,可以用第三方Bmob集成好的工具類進(jìn)行實(shí)現(xiàn),詳細(xì)可以看http://blog.csdn.net/qq_30379689/article/details/52223244
藍(lán)牙連接過程:
1、查詢用戶是否開啟藍(lán)牙。
2、搜索附近的可用的藍(lán)牙。
3、進(jìn)行藍(lán)牙配對。
4、進(jìn)行藍(lán)牙連接。
5、獲取輸入流和輸出流。
6、發(fā)送消息。
曬上我自己畫的美圖:

實(shí)驗(yàn)效果圖:

實(shí)現(xiàn)需要的權(quán)限:由于安卓4.x以上的版本使用藍(lán)牙,需要開啟定位權(quán)限才能搜索到附近的藍(lán)牙設(shè)備
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
服務(wù)端
實(shí)現(xiàn)思路:
1、拿到本地藍(lán)牙設(shè)備。
2、藍(lán)牙之間的通訊需要一個(gè)唯一識別UUID來匹配正確的設(shè)備,使用UUID獲取藍(lán)牙的通訊Socket。
3、開啟獲取數(shù)據(jù)的線程
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
BluetoothSocket BTSocket;
BluetoothAdapter BTAdapter;
Button bt_start;
TextView tv_msg;
StringBuilder sb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_start = (Button) findViewById(R.id.bt_start);
tv_msg = (TextView) findViewById(R.id.tv_msg);
bt_start.setOnClickListener(this);
sb = new StringBuilder();
//拿到本地藍(lán)牙設(shè)備
BTAdapter = BluetoothAdapter.getDefaultAdapter();
}
/**
* UI文本輸出
*
* @param msg
*/
public void show(String msg) {
sb.append(msg + "\n");
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_msg.setText(sb.toString());
}
});
}
@Override
public void onClick(View v) {
//開啟服務(wù)器
ServerThread startServerThread = new ServerThread();
startServerThread.start();
}
/**
* 開啟服務(wù)器
*/
private class ServerThread extends Thread {
public void run() {
try {
BluetoothServerSocket mserverSocket = BTAdapter.listenUsingRfcommWithServiceRecord("btspp",
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
show("服務(wù)端:等待連接");
BTSocket = mserverSocket.accept();
show("服務(wù)端:連接成功");
readThread mreadThread = new readThread();
mreadThread.start();
show("服務(wù)端:啟動接受數(shù)據(jù)");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 讀取數(shù)據(jù)
*/
private class readThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
try {
mmInStream = BTSocket.getInputStream();
show("服務(wù)端:獲得輸入流");
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
try {
if ((bytes = mmInStream.read(buffer)) > 0) {
byte[] buf_data = new byte[bytes];
for (int i = 0; i < bytes; i++) {
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
show("服務(wù)端:讀取數(shù)據(jù)了~~" + s);
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
}
}
}
客戶端
實(shí)現(xiàn)思路:
1、檢查是否開啟藍(lán)牙。
2、注冊一系列藍(lán)牙的廣播。
3、由于藍(lán)牙每經(jīng)過一個(gè)階段都會發(fā)送一個(gè)廣播,根據(jù)廣播來實(shí)現(xiàn)對應(yīng)的方法。
4、藍(lán)牙配對->藍(lán)牙連接->發(fā)送消息(UUID必須相同)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_msg;
private Button bt_search, bt_send;
private BluetoothSocket BTSocket;
private BluetoothAdapter BTAdapter;
private BluetoothDevice device;
private StringBuilder sb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_search = (Button) findViewById(R.id.bt_search);
bt_send = (Button) findViewById(R.id.bt_send);
tv_msg = (TextView) findViewById(R.id.tv_msg);
bt_search.setOnClickListener(this);
bt_send.setOnClickListener(this);
sb = new StringBuilder();
show("客戶端:檢查BT");
checkBT(this);
show("客戶端:注冊接收者");
registerBTReceiver();
}
/**
* UI文本輸出
*
* @param msg
*/
public void show(String msg) {
sb.append(msg + "\n");
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_msg.setText(sb.toString());
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_search:
show("客戶端:開始尋找設(shè)備");
BTAdapter.startDiscovery();
break;
case R.id.bt_send:
sendMessage();
break;
}
}
/**
* 檢查藍(lán)牙
*/
public void checkBT(Context context) {
BTAdapter = BluetoothAdapter.getDefaultAdapter();
if (BTAdapter != null) {
if (!BTAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
// 設(shè)置藍(lán)牙可見性,最多300秒
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
context.startActivity(intent);
}
} else {
System.out.println("本地設(shè)備驅(qū)動異常!");
}
}
/**
* 開啟客戶端
*/
private class clientThread extends Thread {
public void run() {
try {
//創(chuàng)建一個(gè)Socket連接:只需要服務(wù)器在注冊時(shí)的UUID號
BTSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//連接
show("客戶端:開始連接...");
BTSocket.connect();
show("客戶端:連接成功");
//啟動接受數(shù)據(jù)
show("客戶端:啟動接受數(shù)據(jù)");
readThread mreadThread = new readThread();
mreadThread.start();
} catch (IOException e) {
show("客戶端:連接服務(wù)端異常!斷開連接重新試一試");
e.printStackTrace();
}
}
}
/**
* 讀取數(shù)據(jù)
*/
private class readThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream is = null;
try {
is = BTSocket.getInputStream();
show("客戶端:獲得輸入流");
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
try {
if ((bytes = is.read(buffer)) > 0) {
byte[] buf_data = new byte[bytes];
for (int i = 0; i < bytes; i++) {
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
show("客戶端:讀取數(shù)據(jù)了" + s);
}
} catch (IOException e) {
try {
is.close();
} catch (IOException e1) {
e1.printStackTrace();
}
break;
}
}
}
}
/**
* 發(fā)送數(shù)據(jù)
*/
public void sendMessage() {
if (BTSocket == null) {
Toast.makeText(this, "沒有連接", Toast.LENGTH_SHORT).show();
return;
}
try {
OutputStream os = BTSocket.getOutputStream();
os.write("我愛你dahsid132456@#%¥*".getBytes());
os.flush();
show("客戶端:發(fā)送信息成功");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 注冊廣播
*/
public void registerBTReceiver() {
// 設(shè)置廣播信息過濾
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
// 注冊廣播接收器,接收并處理搜索結(jié)果
registerReceiver(BTReceive, intentFilter);
}
/**
* 注銷廣播
*/
public void unregisterBTReceiver() {
unregisterReceiver(BTReceive);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterBTReceiver();
}
/**
* 廣播接收者
*/
private BroadcastReceiver BTReceive = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
show("客戶端:找到的BT名:" + device.getName());
// 如果查找到的設(shè)備符合要連接的設(shè)備,處理
if (device.getName().equalsIgnoreCase("xu")) {
show("客戶端:配對xu藍(lán)牙:");
// 搜索藍(lán)牙設(shè)備的過程占用資源比較多,一旦找到需要連接的設(shè)備后需要及時(shí)關(guān)閉搜索
BTAdapter.cancelDiscovery();
// 獲取藍(lán)牙設(shè)備的連接狀態(tài)
int connectState = device.getBondState();
switch (connectState) {
// 未配對
case BluetoothDevice.BOND_NONE:
show("客戶端:開始配對:");
try {
Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
createBondMethod.invoke(device);
} catch (Exception e) {
e.printStackTrace();
}
break;
// 已配對
case BluetoothDevice.BOND_BONDED:
try {
show("客戶端:開始連接:");
clientThread clientConnectThread = new clientThread();
clientConnectThread.start();
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
// 獲取藍(lán)牙設(shè)備的連接狀態(tài)
int connectState = device.getBondState();
// 已配對
if (connectState == BluetoothDevice.BOND_BONDED) {
try {
show("客戶端:開始連接:");
clientThread clientConnectThread = new clientThread();
clientConnectThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
show(action);
}
};
}
藍(lán)牙廣播內(nèi)容:
ACTION_STATE_CHANGED 當(dāng)你藍(lán)牙開啟或者關(guān)閉的時(shí)候發(fā)送
ACTION_FOUND 當(dāng)你匹配到附近藍(lán)牙設(shè)備時(shí)發(fā)送
ACTION_DISCOVERY_STARTED 當(dāng)你開始搜索附近藍(lán)牙設(shè)備時(shí)發(fā)送
ACTION_DISCOVERY_FINISHED 當(dāng)你結(jié)束搜索附近藍(lán)牙設(shè)備時(shí)發(fā)送
ACTION_BOND_STATE_CHANGED 當(dāng)你藍(lán)牙設(shè)備匹配狀態(tài)發(fā)生變化時(shí)發(fā)送
源碼下載:http://xiazai.jb51.net/201609/yuanma/Androidrobot(jb51.net).rar
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)毛玻璃效果彈出菜單動畫
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)毛玻璃效果彈出菜單動畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Flutter進(jìn)階之實(shí)現(xiàn)動畫效果(九)
這篇文章主要為大家詳細(xì)介紹了Flutter進(jìn)階之實(shí)現(xiàn)動畫效果的第九篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android手勢滑動實(shí)現(xiàn)ImageView縮放圖片大小
這篇文章主要為大家詳細(xì)介紹了Android手勢滑動實(shí)現(xiàn)ImageView縮放圖片大小的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02
android 之Spinner下拉菜單實(shí)現(xiàn)級聯(lián)
android 之Spinner下拉菜單實(shí)現(xiàn)級聯(lián),需要的朋友可以參考一下2013-02-02
Android獲取系統(tǒng)儲存以及內(nèi)存信息的方法(一)
這篇文章主要為大家詳細(xì)介紹了Android獲取系統(tǒng)儲存以及內(nèi)存信息的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Android 5.0最應(yīng)該實(shí)現(xiàn)的8個(gè)期望
毫無疑問,Android 5 將是令人興奮的操作系統(tǒng),因?yàn)?Android4.0 至 4.4 版本之間并沒有顯著的差異,顯然谷歌會在 5.0 版本中進(jìn)行一些較大幅度的革新2016-01-01

