Android物联网(一)—— 蓝牙通讯
蓝牙的基础知识我就不讲了,有兴趣可以看下我之前写的博客,现在我们要做的就是实现两个蓝牙之间的通讯,并且实现聊天功能,这里大家准备两个手机即可。
我们先按照流程走一遍,首先是验证一下设备是否支持蓝牙,一般都是支持的
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物联网(一)—— 蓝牙通讯相关推荐
- Android BLE(1)---蓝牙通讯学习
Android BLE蓝牙通讯学习 在app应用的开发过程中,一般和蓝牙接触的不多,但是随着智能穿戴设备的发展,穿戴设备和手机关联的app越来越多,之前也是没怎么接触过这一块的东西,正好最近需要做一个 ...
- 两个Android端基于蓝牙通讯的demo
这几天很不顺利,经过一段时间的疯狂加班之后工作终于辞了,淡定下来回顾下最近所开发的软件,当做整合整合知识.闲话不多说进入正题. 随着硬件成本的不断降低,目前越来越多的终端外设也运行了Android系统 ...
- android 蓝牙通讯编程 备忘
1.启动App后: 判断->蓝牙是否打开(所有功能必须在打牙打开的情况下才能用) 已打开: 启动代码中的蓝牙通讯Service 未打开: 发布 打开蓝牙意图(系统),根据Activity返回进场 ...
- 蓝牙聊天App设计1:Android Studio制作蓝牙聊天通讯软件(UI界面设计)
前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是一.UI界面设计 课程1:Android Studio小白安装教程,以及第一个Andr ...
- 蓝牙聊天App设计3:Android Studio制作蓝牙聊天通讯软件(完结,蓝牙连接聊天,结合生活情景进行蓝牙通信的通俗讲解,以及代码功能实现,内容详细,讲解通俗易懂)
前言:蓝牙聊天App设计全部有三篇文章(一.UI界面设计,二.蓝牙搜索配对连接实现,三.蓝牙连接聊天),这篇文章是:三.蓝牙连接聊天. 课程1:Android Studio小白安装教程,以及第一个An ...
- Android BLE低功耗蓝牙开发(下) BLE客户端(中央设备)与GATT服务的通讯
之前的文章简单实现了使用传统蓝牙进行通讯的DEMO,说是最简单其实只是夸张的写法~毕竟标题党横行,我们也得学学点~至少没有UC震惊部那么夸张. 然后,本来是要写Android开发之BlueTooth- ...
- Android 蓝牙及蓝牙通讯讲解
一.蓝牙介绍: (一).Bluetooth的由来及现状 蓝牙一词源于公元十世纪丹麦国王HaraldBlatand名字中的Blatand.Blatand的英文之意就是Blue tooth.这是因为这位让 ...
- android蓝牙通讯方法,Android蓝牙通信开发教程(详解版)
Android 系统提供蓝牙 API 包 android.bluetooth,允许手机设备通过蓝牙与其他设备进行无线连接. Android 的蓝牙 API 可提供以下功能: 需要说明的是,Androi ...
- flutter怎么添加ios网络权限_使用Flutter控制蓝牙通讯
背景知识视频教程 Dart和Flutter:完整的开发人员指南 - 国外课栈viadean.com Flutter使用Firestore构建复杂的Android和ios应用 - 国外课栈viade ...
- Android BLE(2)---蓝牙学习
Android 普通蓝牙学习 需要的权限 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" ...
最新文章
- Navicat连接mysql数据库
- Winforn中实现ZedGraph自定义添加右键菜单项(附源码下载)
- require.context
- pymol怎么做底物口袋表面_如何系统的去做有机合成工艺优化---之实战策略
- VGGNet原理和实现
- ORB_SLAM : semi dense code
- 为什么被喷的总是产品经理?
- It seems that scikit-learn has not been built correctly.
- Android之Retrofit详解(转载)
- 微博云原生运维如何快速应对热点流量峰值?
- python数据建模优缺点_Python数据分析\建模入门建议
- 史上最全最简洁的网络传输协议介绍
- RGB565 转 HSV C语言实现
- PHP 二元线性拟合函数
- python 中英文对齐_解决Python 中英文混输格式对齐的问题
- 配置cts performance最优范围
- 做多应用层,做多WEB3华人创业者
- python控制机器人走8字_爱,死亡和机器人 第十四集 齐马蓝 中文字幕(Python处理utf8文件获取想要的内容)...
- 下载cab,sis,sisx等软件包出现乱码的解决方法
- 虚拟现实技术会带来网吧的新春天吗?