一、蓝牙通信的步骤

  1. 开启蓝牙
  2. 搜索可用设备
  3. 创建蓝牙socket
  4. 获取输入输出流
  5. 断开连接关闭蓝牙

二、几个重要的类

  • BluetoothAdapter
  • BluetoothGatt
  • BluetoothDevice
  • BluetoothCattService
  • BluetoothCattCharacteristic

第一个是蓝牙设配器,对蓝牙的操作都需要用到它,很重要,BluetoothGatt作为中央来使用和处理数据,使用时有一个回调方法BluetoothGattCallback返回中央的状态和周边提供的数据,BluetoothCattService作为周边来提供数据;BluetoothGattServerCallback返回周边的状态。BluetoothDevice是蓝牙设备,BluetoothCattCharacteristic是蓝牙设备的特征。

看着有点乱,我们来打个比喻:BluetoothDevice为学校,BluetoothGatt为学校到达某一个班级的通道,BluetoothCattService为学校的某一个班级,BluetoothCattCharacteristic为班级中的某一个学生。那么蓝牙连接通信的过程就是这样,BluetoothAdapter先找到学校(就是连接目的设备),再通过通道找到目标班级,最后从班级中找到目标学生,这个学生就是我们设备之间通信的中介,很重要,学校有唯一的MAC地址,班级有唯一的serviceUUID,学生有唯一的charactersticUUID(相当于学号),所以就是在一所学校找一个学生的问题。

三、蓝牙通信的原理

3.1 蓝牙通信原理与socket通信原理相似

3.2 客户端socket

  1. 创建客户端蓝牙Socket
  2. 创建连接
  3. 读写数据
  4. 关闭

3.3 服务端Socket

  1. 创建服务端蓝牙Socket
  2. 绑定端口号(蓝牙忽略)
  3. 创建监听listen(蓝牙忽略, 蓝牙没有此监听,而是通过while(true)死循环来一直监听的)
  4. 通过accept(),如果有客户端连接,会创建一个新的Socket,体现出并发性,可以同时与多个socket通讯)
  5. 读写数据
  6. 关闭

四、客户端代码

