蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。蓝牙技术最初由电信巨头爱立信公司于1994年创制,当时是作为RS232数据线的替代方案。

蓝牙的基本功能:

  • 扫描其他蓝牙设备
  • 为可配对蓝牙设备查询蓝牙适配器。
  • 建立RFCOMM通道
  • 通过服务搜索来连接其他设备。
  • 与其他设备进行数据传输。
  • 管理多个连接

使用蓝牙进行通信的必要四步:

  • 打开蓝牙;
  • 查找附近已配对或可用的设备;
  • 连接设备;
  • 设备间数据交换。

所有蓝牙API都在android.bluetooth 包下.下面有一些类和接口的摘要,可能需要它们来建立蓝牙连接:

BluetoothAdapter

代表本地蓝牙适配器(蓝牙无线电)。BluetoothAdapter是所有蓝牙交互的入口。使用这个你可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。

BluetoothDevice

代表一个远程蓝牙设备,使用这个来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。

BluetoothSocket

代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。

BluetoothServerSocket

代表一个开放的服务器socket,它监听接受的请求(与TCP ServerSocket类似)。为了连接两台Android设备,一个设备必须使用这个类开启一个服务器socket。当一个远程蓝牙设备开始一个和该设备的连接请求,BluetoothServerSocket将会返回一个已连接的BluetoothSocket,接受该连接。

BluetoothClass

描述一个蓝牙设备的基本特性和性能。这是一个只读的属性集合,它定义了设备的主要和次要的设备类以及它的服务。但是,它没有描述所有的蓝牙配置和设备支持的服务,它只是暗示了设备的类型。

BluetoothProfile

一个表示蓝牙配置文件的接口。一个Bluetooth profile是一个基于蓝牙的通信无线接口定义。一个例子是Hands-Free profile。更多的讨论请见Working with Profiles。

BluetoothHeadset

提供对移动手机使用的蓝牙耳机的支持。它包含了Headset and Hands-Free (v1.5)配置文件。

BluetoothA2dp

定义高品质的音频如何通过蓝牙连接从一个设备传输到另一个设备。”A2DP“是Advanced Audio Distribution Profile的缩写。

BluetoothHealth

表示一个Health Device Profile代理,它控制蓝牙服务。

BluetoothHealthCallback

一个抽象类,你可以使用它来实现BluetoothHealth的回调函数。你必须扩展这个类并实现回调函数方法来接收应用程序的注册状态改变以及蓝牙串口状态的更新。

BluetoothHealthAppConfiguration

表示一个应用程序配置,Bluetooth Health第三方应用程序注册和一个远程Bluetooth Health设备通信。

BluetoothProfile.ServiceListener

一个接口,当BluetoothProfile IPC客户端从服务器上建立连接或断开连接时,它负责通知它们(也就是,运行在特性配置的内部服务)

使用蓝牙需要在配置文件Androidmanifest.xml 中注册两种权限:

//获取蓝牙适配器
<uses-permission android:name="android.permission.BLUETOOTH" />
//蓝牙开启或关闭权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

一、蓝牙搜索

1.获取蓝牙适配器:

private BluetoothAdapter mBluetoothAdapter;

mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter();

Attention:一定要在真机上调试,AndroidStudio上建立的AVD没有蓝牙模块,可以先进行一下判断:

if(mBluetoothAdapter == null){Toast.makeText(this, "Bluetooth is not supported on the device", Toast.LENGTH_LONG).show();return;
}

2.开启蓝牙:

//判断蓝牙是否开启,如未开启则强制开启
if (!mBluetoothAdapter.isEnabled()) {//注释掉的方法为提示窗口开启,部分系统(如EMUI)开启蓝牙自带提示窗,故而用这种方法可能会有两个提示窗/*Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivity(intent);startActivityForResult(intent, REQUEST_CODE_BLUETOOTH_ON);*/mBluetoothAdapter.enable();
}

蓝牙打开有三种方式:

  • enable()直接强制打开
  • 上面注释掉的方法为提示窗打开,本人亲测华为荣耀8这种方式会出现两次提示窗,故而弃用
  • 打开蓝牙并设置可见时间,具体代码就不贴了,到处都是。

