蓝牙的基础知识我就不讲了,有兴趣可以看下我之前写的博客,现在我们要做的就是实现两个蓝牙之间的通讯,并且实现聊天功能,这里大家准备两个手机即可。

我们先按照流程走一遍,首先是验证一下设备是否支持蓝牙,一般都是支持的

if (!BtManager.getInstance().isSupport()) {Toast.makeText(this, "当前设备不支持蓝牙", Toast.LENGTH_SHORT).show();return;
}

然后验证一下是否打开了蓝牙

BtManager.getInstance().open();

我对蓝牙的相关Api是做了一些封装的,紧接着我获取到他之前配对过的设备

Set<BluetoothDevice> mBondedList = BtManager.getInstance().getBondedDevices();
for (BluetoothDevice device : mBondedList) {addModel(device.getName(), device.getAddress());
}

这里要注意一点的是,我们需要添加权限

 <uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

ACCESS_COARSE_LOCATION是后面Android6.0新需要的权限,不然搜索设备是获取不到的

    private void requestPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);} else {startDiscovery();}} else {startDiscovery();}}private void startDiscovery() {BtManager.getInstance().startDiscovery();}

紧接着在在回调中接收结果

    @Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {for (int i = 0; i < permissions.length; i++) {if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {int result = grantResults[i];if (result == PackageManager.PERMISSION_GRANTED) {startDiscovery();} else {requestPermission();}}}}

如果同意了此权限就直接搜索设备了,搜索设备我们会需要用到两个广播

        mBtFoundReceiver = new BtFoundReceiver();IntentFilter filter = new IntentFilter();//搜索结果filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索完成filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(mBtFoundReceiver, filter);

这样我们就可以接收到他返回的列表了

    class BtFoundReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {//判断是否配对过if (device.getBondState() != BluetoothDevice.BOND_BONDED) {addModel(device.getName(), device.getAddress());}}} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {}}}

如图

所以主页的全部代码如下:

package com.liuguilin.iot_bt;import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.Window;
import android.widget.Toast;import com.liuguilin.iot_bt.adapter.BtListAdapter;
import com.liuguilin.iot_bt.manager.BtManager;
import com.liuguilin.iot_bt.model.BtListModel;import java.util.ArrayList;
import java.util.List;
import java.util.Set;/*** IOT系列博客 —— BT 通讯* 作者:刘桂林*/
public class MainActivity extends AppCompatActivity {public static final String TAG = "IOT_BT";public static final int PERMISSION_REQUEST_COARSE_LOCATION = 1001;private RecyclerView mBtListRyView;private BtListAdapter mBtListAdapter;private List<BtListModel> mList = new ArrayList<>();private BtFoundReceiver mBtFoundReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {mBtListRyView = (RecyclerView) findViewById(R.id.mBtListRyView);mBtListRyView.setLayoutManager(new LinearLayoutManager(this));mBtListAdapter = new BtListAdapter(this, mList);mBtListRyView.setAdapter(mBtListAdapter);mBtListAdapter.setOnItemClickListener(new BtListAdapter.OnItemClickListener() {@Overridepublic void OnClick(int i) {BtManager.getInstance().cancelDiscovery();Intent intent = new Intent(MainActivity.this, ChatActivity.class);BtListModel model = mList.get(i);intent.putExtra("name", model.getName());intent.putExtra("address", model.getAddress());startActivity(intent);}});mBtFoundReceiver = new BtFoundReceiver();IntentFilter filter = new IntentFilter();//搜索结果filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索完成filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(mBtFoundReceiver, filter);if (!BtManager.getInstance().isSupport()) {Toast.makeText(this, "当前设备不支持蓝牙", Toast.LENGTH_SHORT).show();return;}BtManager.getInstance().open();Set<BluetoothDevice> mBondedList = BtManager.getInstance().getBondedDevices();for (BluetoothDevice device : mBondedList) {addModel(device.getName(), device.getAddress());}requestPermission();}private void requestPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);} else {startDiscovery();}} else {startDiscovery();}}private void startDiscovery() {BtManager.getInstance().startDiscovery();}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(mBtFoundReceiver);}class BtFoundReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {//判断是否配对过if (device.getBondState() != BluetoothDevice.BOND_BONDED) {addModel(device.getName(), device.getAddress());}}} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {}}}/*** 添加数据** @param name* @param address*/private void addModel(String name, String address) {Log.e(TAG, "name:" + name + "address:" + address);if (TextUtils.isEmpty(name)) {return;}if (TextUtils.isEmpty(address)) {return;}boolean isAdd = false;for (int i = 0; i < mList.size(); i++) {if (mList.get(i).getAddress().equals(address)) {isAdd = true;}}if (isAdd) {return;}BtListModel model = new BtListModel();model.setName(name);model.setAddress(address);mList.add(model);mBtListAdapter.notifyDataSetChanged();}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {for (int i = 0; i < permissions.length; i++) {if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {int result = grantResults[i];if (result == PackageManager.PERMISSION_GRANTED) {startDiscovery();} else {requestPermission();}}}}
}

再来看下封装的蓝牙管理类

package com.liuguilin.iot_bt.manager;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.content.Intent;import java.io.IOException;
import java.util.Set;
import java.util.UUID;/*** FileName: BtManager* Founder: LiuGuiLin* Create Date: 2019/2/12 11:39* Email: lgl@szokl.com.cn* Profile: 蓝牙控制管理类*/
public class BtManager {private static BtManager mInstance = null;private BluetoothAdapter mBluetoothAdapter;private BtManager() {mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();}public static BtManager getInstance() {if (mInstance == null) {synchronized (BtManager.class) {if (mInstance == null) {mInstance = new BtManager();}}}return mInstance;}/*** 是否支持** @return*/public boolean isSupport() {return mBluetoothAdapter != null;}/*** 是否打开** @return*/public boolean isEnabled() {return mBluetoothAdapter.isEnabled();}/*** 开关 无提示*/public void open() {if (!isEnabled()) {mBluetoothAdapter.enable();}}/*** 开关 有提示** @param mActivity* @param requestCode*/public void open(Activity mActivity, int requestCode) {if (!isEnabled()) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);mActivity.startActivityForResult(intent, requestCode);}}/*** 获取已配对列表** @return*/public Set<BluetoothDevice> getBondedDevices() {return mBluetoothAdapter.getBondedDevices();}/*** 是否在搜索** @return*/public boolean isDiscovering() {return mBluetoothAdapter.isDiscovering();}/*** 开始搜索*/public void startDiscovery() {if (!isDiscovering()) {mBluetoothAdapter.startDiscovery();}}/*** 停止搜索*/public void cancelDiscovery() {if (isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}}/*** 获取远程设备** @param address* @return*/public BluetoothDevice getRemoteDevice(String address) {return mBluetoothAdapter.getRemoteDevice(address);}/*** 获取客户端设备* @param name* @param uuid* @return*/public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) {try {return mBluetoothAdapter.listenUsingRfcommWithServiceRecord(name, uuid);} catch (IOException e) {e.printStackTrace();}return null;}
}