public class ConnectThread extends Thread{private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);/** 客户端socket*/private final BluetoothSocket mmSoket;/** 要连接的设备*/private final BluetoothDevice mmDevice;private BluetoothAdapter mBluetoothAdapter;/** 主线程通信的Handler*/private final Handler mHandler;/** 发送和接收数据的处理类*/private ConnectedThread mConnectedThread;public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {mmDevice = device;mBluetoothAdapter = bluetoothAdapter;mHandler = mUIhandler;BluetoothSocket tmp = null;try {// 创建客户端Sockettmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {e.printStackTrace();}mmSoket = tmp;}@Overridepublic void run() {super.run();// 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)mBluetoothAdapter.cancelDiscovery();try {// 连接服务器mmSoket.connect();} catch (IOException e) {// 连接异常就关闭try {mmSoket.close();} catch (IOException e1) {}return;}manageConnectedSocket(mmSoket);}private void manageConnectedSocket(BluetoothSocket mmSoket) {// 通知主线程连接上了服务端socket,更新UImHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);// 新建一个线程进行通讯,不然会发现线程堵塞mConnectedThread = new ConnectedThread(mmSoket,mHandler);mConnectedThread.start();}/*** 关闭当前客户端*/public void cancle() {try {mmSoket.close();} catch (IOException e) {e.printStackTrace();}}/*** 发送数据* @param data*/public void sendData(byte[] data) {if(mConnectedThread != null) {mConnectedThread.write(data);}}
}

五、服务端代码

public class AccepThread extends Thread {/** 连接的名称*/private static final String NAME = "BluetoothClass";/** UUID*/private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);/** 服务端蓝牙Sokcet*/private final BluetoothServerSocket mmServerSocket;private final BluetoothAdapter mBluetoothAdapter;/** 线程中通信的更新UI的Handler*/private final Handler mHandler;/** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/private ConnectedThread mConnectedThread;public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {mBluetoothAdapter = adapter;this.mHandler = handler;// 获取服务端蓝牙socketmmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);}@Overridepublic void run() {super.run();// 连接的客户端soacketBluetoothSocket socket = null;// 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环while (true){// 通知主线程更新UI,客户端开始监听mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);try {// 获取连接的客户端socketsocket =  mmServerSocket.accept();} catch (IOException e) {// 通知主线程更新UI, 获取异常mHandler.sendEmptyMessage(Constant.MSG_ERROR);e.printStackTrace();// 服务端退出一直监听线程break;}if(socket != null) {// 管理连接的客户端socketmanageConnectSocket(socket);// 这里应该是手动断开,案例应该是只保证连接一个客户端,所以连接完以后,关闭了服务端socket
//                try {//                    mmServerSocket.close();
//                    mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
//                } catch (IOException e) {//                    e.printStackTrace();
//                }}}}/*** 管理连接的客户端socket* @param socket*/private void manageConnectSocket(BluetoothSocket socket) {// 只支持同时处理一个连接// mConnectedThread不为空,踢掉之前的客户端if(mConnectedThread != null) {mConnectedThread.cancle();}// 主线程更新UI,连接到了一个客户端mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);// 新建一个线程,处理客户端发来的数据mConnectedThread = new ConnectedThread(socket, mHandler);mConnectedThread.start();}/*** 断开服务端,结束监听*/public void cancle() {try {mmServerSocket.close();mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);} catch (IOException e) {e.printStackTrace();}}/*** 发送数据* @param data*/public void sendData(byte[] data){if(mConnectedThread != null) {mConnectedThread.write(data);}}
}

六、共同通讯处理类

public class ConnectedThread extends Thread{/** 当前连接的客户端BluetoothSocket*/private final BluetoothSocket mmSokcet;/** 读取数据流*/private final InputStream mmInputStream;/** 发送数据流*/private final OutputStream mmOutputStream;/** 与主线程通信Handler*/private Handler mHandler;private String TAG = "ConnectedThread";public ConnectedThread(BluetoothSocket socket,Handler handler) {mmSokcet = socket;mHandler = handler;InputStream tmpIn = null;OutputStream tmpOut = null;try {tmpIn = socket.getInputStream();tmpOut = socket.getOutputStream();} catch (IOException e) {e.printStackTrace();}mmInputStream = tmpIn;mmOutputStream = tmpOut;}@Overridepublic void run() {super.run();byte[] buffer = new byte[1024];while (true) {try {// 读取数据int bytes = mmInputStream.read(buffer);if(bytes > 0) {String data = new String(buffer,0,bytes,"utf-8");// 把数据发送到主线程, 此处还可以用广播Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);mHandler.sendMessage(message);}Log.d(TAG, "messge size :" + bytes);} catch (IOException e) {e.printStackTrace();}}}// 踢掉当前客户端public void cancle() {try {mmSokcet.close();} catch (IOException e) {e.printStackTrace();}}/*** 服务端发送数据* @param data*/public void write(byte[] data) {try {mmOutputStream.write(data);} catch (IOException e) {e.printStackTrace();}}
}

七、基于安卓蓝牙通信的DEMO应用

7.1 DEMO运行截图

7.2 代码仓库

作业六代码仓库

7.3 核心代码

package com.example.bluetoothdemo;import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.SQLOutput;
import java.util.UUID;public class MainActivity extends AppCompatActivity implements View.OnClickListener {public static final int REQUEST_BT_ENABLE_CODE = 200;public static final String BT_UUID = "00001101-0000-1000-8000-00805F9B34FB";//uuidprivate BluetoothAdapter mBluetoothAdapter;//蓝牙适配器private BlueToothStateReceiver mReceiver;//广播接收器private ConnectThread mConnectThread; //客户端线程private AcceptThread mAcceptThread; //服务端线程private RvAdapter mRvAdapter;@SuppressLint("StaticFieldLeak")private static MsgAdapter mMessageAdapter;private EditText inputEt;@SuppressLint("HandlerLeak")private static final Handler mHandler = new Handler() {@Overridepublic void dispatchMessage(Message msg) {mMessageAdapter.addMessage((String) msg.obj);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//这是我是为了6.0以上的设备能搜索到结果,动态申请了位置权限。但是没有处理结果,因为我测试肯定点同意~- -requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1001);initUI();registerRec();}private void initUI() {findViewById(R.id.open).setOnClickListener(this);findViewById(R.id.close).setOnClickListener(this);findViewById(R.id.start).setOnClickListener(this);findViewById(R.id.stop).setOnClickListener(this);findViewById(R.id.send).setOnClickListener(this);inputEt = (EditText) findViewById(R.id.input);RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.devices);mRecyclerView.setLayoutManager(new LinearLayoutManager(this));mRvAdapter = new RvAdapter(this);mRecyclerView.setAdapter(mRvAdapter);mRvAdapter.setOnItemClickListener(new RvAdapter.OnItemClickListener() {@Overridepublic void onClick(BluetoothDevice device) {mConnectThread = new ConnectThread(device);mConnectThread.start();}});RecyclerView mMessageView = (RecyclerView) findViewById(R.id.msglist);mMessageView.setLayoutManager(new LinearLayoutManager(this));mMessageAdapter = new MsgAdapter(this);mMessageView.setAdapter(mMessageAdapter);}private void openBT() {if (mBluetoothAdapter == null) {mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();}//1.设备不支持蓝牙,结束应用if (mBluetoothAdapter == null) {finish();return;}//2.判断蓝牙是否打开try {if (!mBluetoothAdapter.enable()) {//没打开请求打开Intent btEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(btEnable, REQUEST_BT_ENABLE_CODE);}}catch (Exception EX) {System.out.println("异常");}}private void registerRec() {//3.注册蓝牙广播mReceiver = new BlueToothStateReceiver();IntentFilter filter = new IntentFilter();filter.addAction(BluetoothDevice.ACTION_FOUND);//搜多到蓝牙filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束registerReceiver(mReceiver, filter);}@Overrideprotected void onDestroy() {if (mReceiver != null) {unregisterReceiver(mReceiver);}super.onDestroy();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_BT_ENABLE_CODE) {if (resultCode == RESULT_OK) {//用户允许打开蓝牙mMessageAdapter.addMessage("用户同意打开蓝牙");} else if (resultCode == RESULT_CANCELED) {//用户取消打开蓝牙mMessageAdapter.addMessage("用户拒绝打开蓝牙");}}super.onActivityResult(requestCode, resultCode, data);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.open:openBT();mMessageAdapter.addMessage("打开蓝牙");if (mAcceptThread == null && mBluetoothAdapter != null) {mAcceptThread = new AcceptThread();mAcceptThread.start();mMessageAdapter.addMessage("启动服务线程");}break;case R.id.close:mBluetoothAdapter.disable();break;case R.id.start:if (mBluetoothAdapter != null) {mRvAdapter.clearDevices();//开始搜索前清空上一次的列表mBluetoothAdapter.startDiscovery();mMessageAdapter.addMessage("开始搜索蓝牙");} else {openBT();if (mBluetoothAdapter != null) {mRvAdapter.clearDevices();//开始搜索前清空上一次的列表mBluetoothAdapter.startDiscovery();mMessageAdapter.addMessage("开始搜索蓝牙");}}break;case R.id.stop:if (mBluetoothAdapter != null && mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}break;case R.id.send:String msg = inputEt.getText().toString();if (TextUtils.isEmpty(msg)) {Toast.makeText(this, "消息为空", Toast.LENGTH_SHORT).show();return;}if (mConnectThread != null) {//证明我主动去链接别人了mConnectThread.write(msg);} else if (mAcceptThread != null) {mAcceptThread.write(msg);}mMessageAdapter.addMessage("发送消息:" + msg);break;}}class BlueToothStateReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(MainActivity.this, "触发广播", Toast.LENGTH_SHORT).show();String action = intent.getAction();switch (action) {case BluetoothDevice.ACTION_FOUND:BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Toast.makeText(MainActivity.this, "找到设备" + device.getName(), Toast.LENGTH_SHORT).show();if (mRvAdapter != null) {mRvAdapter.addDevice(device);}break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:mMessageAdapter.addMessage("搜索结束");break;}}}class ConnectThread extends Thread {private BluetoothDevice mDevice;private BluetoothSocket mSocket;private InputStream btIs;private OutputStream btOs;private boolean canRecv;private PrintWriter writer;public ConnectThread(BluetoothDevice device) {mDevice = device;canRecv = true;}@Overridepublic void run() {if (mDevice != null) {try {//获取套接字BluetoothSocket temp = mDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));//mDevice.createRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));//sdk 2.3以下使用mSocket = temp;//发起连接请求if (mSocket != null) {mSocket.connect();}sendHandlerMsg("连接 " + mDevice.getName() + "成功!");//获取输入输出流btIs = mSocket.getInputStream();btOs = mSocket.getOutputStream();//通讯-接收消息BufferedReader reader = new BufferedReader(new InputStreamReader(btIs, "UTF-8"));String content = null;while (canRecv) {content = reader.readLine();sendHandlerMsg("收到消息:" + content);}} catch (IOException e) {e.printStackTrace();sendHandlerMsg("错误:" + e.getMessage());} finally {try {if (mSocket != null) {mSocket.close();}//btIs.close();//两个输出流都依赖socket,关闭socket即可//btOs.close();} catch (IOException e) {e.printStackTrace();sendHandlerMsg("错误:" + e.getMessage());}}}}private void sendHandlerMsg(String content) {Message msg = mHandler.obtainMessage();msg.what = 1001;msg.obj = content;mHandler.sendMessage(msg);}public void write(String msg) {if (btOs != null) {try {if (writer == null) {writer = new PrintWriter(new OutputStreamWriter(btOs, "UTF-8"), true);}writer.println(msg);} catch (UnsupportedEncodingException e) {e.printStackTrace();writer.close();sendHandlerMsg("错误:" + e.getMessage());}}}}class AcceptThread extends Thread {private BluetoothServerSocket mServerSocket;private BluetoothSocket mSocket;private InputStream btIs;private OutputStream btOs;private PrintWriter writer;private boolean canAccept;private boolean canRecv;public AcceptThread() {canAccept = true;canRecv = true;}@Overridepublic void run() {try {//获取套接字try {BluetoothServerSocket temp = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("TEST", UUID.fromString(BT_UUID));mServerSocket = temp;}catch (Exception exception) {System.out.println("异常");}//监听连接请求 -- 作为测试,只允许连接一个设备if (mServerSocket != null) {// while (canAccept) {mSocket = mServerSocket.accept();sendHandlerMsg("有客户端连接");// }}//获取输入输出流btIs = mSocket.getInputStream();btOs = mSocket.getOutputStream();//通讯-接收消息BufferedReader reader = new BufferedReader(new InputStreamReader(btIs, "UTF-8"));String content = null;while (canRecv) {content = reader.readLine();sendHandlerMsg("收到消息:" + content);}} catch (IOException e) {e.printStackTrace();} finally {try {if (mSocket != null) {mSocket.close();}// btIs.close();//两个输出流都依赖socket,关闭socket即可// btOs.close();} catch (IOException e) {e.printStackTrace();sendHandlerMsg("错误:" + e.getMessage());}}}private void sendHandlerMsg(String content) {Message msg = mHandler.obtainMessage();msg.what = 1001;msg.obj = content;mHandler.sendMessage(msg);}public void write(String msg) {if (btOs != null) {try {if (writer == null) {writer = new PrintWriter(new OutputStreamWriter(btOs, "UTF-8"), true);}writer.println(msg);} catch (UnsupportedEncodingException e) {e.printStackTrace();writer.close();sendHandlerMsg("错误:" + e.getMessage());}}}}
}

移动开发作业六 蓝牙通信相关推荐