3.蓝牙广播

首先使用蓝牙广播要注册蓝牙广播接收者,我们用的是动态注册的方式,即在程序中使用Context.registerReceiver注册。还有一种静态注册方式是在AndroidManifest.xml文件中定义。

IntentFilter filter=new IntentFilter();
//发现设备
filter.addAction(BluetoothDevice.ACTION_FOUND);
//连接断开
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
//完成扫描
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//设备连接状态改变
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mReceiver,filter);

注册完之后就是定义蓝牙广播接收者啦:

// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver=new BroadcastReceiver(){private List<BluetoothDevice> bondedlist = new ArrayList <>();private List<BluetoothDevice> surroundList = new ArrayList <>();@Overridepublic void onReceive(Context context, Intent intent) {switch (intent.getAction()){case BluetoothDevice.ACTION_FOUND:BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if(device.getBondState() != BluetoothDevice.BOND_BONDED){if (!surroundList.contains(device)) {surroundList.add(device);}System.out.println("設備列表:"+surroundList);// 为listview设置字符换数组适配器,搜索附近未配对设备SimpleAdapter simAdapter = new SimpleAdapter(MainActivity.this, getDeviceList(surroundList), android.R.layout.simple_list_item_2,new String[] { "name" , "address"}, new int[] {android.R.id.text1, android.R.id.text2});surroundDevices.setAdapter(simAdapter);setListViewHeightBasedOnChildren(surroundDevices);}//已配对设备信息bondedlist = new ArrayList <>(mBluetoothAdapter.getBondedDevices());System.out.println("BondedList:"+bondedlist);// 为listview设置字符换数组适配器SimpleAdapter simAdapter = new SimpleAdapter(MainActivity.this, getDeviceList(bondedlist), android.R.layout.simple_list_item_2,new String[] { "name" , "address"}, new int[] {android.R.id.text1, android.R.id.text2});// 为listView绑定适配器bondedDevices.setAdapter(simAdapter);setListViewHeightBasedOnChildren(bondedDevices);break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:statusText.setText("DISCOVERY_FINISHED");break;case BluetoothDevice.ACTION_BOND_STATE_CHANGED:BluetoothDevice device1 = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.e("STATE:","address:"+device1.getAddress()+"\nname:"+device1.getName());switch (device1.getBondState()){case BluetoothDevice.BOND_BONDING:Log.i("STATE", "正在与" + device1.getName() + "__" + device1.getAddress() + "配对");statusText.setText("正在与" + device1.getName() +"进行配对");break;case BluetoothDevice.BOND_BONDED:Log.i("STATE", "与" + device1.getName() + "__" + device1.getAddress() + "完成配对");statusText.setText("与" + device1.getName() + "配对完成");break;case BluetoothDevice.BOND_NONE:Log.i("STATE", "取消与" + device1.getName() + "__" + device1.getAddress() + "配对");statusText.setText("与" + device1.getName() + "配对取消");default:break;}break;case  BluetoothDevice.ACTION_ACL_DISCONNECTED:statusText.setText("Disconnected");break;}}
};

4.开始搜索,触发广播

通过  BluetoothAdapter中startDiscovery( )方法来开始广播。当广播的事件是我们刚刚注册的事件时就会触发广播接收器,并且触发广播接收器中的onReceiver()方法。

二、蓝牙通信

蓝牙配对我偷了个懒,直接在系统设置蓝牙里面配对的,因为做这个的时候主要实现的就是通信啦~

1.蓝牙连接和通信,我把它们写到了一起~

