Android - 传统蓝牙通信聊天

Android -传统蓝牙通信聊天

技术:java+Android4.4+jdk1.8
运行环境:Android4.4、Android7.0

概述

Android 传统蓝牙的使用,包括开关蓝牙、搜索设备、蓝牙连接、通信等。

详细

原文地址

Android 蓝牙开发(一)蓝牙通信 CSDN

Android 蓝牙开发(一)蓝牙通信 简书

一、准备工作

 

开发环境:

    jdk1.8 

    Eclipse Luna Service Release 1 (4.4.1)

运行环境:

    华为荣耀6(Android4.4)、华为p9(Android7.0)

实现功能:

  • Android 蓝牙开发 (开关蓝牙、搜索设备、蓝牙配对、连接、通信、断开连接等)。

二、代码结构

代码包里面,有两个部分,一个是源码,一个是V7支持包。

屏幕快照 2017-07-20 下午5.54.54.png

三、程序实现-蓝牙通信

1 蓝牙基本操作

 

随着可穿戴设备的流行,研究蓝牙是必不可少的一门技术了。

总结了下蓝牙开发使用的一些东西分享一下。

 

蓝牙权限

首先需要AndroidManifest.xml文件中添加操作蓝牙的权限。

1
2
3
4
< uses-permissionandroid:name = "Android.permission.BLUETOOTH"  />
//允许程序连接到已配对的蓝牙设备。
< uses-permissionandroid:name = "android.permission.BLUETOOTH_ADMIN"  />
//允许程序发现和配对蓝牙设备。

 

BluetoothAdapter

操作蓝牙主要用到的类 BluetoothAdapter类,使用时导包
import android.bluetooth.BluetoothAdapter;
源码具体位置frameworks/base/core/Java/android/bluetooth/BluetoothAdapter.java

BluetoothAdapter 代表本地设备的蓝牙适配器。该BluetoothAdapter可以执行基本的蓝牙任务,例如启
动设备发现,查询配对的设备列表,使用已知的MAC地址实例化一个BluetoothDevice类,并创建一个
BluetoothServerSocket监听来自其他设备的连接请求。

获取蓝牙适配器

1
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

开启蓝牙

1
2
3
4
5
6
7
if (!mBluetoothAdapter.isEnabled()){  
//弹出对话框提示用户是后打开  
Intent enabler =  new  Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
startActivityForResult(enabler, REQUEST_ENABLE);  
       //不做提示,直接打开,不建议用下面的方法,有的手机会有问题。  
       // mBluetoothAdapter.enable();  
}

 

获取本地蓝牙信息

1
2
3
4
5
6
7
8
9
10
11
//获取本机蓝牙名称  
String name = mBluetoothAdapter.getName();  
//获取本机蓝牙地址  
String address = mBluetoothAdapter.getAddress();  
Log.d(TAG, "bluetooth name =" +name+ " address =" +address);  
//获取已配对蓝牙设备  
Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();  
Log.d(TAG,  "bonded device size =" +devices.size());  
for (BluetoothDevice bonddevice:devices){  
     Log.d(TAG,  "bonded device name =" +bonddevice.getName()+ " address" +bonddevice.getAddress());  
}

搜索设备

1
mBluetoothAdapter.startDiscovery();

 

停止搜索

1
mBluetoothAdapter.cancelDiscovery();

搜索蓝牙设备,该过程是异步的,通过下面注册广播接受者,可以监听是否搜到设备。

1
2
3
4
5
6
7
8
IntentFilter filter =  new  IntentFilter();  
//发现设备  
filter.addAction(BluetoothDevice.ACTION_FOUND);  
//设备连接状态改变  
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);  
//蓝牙设备状态改变  
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  
registerReceiver(mBluetoothReceiver, filter);

 

监听扫描结果

通过广播接收者查看扫描到的蓝牙设备,每扫描到一个设备,系统都会发送此广播(BluetoothDevice.ACTION_FOUNDE)。其中参数intent可以获取蓝牙设备BluetoothDevice