  1. 移动开发作业6——蓝牙通信的简要设计与开发

    一.蓝牙通信原理介绍 Android 平台包含蓝牙网络堆栈支持,此支持能让设备以无线方式与其他蓝牙设备交换数据.应用框架提供通过 Android Bluetooth API 访问蓝牙功能的权限.这些 ...

  2. 2.19 haas506 2.0开发教程 - bluetooth - 蓝牙通信(仅支持2.2以上版本)

    haas506 2.0开发教程 - bluetooth - 蓝牙通信 蓝牙 案例说明 从机测试(支持601与320) 1. 蓝牙调试工具 2. 设备端开发 3. 功能测试 主机测试(仅支持320) 1 ...

  3. 车载开发中,蓝牙通信需要学习那些核心技术点?

    车载蓝牙通信是指在汽车内部或车辆与外部设备之间使用蓝牙技术进行数据传输和通信.蓝牙5.0是现代蓝牙技术的最新版本,它引入了一系列新功能和改进,提供了更快的数据传输速度.更长的传输距离.更稳定的连接和更 ...

  4. 用C#开发.NET CF 蓝牙通信模块

    www.itdocx.com 在Windows Mobile软件开发中.Net正扮演着日益重要的角色,我们已经可以看到很多用.Net CF开发的软件,这些软件涉及到了日常应用的方方面面.在智能设备的软 ...