好了,我们重点回到如何建立连接上,我们也知道,当我们点击设备的时候会跳转ChatActivity

                Intent intent = new Intent(MainActivity.this, ChatActivity.class);BtListModel model = mList.get(i);intent.putExtra("name", model.getName());intent.putExtra("address", model.getAddress());startActivity(intent);

那ChatActivity拿到这两个参数之后会做什么呢?

首先,会创建一个AcceptThread循环读取远程端发送过来的消息

private class AcceptThread extends Thread {// 服务端接口private BluetoothServerSocket serverSocket;// 获取到客户端的接口private BluetoothSocket socket;// 获取到输入流private InputStream is;public AcceptThread() {serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);}@Overridepublic void run() {try {// 接收其客户端的接口socket = serverSocket.accept();// 获取到输入流is = socket.getInputStream();while (true) {// 创建一个128字节的缓冲byte[] buffer = new byte[128];// 每次读取128字节,并保存其读取的角标int count = is.read(buffer);// 创建Message类,向handler发送数据Message msg = new Message();// 发送一个String的数据,让他向上转型为obj类型msg.obj = new String(buffer, 0, count, "utf-8");// 发送数据mHandler.sendMessage(msg);}} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}}

所以我们接收到数据,则是在这里获取到的,然后我们才申请建立连接