该demo中是连接指定名称的蓝牙设备,BLUETOOTH_NAME为"Galaxy Nexus",如果扫描不到,记得改这个蓝牙名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private  BroadcastReceiver mBluetoothReceiver =  new  BroadcastReceiver(){  
         @Override  
         public  void  onReceive(Context context, Intent intent) {  
             String action = intent.getAction();  
             Log.d(TAG, "mBluetoothReceiver action =" +action);  
             if (BluetoothDevice.ACTION_FOUND.equals(action)){ //每扫描到一个设备,系统都会发送此广播。  
                 //获取蓝牙设备  
                 BluetoothDevice scanDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
                 if (scanDevice ==  null  || scanDevice.getName() ==  null return ;  
                 Log.d(TAG,  "name=" +scanDevice.getName()+ "address=" +scanDevice.getAddress());  
                 //蓝牙设备名称  
                 String name = scanDevice.getName();  
                 if (name !=  null  && name.equals(BLUETOOTH_NAME)){  
                     mBluetoothAdapter.cancelDiscovery();  
                     //取消扫描  
                     mProgressDialog.setTitle(getResources().getString(R.string.progress_connecting));                    //连接到设备。  
                     mBlthChatUtil.connect(scanDevice);  
                 }  
             } else  if  (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){  
   
             }
         }          
};

 

 

设置蓝牙可见性

有时候扫描不到某设备,这是因为该设备对外不可见或者距离远,需要设备该蓝牙可见,这样该才能被搜索到。

可见时间默认值为120s,最多可设置300。

 

1
2
3
4
5
6
7
8
9
10
if  (mBluetoothAdapter.isEnabled()) {  
     if  (mBluetoothAdapter.getScanMode() !=   
             BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {  
         Intent discoverableIntent =  new  Intent(  
                 BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
         discoverableIntent.putExtra(  
                 BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,  120 );  
         startActivity(discoverableIntent);  
     }  
}

 

2 服务端

 

 

android 蓝牙之间可以通过SDP协议建立连接进行通信,通信方式类似于平常使用socket。

首先创建BluetoothServerSocket ,BluetoothAdapter中提供了两种创建BluetoothServerSocket 方式,如下图所示为创建安全的RFCOMM Bluetooth socket,该连接是安全的需要进行配对。而通过listenUsingInsecureRfcommWithServiceRecord创建的RFCOMM Bluetooth socket是不安全的,连接时不需要进行配对。

其中的uuid需要服务器端和客户端进行统一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
private  class  AcceptThread  extends  Thread {  
         // 本地服务器套接字  
         private  final  BluetoothServerSocket mServerSocket;  
         public  AcceptThread() {           
             BluetoothServerSocket tmp =  null ;  
             // 创建一个新的侦听服务器套接字  
             try  {  
                 tmp = mAdapter.listenUsingRfcommWithServiceRecord(  
                         SERVICE_NAME, SERVICE_UUID);  
                 //tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME, SERVICE_UUID);  
             catch  (IOException e) {  
                 Log.e(TAG,  "listen() failed" , e);  
             }  
             mServerSocket = tmp;  
         }  
   
         public  void  run() {  
             BluetoothSocket socket =  null ;  
             // 循环,直到连接成功  
             while  (mState != STATE_CONNECTED) {  
                 try  {  
                     // 这是一个阻塞调用 返回成功的连接  
                     // mServerSocket.close()在另一个线程中调用,可以中止该阻塞  
                     socket = mServerSocket.accept();  
                 catch  (IOException e) {  
                     Log.e(TAG,  "accept() failed" , e);  
                     break ;  
                 }  
                 // 如果连接被接受  
                 if  (socket !=  null ) {  
                     synchronized  (BluetoothChatUtil. this ) {  
                         switch  (mState) {  
                         case  STATE_LISTEN:  
                         case  STATE_CONNECTING:  
                             // 正常情况。启动ConnectedThread。  
                             connected(socket, socket.getRemoteDevice());  
                             break ;  
                         case  STATE_NONE:  
                         case  STATE_CONNECTED:  
                             // 没有准备或已连接。新连接终止。  
                             try  {  
                                 socket.close();  
                             catch  (IOException e) {  
                                 Log.e(TAG,  "Could not close unwanted socket" , e);  
                             }  
                             break ;  
                         }  
                     }  
                 }  
             }  
             if  (D) Log.i(TAG,  "END mAcceptThread" );  
         }  
   
         public  void  cancel() {  
             if  (D) Log.d(TAG,  "cancel "  this );  
             try  {  
                 mServerSocket.close();  
             catch  (IOException e) {  
                 Log.e(TAG,  "close() of server failed" , e);  
             }  
         }  
}

mServerSocket通过accept()等待客户端的连接(阻塞),直到连接成功或失败。

 

3 客户端

 

客户端主要用来创建RFCOMM socket,并连接服务端。

先扫描周围的蓝牙设备,如果扫描到指定设备则进行连接。mBlthChatUtil.connect(scanDevice)连接到设备,

连接过程主要在ConnectThread线程中进行,先创建socket,方式有两种,

如下代码中是安全的(createRfcommSocketToServiceRecord)。另一种不安全连接对应的函数是createInsecureRfcommSocketToServiceRecord

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private  class  ConnectThread  extends  Thread {  
         private  BluetoothSocket mmSocket;  
         private  final  BluetoothDevice mmDevice;  
         public  ConnectThread(BluetoothDevice device) {  
             mmDevice = device;  
             BluetoothSocket tmp =  null ;  
             // 得到一个bluetoothsocket  
             try  {  
                 mmSocket = device.createRfcommSocketToServiceRecord  
                         (SERVICE_UUID);  
             catch  (IOException e) {  
                 Log.e(TAG,  "create() failed" , e);  
                 mmSocket =  null ;  
             }  
         }  
   
         public  void  run() {  
             Log.i(TAG,  "BEGIN mConnectThread" );  
             try  {   
                 // socket 连接,该调用会阻塞,直到连接成功或失败  
                 mmSocket.connect();  
             catch  (IOException e) {  
                 connectionFailed();  
                 try  { //关闭这个socket  
                     mmSocket.close();  
                 catch  (IOException e2) {  
                     e2.printStackTrace();  
                 }  
                 return ;  
             }  
             // 启动连接线程  
             connected(mmSocket, mmDevice);  
         }  
   
         public  void  cancel() {  
             try  {  
                 mmSocket.close();  
             catch  (IOException e) {  
                 Log.e(TAG,  "close() of connect socket failed" , e);  
             }  
         }  
}

接着客户端socket主动连接服务端。连接过程中会自动进行配对,需要双方同意才可以连接成功。

 

4 数据传输

客户端与服务端连接成功后都会调用connected(mmSocket, mmDevice),创建一个ConnectedThread线程()。

该线程主要用来接收和发送数据。客户端和服务端处理方式一样。该线程通过socket获得输入输出流。

 

private  InputStream mmInStream = socket.getInputStream();

private  OutputStream mmOutStream =socket.getOutputStream();

发送数据

1
2
3
4
5
6
7
8
9
10
public  void  write( byte [] buffer) {  
     try  {  
         mmOutStream.write(buffer);  
         // 分享发送的信息到Activity  
         mHandler.obtainMessage(MESSAGE_WRITE, - 1 , - 1 , buffer)  
                 .sendToTarget();  
     catch  (IOException e) {  
         Log.e(TAG,  "Exception during write" , e);  
     }  
}

 

接收数据

 

线程循环进行接收数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  void  run() {  
     // 监听输入流  
     while  ( true ) {  
         try  {  
             byte [] buffer =  new  byte [ 1024 ];  
             // 读取输入流  
             int  bytes = mmInStream.read(buffer);  
             // 发送获得的字节的ui activity  
             Message msg = mHandler.obtainMessage(MESSAGE_READ);  
             Bundle bundle =  new  Bundle();  
             bundle.putByteArray(READ_MSG, buffer);  
             msg.setData(bundle);  
             mHandler.sendMessage(msg);            
         catch  (IOException e) {  
             Log.e(TAG,  "disconnected" , e);  
                 connectionLost();  
                 break ;  
             }  
         }  
}

 

四、运行效果

1、运行,右键项目:Run as -》Android Application   (备注:Eclipse需要配置Android开发环境)

2、运行效果如下: 

 

客户端 

1500550538898087682.jpeg

 

服务端

Screenshot_2017-07-20-19-26-57.png

 

出处:http://www.demodashi.com/demo/10676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Uni-app 是一个基于Vue.js框架开发的跨平台应用开发框架,可以同时开发iOS、Android和Web应用。在Uni-app中进行蓝牙通信可以通过uni.bluetooth API来实现。 首先,你需要在manifest.json文件中配置蓝牙权限,具体配置如下: ```json { "mp-weixin": { "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" }, "scope.userInfo": { "desc": "你的昵称、头像、地区及性别信息将用于小程序用户接口的效果展示" }, "scope.record": { "desc": "你的语音将用于小程序语音识别接口的效果展示" }, "scope.writePhotosAlbum": { "desc": "你的相册图片将用于小程序界面展示" }, "scope.camera": { "desc": "你的相机功能将用于小程序界面展示" }, "scope.bluetooth": { "desc": "你的蓝牙信息将用于小程序蓝牙接口的效果展示" } } } } ``` 然后,在你的页面中通过uni.openBluetoothAdapter()方法来打开蓝牙适配器,代码如下: ```javascript uni.openBluetoothAdapter({ success: function (res) { console.log('蓝牙适配器打开成功') }, fail: function (res) { console.log('蓝牙适配器打开失败') } }) ``` 接下来,你可以使用uni.startBluetoothDevicesDiscovery()方法来开始搜索附近的蓝牙设备,代码如下: ```javascript uni.startBluetoothDevicesDiscovery({ success: function (res) { console.log('开始搜索蓝牙设备') }, fail: function (res) { console.log('搜索蓝牙设备失败') } }) ``` 当搜索到蓝牙设备后,你可以使用uni.getBluetoothDevices()方法来获取设备列表,代码如下: ```javascript uni.getBluetoothDevices({ success: function (res) { console.log('获取蓝牙设备列表成功') // 获取到的设备列表在res.devices中 }, fail: function (res) { console.log('获取蓝牙设备列表失败') } }) ``` 最后,你可以使用uni.createBLEConnection()方法来连接指定的蓝牙设备,代码如下: ```javascript uni.createBLEConnection({ deviceId: '你要连接的设备的deviceId', success: function (res) { console.log('蓝牙设备连接成功') }, fail: function (res) { console.log('蓝牙设备连接失败') } }) ``` 以上是Uni-app中进行蓝牙通信的基本步骤,具体的操作和逻辑根据你的需求进行调整。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值