  5. Android Studio开发(六)短距离无线通信——蓝牙通信

    Android Studio开发(六)短距离无线通信--蓝牙通信 Android Studio开发(六)蓝牙通信 一.任务需求 二.短距离无线通信技术(Short-Distance Wirleless ...

  6. 作业六:安卓实现蓝牙通信

    安卓如何实现蓝牙通信? 功能说明 项目结构 核心代码 结果展示 功能说明 该程序主要实现蓝牙通信.具体功能有: 1.搜索附近蓝牙设备,并且能手动与周围设备发起蓝牙通信请求. 2.通信请求建立后,双方可 ...

  7. 物联网开发笔记(53)- 使用Micropython开发ESP32开发板之蓝牙BLE通信

    一.目的 这一节我们学习如何使用我们的ESP32开发板通过蓝牙和手机进行通信. 二.环境 ESP32 + 手机(笔者用的小米10) + Thonny IDE 三.蓝牙介绍 这个知识大家自行百度吧,这里 ...

  8. Qt on Android 蓝牙通信开发

    版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...

  9. Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发

    一.Android Bluetooth现状 在android官网可以了解到android4.2新增了部分新功能,但是对于BT熟悉的人或许开始头疼了,那就是Android4.2引入了一个新的蓝牙协议栈针 ...

最新文章

  1. python打印星星居中_python中怎么打印星星
  2. HMTL/CSS——下拉菜单DEMO
  3. linux下 tar解压 gz解压 bz2等各种解压文件使用方法
  4. 回答朋友的问题(关于 RTEMS 学习)
  5. office高级应用与python综合案例教程_使用Python操作Office——EXCEL
  6. 数据挖掘-目录-impurity
  7. java 因数分解_Java--分解质因数
  8. shader函数整理
  9. 文件夹自动生成目录树(批处理)
  10. ubuntu samba Windows共享 你可能没有权限访问网络资源
  11. 李开复:移动互联网创业看趋势 看好Android
  12. It seems like the kubelet isn‘t running or healthy
  13. 大数据006——Zookeeper
  14. recovery之刷机脚本自定义(解决刷zip文件时出现Status 6错误)
  15. JZOJ8.14(C组)帕秋莉·诺雷姬
  16. 游戏公司的越冬样本:出海和精品化成为新的增长点?
  17. 难,难,难,如何把握分寸感?
  18. JavaScript的关键字详解
  19. php简易在线投票系统,ThinkPHP 框架 简易投票系统
  20. linux与防火墙建立ipsec,ipsec做防火墙

热门文章

  1. 重置vCenter Server Appliance 管理员密码
  2. hashcode原理 / 比较器 / 聚合操作
  3. HTML、CSS综合01——html、标签、表格
  4. 以人为本,以什么人为本?
  5. 如何使用dos命令运行sqlserver
  6. 运行hadoop 命令截图
  7. android 高德地图周边,地点/周边搜索-Android平台-开发指南-高德地图车机版 | 高德地图API...
  8. 微信小程序--微信支付
  9. mybatis 无效列类型
  10. 03-视频处理-视频处理技术方案