Android -传统蓝牙通信聊天
概述
详细
原文地址:
Android 蓝牙开发(一)蓝牙通信 CSDN
一、准备工作
开发环境:
jdk1.8
Eclipse Luna Service Release 1 (4.4.1)
运行环境:
华为荣耀6(Android4.4)、华为p9(Android7.0)
实现功能:
Android 蓝牙开发 (开关蓝牙、搜索设备、蓝牙配对、连接、通信、断开连接等)。
二、代码结构
代码包里面,有两个部分,一个是源码,一个是V7支持包。

三、程序实现-蓝牙通信
1 蓝牙基本操作
随着可穿戴设备的流行,研究蓝牙是必不可少的一门技术了。
总结了下蓝牙开发使用的一些东西分享一下。
蓝牙权限
首先需要AndroidManifest.xml文件中添加操作蓝牙的权限。
<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监听来自其他设备的连接请求。
获取蓝牙适配器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
开启蓝牙
if(!mBluetoothAdapter.isEnabled()){
//弹出对话框提示用户是后打开
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler, REQUEST_ENABLE);
//不做提示,直接打开,不建议用下面的方法,有的手机会有问题。
// mBluetoothAdapter.enable();
}
获取本地蓝牙信息
//获取本机蓝牙名称
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());
}
搜索设备
mBluetoothAdapter.startDiscovery();
停止搜索
mBluetoothAdapter.cancelDiscovery();
搜索蓝牙设备,该过程是异步的,通过下面注册广播接受者,可以监听是否搜到设备。
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",如果扫描不到,记得改这个蓝牙名称。
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。
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需要服务器端和客户端进行统一。
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。
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();
发送数据
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);
}
}
接收数据
线程循环进行接收数据。
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、运行效果如下:
客户端

服务端

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
Android -传统蓝牙通信聊天的更多相关文章
- Android - 传统蓝牙通信聊天
Android -传统蓝牙通信聊天 技术:java+Android4.4+jdk1.8 运行环境:Android4.4.Android7.0 概述 Android 传统蓝牙的使用,包括开关蓝牙.搜索设 ...
- Android 串口蓝牙通信开发Java版本
Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...
- Android - 传统蓝牙(蓝牙2.0)
Android Bluetooth 源码基于 Android L [TOC] Reference BluetoothAdapter 首先调用静态方法getDefaultAdapter()获取蓝牙适配器 ...
- Android蓝牙通信
Android为蓝牙设备之间的通信封装好了一些调用接口,使得实现Android的蓝牙通信功能并不困难.可通过UUID使两个设备直接建立连接. 具体步骤: 1. 获取BluetoothAdapter实例 ...
- Android学习笔记之蓝牙通信...
PS:最近同学问我蓝牙的事,因此自己也就脑补了一下蓝牙... 学习内容: 1.如何实现蓝牙通信技术... 蓝牙通信其实是手机里很常用的一种通信方式,现在的手机中是必然存在蓝牙的,蓝牙通信也是有一部 ...
- Android BLE设备蓝牙通信框架BluetoothKit
BluetoothKit是一款功能强大的Android蓝牙通信框架,支持低功耗蓝牙设备的连接通信.蓝牙广播扫描及Beacon解析. 关于该项目的详细文档请关注:https://github.com/d ...
- Android蓝牙通信总结
这篇文章要达到的目标: 1.介绍在Android系统上实现蓝牙通信的过程中涉及到的概念. 2.在android系统上实现蓝牙通信的步骤. 3.在代码实现上的考虑. 4.例子代码实现(手持设备和蓝牙串口 ...
- Qt on Android 蓝牙通信开发
版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...
- Android蓝牙通信具体解释
蓝牙通信的大概过程例如以下: 1.首先开启蓝牙 2,搜索可用设备 3,创建蓝牙socket.获取输入输出流 4,读取和写入数据 5.断开连接关闭蓝牙 还要发送配对码发送进行推断! 以下是全部的源码:不 ...
随机推荐
- shell实例练习+详解
想着将Shell与Python和Java等脚本比较比较,当一有这个念头我就放弃了.这太侮辱Shell了.(哭笑脸!) 作为一个程序员,Linux那是最基本要求.而shell脚本有时候也会显示它在Lin ...
- 2017-06-22(locate shutdown half poweroff init0 reboot init 6)
locate locate 文件搜索命令 格式:locate [文件名] locate 在后台数据库中(/var/lib/mlocate/mlocate.db)按文件名搜索,速度快 刚刚新建的文件, ...
- Hystrix-异常处理
异常的传播和捕获 传播:在HystrixCommand实现的run()方法中跑出异常时,除了HystrixBadRequestException之外,其他异常均会被Hystrix认为命令执行失败并处罚 ...
- DS18B20温度传感器知识点总结
2018-01-1818:20:48 感觉自己最近有点凌乱,一个很简单的问题都能困扰自己很久.以前能很好使用和调试的DS18B20温度传感器,今天愣是搞了很久,妈卖批. 仅仅一个上拉电阻就困扰了我很久 ...
- 基于 HTML5 的 3D 工控隧道案例
隧道的项目我目前是第一次接触,感觉做起来的效果还蛮赞的,所以给大家分享一下.这个隧道项目的主要内容包括:照明.风机.车道指示灯.交通信号灯.情报板.消防.火灾报警.车行横洞.风向仪.COVI.微波车检 ...
- 提示让IE8以下版本的浏览器去更新浏览器
需求: 强制让IE进行页面渲染时候,用最新的方式渲染,并提示让IE8以下的版本去更新浏览器并给一个连接地址 那,如何满足? <!DOCTYPE html> <html lang=&q ...
- 微信屏蔽js分享、复制链接
页面内引入js(不放在页面内部不起作用) $(function(){ function onBridgeReady() { WeixinJSBridge.call('hideOptionMenu'); ...
- mybatis 中文文档
http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
- jsp的语法
JSP指令和脚本元素指令 <%@ 指令%>声明 <%! 声明%>表达式 <%= 表达式%>代码段/脚本段 <% 代码段%>注释 <%-- 注释-- ...
- 【转】How to append current date and timestamp to filename in shell script
$ date +"FORMAT" now=$(date +"%Y-%m-%d-%S") filename="my_program.$now.log&q ...