    /*** 建立连接** @param address*/private void connetSocket(String address) {if (selectDevice == null) {//通过地址获取到该设备selectDevice = BtManager.getInstance().getRemoteDevice(address);}try {if (clientSocket == null) {// 获取到客户端接口clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);// 向服务端发送连接clientSocket.connect();// 获取到输出流,向外写数据os = clientSocket.getOutputStream();}sendText("连接成功");} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}

建立连接以后我们就可以发送数据了

    /*** 发送消息** @param text*/private void sendText(final String text) {if (!TextUtils.isEmpty(text)) {if (os != null) {// 以utf-8的格式发送出去try {os.write(text.getBytes("UTF-8"));mHandler.post(new Runnable() {@Overridepublic void run() {addLeft(text);}});Log.e(MainActivity.TAG, text);} catch (IOException e) {Toast.makeText(this, "消息发送失败:" + e.toString(), Toast.LENGTH_SHORT).show();}} else {Toast.makeText(this, "设备未连接", Toast.LENGTH_SHORT).show();}}}

与此同时,对方的AcceptThread就会收到我们的消息然后达成互相通信的功能

如图

我们来看下ChatActivity的所有代码

package com.liuguilin.iot_bt;import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import com.liuguilin.iot_bt.adapter.ChatListAdapter;
import com.liuguilin.iot_bt.manager.BtManager;
import com.liuguilin.iot_bt.model.ChatListModel;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;/*** FileName: ChatActivity* Founder: LiuGuiLin* Create Date: 2019/2/12 15:52* Email: lgl@szokl.com.cn* Profile:聊天*/
public class ChatActivity extends AppCompatActivity implements View.OnClickListener {private RecyclerView mChatRyView;private EditText et_text;private Button btn_send;private ChatListAdapter mChatListAdapter;private List<ChatListModel> mList = new ArrayList<>();// UUID,蓝牙建立链接需要的private final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");// 为其链接创建一个名称private final String NAME = "Bluetooth_Socket";// 选中发送数据的蓝牙设备,全局变量,否则连接在方法执行完就结束了private BluetoothDevice selectDevice;// 获取到选中设备的客户端串口,全局变量,否则连接在方法执行完就结束了private BluetoothSocket clientSocket;// 获取到向设备写的输出流,全局变量,否则连接在方法执行完就结束了private OutputStream os;// 服务端利用线程不断接受客户端信息private AcceptThread thread;private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {String text = (String) msg.obj;Log.e(MainActivity.TAG, "text:" + text);addRight(text);Toast.makeText(ChatActivity.this, text, Toast.LENGTH_SHORT).show();return false;}});@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat);initView();}private void initView() {mChatRyView = (RecyclerView) findViewById(R.id.mChatRyView);et_text = (EditText) findViewById(R.id.et_text);btn_send = (Button) findViewById(R.id.btn_send);btn_send.setOnClickListener(this);mChatRyView.setLayoutManager(new LinearLayoutManager(this));mChatListAdapter = new ChatListAdapter(this, mList);mChatRyView.setAdapter(mChatListAdapter);Intent intent = getIntent();String name = intent.getStringExtra("name");final String address = intent.getStringExtra("address");getSupportActionBar().setTitle(name);thread = new AcceptThread();thread.start();new Thread(new Runnable() {@Overridepublic void run() {connetSocket(address);}}).start();}/*** 建立连接** @param address*/private void connetSocket(String address) {if (selectDevice == null) {//通过地址获取到该设备selectDevice = BtManager.getInstance().getRemoteDevice(address);}try {if (clientSocket == null) {// 获取到客户端接口clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);// 向服务端发送连接clientSocket.connect();// 获取到输出流,向外写数据os = clientSocket.getOutputStream();}sendText("连接成功");} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}/*** 发送消息** @param text*/private void sendText(final String text) {if (!TextUtils.isEmpty(text)) {if (os != null) {// 以utf-8的格式发送出去try {os.write(text.getBytes("UTF-8"));mHandler.post(new Runnable() {@Overridepublic void run() {addLeft(text);}});Log.e(MainActivity.TAG, text);} catch (IOException e) {Toast.makeText(this, "消息发送失败:" + e.toString(), Toast.LENGTH_SHORT).show();}} else {Toast.makeText(this, "设备未连接", Toast.LENGTH_SHORT).show();}}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_send:String text = et_text.getText().toString().trim();sendText(text);et_text.setText("");break;}}private class AcceptThread extends Thread {// 服务端接口private BluetoothServerSocket serverSocket;// 获取到客户端的接口private BluetoothSocket socket;// 获取到输入流private InputStream is;public AcceptThread() {serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);}@Overridepublic void run() {try {// 接收其客户端的接口socket = serverSocket.accept();// 获取到输入流is = socket.getInputStream();while (true) {// 创建一个128字节的缓冲byte[] buffer = new byte[128];// 每次读取128字节,并保存其读取的角标int count = is.read(buffer);// 创建Message类,向handler发送数据Message msg = new Message();// 发送一个String的数据,让他向上转型为obj类型msg.obj = new String(buffer, 0, count, "utf-8");// 发送数据mHandler.sendMessage(msg);}} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}}private void addLeft(String text) {ChatListModel model = new ChatListModel();model.setType(ChatListAdapter.LEFT_TEXT);model.setLeftText(text);mList.add(model);mChatListAdapter.notifyDataSetChanged();}private void addRight(String text) {ChatListModel model = new ChatListModel();model.setType(ChatListAdapter.RIGHT_TEXT);model.setRightText(text);mList.add(model);mChatListAdapter.notifyDataSetChanged();}
}

这个只是一个简单的实现Demo,有兴趣的自己去钻研一下

点击下载

有兴趣的加入群:555974449

Android物联网(一)—— 蓝牙通讯相关推荐

  1. Android BLE(1)---蓝牙通讯学习

    Android BLE蓝牙通讯学习 在app应用的开发过程中,一般和蓝牙接触的不多,但是随着智能穿戴设备的发展,穿戴设备和手机关联的app越来越多,之前也是没怎么接触过这一块的东西,正好最近需要做一个 ...

  2. 两个Android端基于蓝牙通讯的demo

    这几天很不顺利,经过一段时间的疯狂加班之后工作终于辞了,淡定下来回顾下最近所开发的软件,当做整合整合知识.闲话不多说进入正题. 随着硬件成本的不断降低,目前越来越多的终端外设也运行了Android系统 ...

  3. android 蓝牙通讯编程 备忘

    1.启动App后: 判断->蓝牙是否打开(所有功能必须在打牙打开的情况下才能用) 已打开: 启动代码中的蓝牙通讯Service 未打开: 发布 打开蓝牙意图(系统),根据Activity返回进场 ...

  4. 蓝牙聊天App设计1:Android Studio制作蓝牙聊天通讯软件(UI界面设计)

    前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是一.UI界面设计 课程1:Android Studio小白安装教程,以及第一个Andr ...

  5. 蓝牙聊天App设计3:Android Studio制作蓝牙聊天通讯软件(完结,蓝牙连接聊天,结合生活情景进行蓝牙通信的通俗讲解,以及代码功能实现,内容详细,讲解通俗易懂)

    前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是:三.蓝牙连接聊天. 课程1:Android Studio小白安装教程,以及第一个An ...

  6. Android BLE低功耗蓝牙开发(下) BLE客户端(中央设备)与GATT服务的通讯

    之前的文章简单实现了使用传统蓝牙进行通讯的DEMO,说是最简单其实只是夸张的写法~毕竟标题党横行,我们也得学学点~至少没有UC震惊部那么夸张. 然后,本来是要写Android开发之BlueTooth- ...

  7. Android 蓝牙及蓝牙通讯讲解

    一.蓝牙介绍: (一).Bluetooth的由来及现状 蓝牙一词源于公元十世纪丹麦国王HaraldBlatand名字中的Blatand.Blatand的英文之意就是Blue tooth.这是因为这位让 ...

  8. android蓝牙通讯方法,Android蓝牙通信开发教程(详解版)

    Android 系统提供蓝牙 API 包 android.bluetooth,允许手机设备通过蓝牙与其他设备进行无线连接. Android 的蓝牙 API 可提供以下功能: 需要说明的是,Androi ...

  9. flutter怎么添加ios网络权限_使用Flutter控制蓝牙通讯

    背景知识视频教程 Dart和Flutter:完整的开发人员指南 - 国外课栈​viadean.com Flutter使用Firestore构建复杂的Android和ios应用 - 国外课栈​viade ...

  10. Android BLE(2)---蓝牙学习

    Android 普通蓝牙学习 需要的权限 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" ...

最新文章

  1. Navicat连接mysql数据库
  2. Winforn中实现ZedGraph自定义添加右键菜单项(附源码下载)
  3. require.context
  4. pymol怎么做底物口袋表面_如何系统的去做有机合成工艺优化---之实战策略
  5. VGGNet原理和实现
  6. ORB_SLAM : semi dense code
  7. 为什么被喷的总是产品经理?
  8. It seems that scikit-learn has not been built correctly.
  9. Android之Retrofit详解(转载)
  10. 微博云原生运维如何快速应对热点流量峰值?
  11. python数据建模优缺点_Python数据分析\建模入门建议
  12. 史上最全最简洁的网络传输协议介绍
  13. RGB565 转 HSV C语言实现
  14. PHP 二元线性拟合函数
  15. python 中英文对齐_解决Python 中英文混输格式对齐的问题
  16. 配置cts performance最优范围
  17. 做多应用层,做多WEB3华人创业者
  18. python控制机器人走8字_爱,死亡和机器人 第十四集 齐马蓝 中文字幕(Python处理utf8文件获取想要的内容)...
  19. 下载cab,sis,sisx等软件包出现乱码的解决方法
  20. 虚拟现实技术会带来网吧的新春天吗?

热门文章

  1. 《Java高级程序设计》清华大学出版社 徐传远 课后习题答案
  2. PHP+SQlite 制作简单的留言板
  3. 第一行代码中过时的通知写法更正;
  4. 阿里云虚拟主机和服务器的区别
  5. Fomo玩法加持的PixelMaster为什么火了?
  6. Base64转MultipartFile
  7. 解决VsCode感叹号快捷键生成html骨架失效
  8. 利用QQ游戏破解QQ密码
  9. win7 64位纯净版系统下载
  10. 多层高速PCB设计不得不知道的那些事。1:多层板的设计原则