当前位置: 首页 > news >正文

基于低功耗蓝牙的手机APP(文末有整个工程的下载连接哦!)

文章目录

  • 前言
  • 一、低功耗蓝牙BLE是什么?
  • 二、基于低功耗蓝牙的手机APP
    • 1.工程源码
    • 2.蓝牙接收数据函数
    • 3.数据处理函数(可自定义) 

一、低功耗蓝牙BLE是什么?

低功耗蓝牙是一种全新的技术,是当前可以用来设计和使用的功耗最低的无线技术。

经典蓝牙的设计目的在于统一全球各地的计算和通信设备,让手机与笔记本电脑相互连接。不过事实证明,蓝牙最为广泛的应用还是音频传输,比如将音频从手机传到蓝牙耳机。

低功耗蓝牙选择了完全不同的方向:并非只是增加可达的数据传输速率,而是从尽可能降低功耗方面进行优化。这意味着,也许你无法获得很高的传输速率,但是可以将连接保持数小时或数天的时间。

二、基于低功耗蓝牙的手机APP

1.工程源码

关于低功耗蓝牙的一些操作,包括开启、搜索蓝牙等等

package com.kaka.bluetoothble;import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;import com.blankj.utilcode.util.ToastUtils;
import com.kaka.bluetoothble.adapter.BleAdapter;
import com.tbruyelle.rxpermissions2.RxPermissions;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;public class MainActivity extends AppCompatActivity {private static final String TAG ="ble_tag" ;ProgressBar pbSearchBle;ImageView ivSerBleStatus;TextView tvSerBleStatus;TextView tvSerBindStatus;ListView bleListView;private LinearLayout operaView;private Button btnWrite;private Button btnRead;private EditText etWriteContent;private TextView tvResponse;private TextView tvR;private TextView tvxlv;private TextView tvpa;private TextView tvgps;private List<BluetoothDevice> mDatas;private List<Integer> mRssis;private BleAdapter mAdapter;private BluetoothAdapter mBluetoothAdapter;private BluetoothManager mBluetoothManager;private boolean isScaning=false;private boolean isConnecting=false;private BluetoothGatt mBluetoothGatt;//服务和特征值private UUID write_UUID_service;private UUID write_UUID_chara;private UUID read_UUID_service;private UUID read_UUID_chara;private UUID notify_UUID_service;private UUID notify_UUID_chara;private UUID indicate_UUID_service;private UUID indicate_UUID_chara;private String hex="7B46363941373237323532443741397D";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_search_device);initView();initData();mBluetoothManager= (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);mBluetoothAdapter=mBluetoothManager.getAdapter();if (mBluetoothAdapter==null||!mBluetoothAdapter.isEnabled()){Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent,0);}}private void initData() {mDatas=new ArrayList<>();mRssis=new ArrayList<>();mAdapter=new BleAdapter(MainActivity.this,mDatas,mRssis);bleListView.setAdapter(mAdapter);mAdapter.notifyDataSetChanged();}private void initView(){pbSearchBle=findViewById(R.id.progress_ser_bluetooth);ivSerBleStatus=findViewById(R.id.iv_ser_ble_status);tvSerBindStatus=findViewById(R.id.tv_ser_bind_status);tvSerBleStatus=findViewById(R.id.tv_ser_ble_status);bleListView=findViewById(R.id.ble_list_view);operaView=findViewById(R.id.opera_view);btnWrite=findViewById(R.id.btnWrite);btnRead=findViewById(R.id.btnRead);etWriteContent=findViewById(R.id.et_write);tvResponse=findViewById(R.id.tv_response);tvR=findViewById(R.id.tv_R);tvxlv=findViewById(R.id.tv_XLV);tvpa=findViewById(R.id.tv_Pa);btnRead.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {readData();}});btnWrite.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//执行写入操作writeData();}});ivSerBleStatus.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (isScaning){tvSerBindStatus.setText("停止搜索");stopScanDevice();}else{checkPermissions();}}});bleListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {if (isScaning){stopScanDevice();}if (!isConnecting){isConnecting=true;BluetoothDevice bluetoothDevice= mDatas.get(position);//连接设备tvSerBindStatus.setText("连接中");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this,true, gattCallback, TRANSPORT_LE);} else {mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this,true, gattCallback);}}}});}private void readData() {BluetoothGattCharacteristic characteristic=mBluetoothGatt.getService(read_UUID_service).getCharacteristic(read_UUID_chara);mBluetoothGatt.readCharacteristic(characteristic);}/*** 开始扫描 10秒后自动停止* */private void scanDevice(){tvSerBindStatus.setText("正在搜索");isScaning=true;pbSearchBle.setVisibility(View.VISIBLE);mBluetoothAdapter.startLeScan(scanCallback);new Handler().postDelayed(new Runnable() {@Overridepublic void run() {//结束扫描mBluetoothAdapter.stopLeScan(scanCallback);runOnUiThread(new Runnable() {@Overridepublic void run() {isScaning=false;pbSearchBle.setVisibility(View.GONE);tvSerBindStatus.setText("搜索已结束");}});}},10000);}/*** 停止扫描* */private void stopScanDevice(){isScaning=false;pbSearchBle.setVisibility(View.GONE);mBluetoothAdapter.stopLeScan(scanCallback);}BluetoothAdapter.LeScanCallback scanCallback=new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {Log.e(TAG, "run: scanning...");if (!mDatas.contains(device)){mDatas.add(device);mRssis.add(rssi);mAdapter.notifyDataSetChanged();}}};private BluetoothGattCallback gattCallback=new BluetoothGattCallback() {/*** 断开或连接 状态发生变化时调用* */@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);Log.e(TAG,"onConnectionStateChange()");if (status==BluetoothGatt.GATT_SUCCESS){//连接成功if (newState== BluetoothGatt.STATE_CONNECTED){Log.e(TAG,"连接成功");//发现服务gatt.discoverServices();}}else{//连接失败Log.e(TAG,"失败=="+status);mBluetoothGatt.close();isConnecting=false;}}/*** 发现设备(真正建立连接)* */@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {super.onServicesDiscovered(gatt, status);//直到这里才是真正建立了可通信的连接isConnecting=false;Log.e(TAG,"onServicesDiscovered()---建立连接");//获取初始化服务和特征值initServiceAndChara();//订阅通知mBluetoothGatt.setCharacteristicNotification(mBluetoothGatt.getService(notify_UUID_service).getCharacteristic(notify_UUID_chara),true);runOnUiThread(new Runnable() {@Overridepublic void run() {bleListView.setVisibility(View.GONE);operaView.setVisibility(View.VISIBLE);tvSerBindStatus.setText("已连接");}});}/*** 读操作的回调* */@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);Log.e(TAG,"onCharacteristicRead()");}/*** 写操作的回调* */@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);Log.e(TAG,"onCharacteristicWrite()  status="+status+",value="+HexUtil.encodeHexStr(characteristic.getValue()));}/*** 接收到硬件返回的数据* */@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {super.onCharacteristicChanged(gatt, characteristic);Log.e(TAG,"onCharacteristicChanged()"+characteristic.getValue());final byte[] data=characteristic.getValue();runOnUiThread(new Runnable() {@Overridepublic void run() {// byte[] 转 stringString res = new String(data);//       addText(tvResponse,bytes2hex(data));//       addText(tvR,bytes2hex(data));String[] stra=new String[10];stra=getString(res);tvResponse.setText(stra[1].toString()+" ℃");tvR.setText(stra[2].toString()+" RH");tvxlv.setText(stra[3].toString()+" ℃");tvpa.setText(stra[4].toString()+" RH");}});}};/*** 检查权限*/private void checkPermissions() {RxPermissions rxPermissions = new RxPermissions(MainActivity.this);rxPermissions.request(android.Manifest.permission.ACCESS_FINE_LOCATION).subscribe(new io.reactivex.functions.Consumer<Boolean>() {@Overridepublic void accept(Boolean aBoolean) throws Exception {if (aBoolean) {// 用户已经同意该权限scanDevice();} else {// 用户拒绝了该权限,并且选中『不再询问』ToastUtils.showLong("用户开启权限后才能使用");}}});}private void initServiceAndChara(){List<BluetoothGattService> bluetoothGattServices= mBluetoothGatt.getServices();for (BluetoothGattService bluetoothGattService:bluetoothGattServices){List<BluetoothGattCharacteristic> characteristics=bluetoothGattService.getCharacteristics();for (BluetoothGattCharacteristic characteristic:characteristics){int charaProp = characteristic.getProperties();if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {read_UUID_chara=characteristic.getUuid();read_UUID_service=bluetoothGattService.getUuid();Log.e(TAG,"read_chara="+read_UUID_chara+"----read_service="+read_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {write_UUID_chara=characteristic.getUuid();write_UUID_service=bluetoothGattService.getUuid();Log.e(TAG,"write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {write_UUID_chara=characteristic.getUuid();write_UUID_service=bluetoothGattService.getUuid();Log.e(TAG,"write_chara="+write_UUID_chara+"----write_service="+write_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {notify_UUID_chara=characteristic.getUuid();notify_UUID_service=bluetoothGattService.getUuid();Log.e(TAG,"notify_chara="+notify_UUID_chara+"----notify_service="+notify_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {indicate_UUID_chara=characteristic.getUuid();indicate_UUID_service=bluetoothGattService.getUuid();Log.e(TAG,"indicate_chara="+indicate_UUID_chara+"----indicate_service="+indicate_UUID_service);}}}}//将字符串数据进行显示的函数private void addText(TextView textView, String content) {textView.setText(content+"℃");}private void writeData(){BluetoothGattService service=mBluetoothGatt.getService(write_UUID_service);BluetoothGattCharacteristic charaWrite=service.getCharacteristic(write_UUID_chara);byte[] data;String content=etWriteContent.getText().toString();if (!TextUtils.isEmpty(content)){data=HexUtil.hexStringToBytes(content);}else{data=HexUtil.hexStringToBytes(hex);}if (data.length>20){//数据大于个字节 分批次写入Log.e(TAG, "writeData: length="+data.length);int num=0;if (data.length%20!=0){num=data.length/20+1;}else{num=data.length/20;}for (int i=0;i<num;i++){byte[] tempArr;if (i==num-1){tempArr=new byte[data.length-i*20];System.arraycopy(data,i*20,tempArr,0,data.length-i*20);}else{tempArr=new byte[20];System.arraycopy(data,i*20,tempArr,0,20);}charaWrite.setValue(tempArr);mBluetoothGatt.writeCharacteristic(charaWrite);}}else{charaWrite.setValue(data);mBluetoothGatt.writeCharacteristic(charaWrite);}}private static final String HEX = "0123456789abcdef";public static String bytes2hex(byte[] bytes){StringBuilder sb = new StringBuilder(bytes.length * 2);for (byte b : bytes){// 取出这个字节的高4位,然后与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数sb.append(HEX.charAt((b >> 4) & 0x0f));// 取出这个字节的低位,与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数sb.append(HEX.charAt(b & 0x0f));}return sb.toString();}//下面是一种稍复杂的写法,将单片机传输过来的数据进行分解,最后得到一个字符串数组public static String[] getString(String str) {//先定义一个集合来存放分解后的字符List<String> list = new ArrayList<String>();String streee = "";for (int i = 0; i <str.length(); i++) {streee = str.substring(i, i + 1);list.add(streee);}//定义一个存放最终字符串的数组String[] strk=new String[10];//定义一个存放最终字符串的StringBufferStringBuffer stra = new StringBuffer();StringBuffer strb = new StringBuffer();StringBuffer strc = new StringBuffer();StringBuffer strd = new StringBuffer();StringBuffer stre = new StringBuffer();int i=0;for (int j = 0; j < list.size(); j++) {String a = list.get(j).toString();if (a.equals("$")){i++;j++;}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==1){String b= list.get(j).toString();stra.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==2){String b= list.get(j).toString();strb.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==3){String b= list.get(j).toString();strc.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==4){String b= list.get(j).toString();strd.append(b);}else{}}strk[1]=stra.toString();strk[2]=strb.toString();strk[3]=strc.toString();strk[4]=strd.toString();return strk;}@Overrideprotected void onDestroy() {super.onDestroy();mBluetoothGatt.disconnect();}
}