/*** 发送信息到另一个蓝牙设备** @param message 信息*/private void sendMessage(String message) {if (address==null||"".equals(address)){Toast.makeText(MainActivity.this,"未连接任何设备",Toast.LENGTH_SHORT).show();return;}try {mBluetoothAdapter.cancelDiscovery();Log.e(TAG, "sendMessage: 1");if (null == bluetoothDevice) {bluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);}Log.e(TAG, "sendMessage: 2");if (bluetoothSocket == null) {bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);bluetoothSocket.connect();outputStream = bluetoothSocket.getOutputStream();Message msg1 = new Message();msg1.obj = new String(bluetoothSocket.getRemoteDevice().getName().getBytes("utf-8"), "utf-8");msg1.what = 3;mHandler.sendMessage(msg1);}Log.e(TAG, "sendMessage: 3");if (!bluetoothSocket.isConnected()) {resetSocket();}Log.e(TAG, "sendMessage: 4");if (outputStream != null) {try {outputStream.write((message.getBytes("utf-8")));Log.e(TAG, "onItemClick: " + mBluetoothAdapter.getName() + ":" + message);Message msg = new Message();msg.obj = new String(message.getBytes("utf-8"), "utf-8");msg.what = 0;mHandler.sendMessage(msg);} catch (Exception e) {resetSocket();sendMessage(message);}}} catch (Exception e) {Toast.makeText(MainActivity.this,"建立连接失败",Toast.LENGTH_SHORT).show();e.printStackTrace();}}private void resetSocket() {try {bluetoothSocket.close();bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);bluetoothSocket.connect();outputStream = bluetoothSocket.getOutputStream();Message msg1 = new Message();msg1.obj = new String(bluetoothSocket.getRemoteDevice().getName().getBytes("utf-8"), "utf-8");msg1.what = 3;mHandler.sendMessage(msg1);} catch (IOException e) {e.printStackTrace();}}

2.服务端接收线程:

private class AcceptThread extends Thread {private BluetoothServerSocket mBluetoothServerSocket;private BluetoothSocket bluetoothSocket;private InputStream is;private OutputStream os;private boolean isContinue;AcceptThread() {try {mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("bluetooth_socket", MY_UUID);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {while (true) {try {if (mBluetoothServerSocket == null) {return;}bluetoothSocket = mBluetoothServerSocket.accept();serverBleName = bluetoothSocket.getRemoteDevice().getName();Log.e(TAG, "run: accept");is = bluetoothSocket.getInputStream();os = bluetoothSocket.getOutputStream();Message msg = new Message();msg.obj = new String(serverBleName.getBytes("utf-8"), "utf-8");msg.what = 4;mHandler.sendMessage(msg);isContinue = true;while (isContinue) {byte[] buffer = new byte[128];int count = is.read(buffer);Message message = new Message();message.obj = new String(buffer, 0, count, "utf-8");message.what = 1;mHandler.sendMessage(message);}} catch (IOException e) {e.printStackTrace();isContinue = false;} finally {try {if (bluetoothSocket != null) {bluetoothSocket.close();}} catch (IOException e) {e.printStackTrace();}}}}}

3.更新界面UI线程

private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {//Toast.makeText(MainActivity.this, String.valueOf(msg.obj), Toast.LENGTH_SHORT).show();switch (msg.what){//send messagecase 0:receiveText.append("Me : "+String.valueOf(msg.obj)+"\n");break;//receive messagecase 1:receiveText.append(serverBleName + " : "+String.valueOf(msg.obj)+"\n");break;//connect servercase 3:statusText.setText("Connnected to "+String.valueOf(msg.obj));break;//connectclientcase 4:statusText.setText("Connnected to "+String.valueOf(msg.obj));break;}return false;}});

三、结果展示

下面是各个阶段的截图

             

   

Android蓝牙搜索连接通信相关推荐

  1. Android蓝牙A2DP连接实现

    代码地址如下: http://www.demodashi.com/demo/14624.html 开发环境: 开发工具:Androidstudio 适配机型:honor8(Android6.0), 坚 ...

  2. android 蓝牙自动断开,Android蓝牙:连接()/断开()

    我目前正在设计一个应用程序,它需要连接到设备,写入/读取数据,并可靠地关闭连接.目前我有写/读固体.我的断开连接然后重新连接非常不可靠,并且经常实际上使手机崩溃.我一直在寻找通过大量文章试图弄清楚和. ...

  3. android 蓝牙搜索、配对连接通信总结

    蓝牙协议可以实现一个蓝牙设备和6到8个蓝牙设备进行通信. 1.蓝牙搜索的实现 利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备. 第一步,获得蓝牙适配器 BluetoothAdapter mBt ...

  4. Android 低功耗蓝牙BLE连接通信

    目录 简介 蓝牙 4.0 BLE与蓝牙4.0的区别 BLE的特点 主要特性 技术细节 BLE的应用 BLE的体系结构 BLE设备链路层状态 就绪态 广播态 扫描态 发起态 连接状态 通信基本过程 两种 ...

  5. android 实现蓝牙自动配对连接,Android实践 -- Android蓝牙设置连接

    蓝牙开发相关 使用Android Bluetooth APIs将设备通过蓝牙连接并通信,设置蓝牙,查找蓝牙设备,配对蓝牙设备 连接并传输数据,以下是Android系统提供的蓝牙相关的类和接口 Blue ...

  6. Android 蓝牙BLE串口通信之高低位转换、16进制字符串转换float浮点型

    蓝牙技术的普及与发展,为传统设备提供了一种低成本无线通信的方式.串口作为一种使用广泛的通信接口,通过串口转蓝牙,进行无线通信传输的需求逐渐展现出来. 蓝牙串口模块是嵌入式设备上的常用模块,它可以方便地 ...

  7. android 蓝牙自动连接,蓝牙自动连接实现

    实现的主要功能(蓝牙配对成功如何与远程设备一直连接) 1.当蓝牙配对成功连接时,断开远程端设备会自动连接 2.当设备长时间锁屏会导致CachedBluetoothDevice自动清空,如果蓝牙断开就不 ...

  8. android 蓝牙串口连接不上,安卓手机搜索不到蓝牙模块HC-06,是怎么回事?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 问题0010:蓝牙串口模块使用的正确步骤 很多人现在都开始使用蓝口模块,利用手机蓝牙或者PC蓝牙进行控制单片机系统.但是很多人一上来就直接把蓝牙模块和单片 ...

  9. android 蓝牙搜索代码,关于蓝牙设备搜索和Ble设备的搜索的简单调用方法

    最近一段时间一直在调试蓝牙设备,论坛里面关于这方面资料的太少,特别是关于蓝牙4.0的案例,基本上没有,也只好摸石头过河了.目前的代码也就勉强能用,我希望在此抛砖引玉,大家一起来完善这一部分. 说明一下 ...

最新文章

  1. 漫漫运维路——集群基础知识
  2. LoRaWAN与LoRa的区别!
  3. 4kyu Twice linear
  4. linux递归创建文件夹_Python中并发请求创建文件夹带来的线程安全问题
  5. thinkphp v5.0.11漏洞_thinkphp 5.0 代码执行漏洞
  6. CompactExifLib:访问JPEG文件中的EXIF标签
  7. java与javac版本不一致问题
  8. React --获取服务器数据的两种方式(Axios和FetchJsonp)
  9. java php 通讯录,基于ssh/bs/java/asp.net/php/web通讯录管理系统
  10. 各层电子数排布规则_原子核外电子排布规律性质-1~36号原子结构示意图-电子层排布规律...
  11. python在excel中插入折线图_Python-使用XlsxWriter模块在Excel工作表中绘制折线图
  12. 50个查询系列-第七个查询:查询学过“叶平”老师所教的所有课的同学的学号、姓名...
  13. 环信java_java环信服务端注册IM代码
  14. Machine Learning-数学基础2
  15. Repeated measures ANOVA with R
  16. 银行家算法—简单易懂解题思路
  17. byteTrack数据集categories不规范带来的问题
  18. 修改IBM MQ CCSID
  19. java QQ客户端
  20. Android Hawk数据库

热门文章

  1. 电脑的显卡驱动需要更新吗?
  2. win10计算机停止工作,360重装Win10系统后如何应对已停止工作提示的办法
  3. 如何检查投标文件以及常见错误?
  4. 使用 Windows XP 的外观风格
  5. USB组合设备——带鼠标功能的键盘
  6. CommonUtils 工具类
  7. android+判断wifi+5g,Android判断wifi是5G还是2.4G
  8. python 各类距离公式实现
  9. java.lang.IllegalStateException: Underflow in restore - more restores than saves
  10. 00_00 python机器学习_各章实例代码汇总(随学习进度更新)