2.蓝牙接收数据函数

data为蓝牙接收到的数据

/*** 接收到硬件返回的数据* */
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {super.onCharacteristicChanged(gatt, characteristic);Log.e(TAG,"onCharacteristicChanged()"+characteristic.getValue());final byte[] data=characteristic.getValue();runOnUiThread(new Runnable() {@Overridepublic void run() {// byte[] 转 stringString res = new String(data);//       addText(tvResponse,bytes2hex(data));//       addText(tvR,bytes2hex(data));String[] stra=new String[10];stra=getString(res);tvResponse.setText(stra[1].toString()+" ℃");tvR.setText(stra[2].toString()+" RH");tvxlv.setText(stra[3].toString()+" ℃");tvpa.setText(stra[4].toString()+" RH");}});}

3.数据处理函数

可以自定义数据处理函数

  //下面是一种稍复杂的写法,将单片机传输过来的数据进行分解,最后得到一个字符串数组public static String[] getString(String str) {//先定义一个集合来存放分解后的字符List<String> list = new ArrayList<String>();String streee = "";for (int i = 0; i <str.length(); i++) {streee = str.substring(i, i + 1);list.add(streee);}//定义一个存放最终字符串的数组String[] strk=new String[10];//定义一个存放最终字符串的StringBufferStringBuffer stra = new StringBuffer();StringBuffer strb = new StringBuffer();StringBuffer strc = new StringBuffer();StringBuffer strd = new StringBuffer();StringBuffer stre = new StringBuffer();int i=0;for (int j = 0; j < list.size(); j++) {String a = list.get(j).toString();if (a.equals("$")){i++;j++;}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==1){String b= list.get(j).toString();stra.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==2){String b= list.get(j).toString();strb.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==3){String b= list.get(j).toString();strc.append(b);}else{}//如果是'$'就把这个字符加在上面定义的StringBufferif (i==4){String b= list.get(j).toString();strd.append(b);}else{}}strk[1]=stra.toString();strk[2]=strb.toString();strk[3]=strc.toString();strk[4]=strd.toString();return strk;}

 

总结

工程下载链接:低功耗蓝牙手机APP工程文件

该低功耗蓝牙APP工程源码以及APK文件可通过我的资源进行下载

(1)该工程为基本模板,可以基于本工程进行进一步开发

(2)根据自己的需求进行定制化开发

(3)来学习低功耗蓝牙


http://www.taodudu.cc/news/show-4752386.html

相关文章:

  • Ubuntu20.4安装pytorch的笔记和遇到的坑
  • Django 静态文件管理与部署指南
  • 机器学习在数据分析中的应用:探索未来趋势
  • Mac电脑安装打开APP显示问题已损坏 问题解决
  • Docker 部署 Nginx 实现一个极简的 负载均衡
  • 2024面试算法题目(go)
  • 实体鉴别GB/T 15843研究(合集)
  • 区块链与数字货币之间的关系
  • .net 部署到服务端IIS,Process调用exe程序无法运行问题解决
  • Java与RabbitMQ(二)启动rabbitmq web管理后台插件
  • docker 镜像使用
  • 配置OpenStack准备环境
  • ElasticSearch - 简介
  • 思维导图软件对比
  • 【韩顺平JAVA】房屋出租系统
  • 日本九州攻略
  • 已知分布函数求概率密度例题_【考研数学】考试重点、难点和常考题型:?随机变量及其分布...
  • 【概率论】作业三
  • 贝叶斯课后习题(零)常用分布
  • 【概率论与数理统计】猴博士 笔记 p29-32 均匀分布、泊松分布、指数分布、几何分布
  • 怎样用matlab产生泊松分布随机数
  • 模拟台球运动
  • 【算法修炼】台球碰撞 C
  • c语言写台球游戏,OpenGL版 3D台球 (原创,Basic实现) 申精!
  • 网站快照被劫持怎么办?
  • 网站快照被篡改劫持怎么办
  • recv_contxt = std::string( (char*)recv_buffer+sizeof(Req),pReq->context_len-86);
  • typedef int(*P)(int )
  • BLE 协议栈之 主机透传
  • 安装LR11 时,安装Microsoft Visual c++2005 sp1运行时组件,就会提示命令行选项语法错误,键入“命令/?”可获取帮肋信息...
  • HTTP 代理原理及实现(一)
  • ST17H66低功耗蓝牙SOC开发(7)—— simpleBleCentral工程讲解(下)
  • 面试集锦-------LRU,LFU手撕算法
  • 若干个进阶SQL 进阶技巧
  • 【小知识】linux hash命令
  • oracle中的flag,MMT 表中的 Cost_Flag=E,如何解决?