Android蓝牙开发—经典蓝牙详细开发流程

发布时间:2018-07-16 13:41,

浏览次数:637

, 标签:

Android

Android蓝牙开发前,首先要区分是经典蓝牙开发还是BLE(低功耗)蓝牙开发,它们的开发是有区别的,如果还分不清经典蓝牙和BLE(低功耗)蓝牙的小伙伴,可以先看

Android蓝牙开发—经典蓝牙和BLE(低功耗)蓝牙的区别

本文是针对经典蓝牙开发的,如果是BLE(低功耗)蓝牙开发,可以看Android蓝牙开发—BLE(低功耗)蓝牙详细开发流程

开发流程

* 开启蓝牙

* 扫描蓝牙

* 配对蓝牙

* 连接蓝牙

* 通信

开启蓝牙

1.获取BluetoothAdapter对象

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

2.判断设备是否支持蓝牙

/** * 设备是否支持蓝牙 true为支持 * @return */ public boolean isSupportBlue(){ return

mBluetoothAdapter != null; }

3.判断蓝牙是否开启

/** * 蓝牙是否打开 true为打开 * @return */ public boolean isBlueEnable(){ return

isSupportBlue() && mBluetoothAdapter.isEnabled(); }

4.开启蓝牙

* 异步自动开启蓝牙 /** * 自动打开蓝牙(异步:蓝牙不会立刻就处于开启状态) * 这个方法打开蓝牙不会弹出提示 */ public void

openBlueAsyn(){ if (isSupportBlue()) { mBluetoothAdapter.enable(); } }

* 同步提示开启蓝牙 /** * 自动打开蓝牙(同步) * 这个方法打开蓝牙会弹出提示 * 需要在onActivityResult

方法中判断resultCode == RESULT_OK true为成功 */ public void openBlueSync(Activity

activity, int requestCode){ Intent intent = new

Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

activity.startActivityForResult(intent, requestCode); }

5.权限处理

* 处理6.0以下版本的权限

在AndroidManifest里面添加权限

/>

android:name="android.permission.BLUETOOTH_ADMIN" />

* 处理6.0以上版本的权限

(1)在AndroidManifest里面添加权限

/>

android:name="android.permission.BLUETOOTH_ADMIN" />

android:name="android.permission.ACCESS_FINE_LOCATION" />

(2)动态检查权限

/** * 检查权限 */ private void checkPermissions() { String[] permissions =

{Manifest.permission.ACCESS_FINE_LOCATION}; List permissionDeniedList =

new ArrayList<>(); for (String permission : permissions) { int permissionCheck

= ContextCompat.checkSelfPermission(this, permission); if (permissionCheck ==

PackageManager.PERMISSION_GRANTED) { onPermissionGranted(permission); } else {

permissionDeniedList.add(permission); } } if (!permissionDeniedList.isEmpty())

{ String[] deniedPermissions = permissionDeniedList.toArray(new

String[permissionDeniedList.size()]); ActivityCompat.requestPermissions(this,

deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION); } } /** * 权限回调 * @param

requestCode * @param permissions * @param grantResults */ @Override public

final void onRequestPermissionsResult(int requestCode, @NonNull String[]

permissions, @NonNull int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

switch (requestCode) { case REQUEST_CODE_PERMISSION_LOCATION: if

(grantResults.length > 0) { for (int i = 0; i < grantResults.length; i++) { if

(grantResults[i] == PackageManager.PERMISSION_GRANTED) {

onPermissionGranted(permissions[i]); } } } break; } }

(3)开启GPS

/** * 开启GPS * @param permission */ private void onPermissionGranted(String

permission) { switch (permission) { case

Manifest.permission.ACCESS_FINE_LOCATION: if (Build.VERSION.SDK_INT >=

Build.VERSION_CODES.M && !checkGPSIsOpen()) { new AlertDialog.Builder(this)

.setTitle("提示") .setMessage("当前手机扫描蓝牙需要打开定位功能。") .setNegativeButton("取消", new

DialogInterface.OnClickListener() { @Override public void

onClick(DialogInterface dialog, int which) { finish(); } })

.setPositiveButton("前往设置", new DialogInterface.OnClickListener() { @Override

public void onClick(DialogInterface dialog, int which) { Intent intent = new

Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);

startActivityForResult(intent, REQUEST_CODE_OPEN_GPS); } })

.setCancelable(false) .show(); } else { //GPS已经开启了 } break; } }

(4)检查GPS是否开启

/** * 检查GPS是否打开 * @return */ private boolean checkGPSIsOpen() {

LocationManager locationManager = (LocationManager)

this.getSystemService(Context.LOCATION_SERVICE); if (locationManager == null)

return false; return

locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);

}

扫描蓝牙

1.扫描周围蓝牙设备(配对上的设备有可能扫描不出来)

/** * 扫描的方法 返回true 扫描成功 * 通过接收广播获取扫描到的设备 * @return */ public boolean

scanBlue(){ if (!isBlueEnable()){ Log.e(TAG, "Bluetooth not enable!"); return

false; } //当前是否在扫描,如果是就取消当前的扫描,重新扫描 if (mBluetoothAdapter.isDiscovering()){

mBluetoothAdapter.cancelDiscovery(); } //此方法是个异步操作,一般搜索12秒 return

mBluetoothAdapter.startDiscovery(); }

2.取消扫描蓝牙

/** * 取消扫描蓝牙 * @return true 为取消成功 */ public boolean cancelScanBule(){ if

(isSupportBlue()){ return mBluetoothAdapter.cancelDiscovery(); } return true; }

3.通过广播的方式接收扫描结果

(1)注册广播

IntentFilter filter1 = new

IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);

IntentFilter filter2 = new

IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_FOUND);

registerReceiver(scanBlueReceiver,filter1);

registerReceiver(scanBlueReceiver,filter2);

registerReceiver(scanBlueReceiver,filter3);

(2)接收广播

/** *扫描广播接收类 * Created by zqf on 2018/7/6. */ public class ScanBlueReceiver

extends BroadcastReceiver { private static final String TAG =

ScanBlueReceiver.class.getName(); private ScanBlueCallBack callBack; public

ScanBlueReceiver(ScanBlueCallBack callBack){ this.callBack = callBack; }

//广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行 @Override public void

onReceive(Context context, Intent intent) { String action = intent.getAction();

Log.d(TAG, "action:" + action); BluetoothDevice device =

intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (action){ case

BluetoothAdapter.ACTION_DISCOVERY_STARTED: Log.d(TAG, "开始扫描...");

callBack.onScanStarted(); break; case

BluetoothAdapter.ACTION_DISCOVERY_FINISHED: Log.d(TAG, "结束扫描...");

callBack.onScanFinished(); break; case BluetoothDevice.ACTION_FOUND: Log.d(TAG,

"发现设备..."); callBack.onScanning(device); break; } } }

配对蓝牙

1.开始配对

/** * 配对(配对成功与失败通过广播返回) * @param device */ public void pin(BluetoothDevice

device){ if (device == null){ Log.e(TAG, "bond device null"); return; } if

(!isBlueEnable()){ Log.e(TAG, "Bluetooth not enable!"); return; } //配对之前把扫描关闭

if (mBluetoothAdapter.isDiscovering()){ mBluetoothAdapter.cancelDiscovery(); }

//判断设备是否配对,没有配对在配,配对了就不需要配了 if (device.getBondState() ==

BluetoothDevice.BOND_NONE) { Log.d(TAG, "attemp to bond:" + device.getName());

try { Method createBondMethod = device.getClass().getMethod("createBond");

Boolean returnValue = (Boolean) createBondMethod.invoke(device);

returnValue.booleanValue(); } catch (Exception e) { // TODO Auto-generated

catch block e.printStackTrace(); Log.e(TAG, "attemp to bond fail!"); } } }

2.取消配对

/** * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败) * @param device */ public void

cancelPinBule(BluetoothDevice device){ if (device == null){ Log.d(TAG, "cancel

bond device null"); return; } if (!isBlueEnable()){ Log.e(TAG, "Bluetooth not

enable!"); return; } //判断设备是否配对,没有配对就不用取消了 if (device.getBondState() !=

BluetoothDevice.BOND_NONE) { Log.d(TAG, "attemp to cancel bond:" +

device.getName()); try { Method removeBondMethod =

device.getClass().getMethod("removeBond"); Boolean returnValue = (Boolean)

removeBondMethod.invoke(device); returnValue.booleanValue(); } catch (Exception

e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e(TAG, "attemp

to cancel bond fail!"); } } }

3.通过广播的方式接收配对结果

(1)注册广播

IntentFilter filter4 = new

IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST); IntentFilter filter5 =

new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);

registerReceiver(pinBlueReceiver,filter4);

registerReceiver(pinBlueReceiver,filter5);

(2)接收广播

/**配对广播接收类 * Created by zqf on 2018/7/7. */ public class PinBlueReceiver

extends BroadcastReceiver { private String pin = "0000";

//此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000 private static final String TAG =

PinBlueReceiver.class.getName(); private PinBlueCallBack callBack; public

PinBlueReceiver(PinBlueCallBack callBack){ this.callBack = callBack; }

//广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行 @Override public void

onReceive(Context context, Intent intent) { String action = intent.getAction();

Log.d(TAG, "action:" + action); BluetoothDevice device =

intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if

(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){ try {

callBack.onBondRequest(); //1.确认配对 //

ClsUtils.setPairingConfirmation(device.getClass(), device, true); Method

setPairingConfirmation =

device.getClass().getDeclaredMethod("setPairingConfirmation",boolean.class);

setPairingConfirmation.invoke(device,true); //2.终止有序广播 Log.d("order...",

"isOrderedBroadcast:"+isOrderedBroadcast()+",isInitialStickyBroadcast:"+isInitialStickyBroadcast());

abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。 //3.调用setPin方法进行配对... // boolean

ret = ClsUtils.setPin(device.getClass(), device, pin); Method removeBondMethod

= device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});

Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new

Object[]{pin.getBytes()}); } catch (Exception e) { // TODO Auto-generated catch

block e.printStackTrace(); } }else if

(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){ switch

(device.getBondState()) { case BluetoothDevice.BOND_NONE: Log.d(TAG, "取消配对");

callBack.onBondFail(device); break; case BluetoothDevice.BOND_BONDING:

Log.d(TAG, "配对中"); callBack.onBonding(device); break; case

BluetoothDevice.BOND_BONDED: Log.d(TAG, "配对成功");

callBack.onBondSuccess(device); break; } } } }

连接蓝牙

经典蓝牙连接相当于socket连接,是个非常耗时的操作,所以应该放到子线程中去完成。

1.连接线程

/**连接线程 * Created by zqf on 2018/7/7. */ public class ConnectBlueTask extends

AsyncTask { private static final

String TAG = ConnectBlueTask.class.getName(); private BluetoothDevice

bluetoothDevice; private ConnectBlueCallBack callBack; public

ConnectBlueTask(ConnectBlueCallBack callBack){ this.callBack = callBack; }

@Override protected BluetoothSocket doInBackground(BluetoothDevice...

bluetoothDevices) { bluetoothDevice = bluetoothDevices[0]; BluetoothSocket

socket = null; try{ Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);

socket =

bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(ClassicsBluetooth.UUID));

if (socket != null && !socket.isConnected()){ socket.connect(); } }catch

(IOException e){ Log.e(TAG,"socket连接失败"); try { socket.close(); } catch

(IOException e1) { e1.printStackTrace(); Log.e(TAG,"socket关闭失败"); } } return

socket; } @Override protected void onPreExecute() { Log.d(TAG,"开始连接"); if

(callBack != null) callBack.onStartConnect(); } @Override protected void

onPostExecute(BluetoothSocket bluetoothSocket) { if (bluetoothSocket != null &&

bluetoothSocket.isConnected()){ Log.d(TAG,"连接成功"); if (callBack != null)

callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket); }else {

Log.d(TAG,"连接失败"); if (callBack != null)

callBack.onConnectFail(bluetoothDevice, "连接失败"); } } }

2.启动连接线程

/** * 连接 (在配对之后调用) * @param device */ public void connect(BluetoothDevice

device, ConnectBlueCallBack callBack){ if (device == null){ Log.d(TAG, "bond

device null"); return; } if (!isBlueEnable()){ Log.e(TAG, "Bluetooth not

enable!"); return; } //连接之前把扫描关闭 if (mBluetoothAdapter.isDiscovering()){

mBluetoothAdapter.cancelDiscovery(); } new

ConnectBlueTask(callBack).execute(device); }

3.判断是否连接成功

/** * 蓝牙是否连接 * @return */ public boolean isConnectBlue(){ return

mBluetoothSocket != null && mBluetoothSocket.isConnected(); }

4.断开连接

/** * 断开连接 * @return */ public boolean cancelConnect(){ if (mBluetoothSocket

!= null && mBluetoothSocket.isConnected()){ try { mBluetoothSocket.close(); }

catch (IOException e) { e.printStackTrace(); return false; } } mBluetoothSocket

= null; return true; }

5.MAC地址连接

/** * 输入mac地址进行自动配对 * 前提是系统保存了该地址的对象 * @param address * @param callBack */

public void connectMAC(String address, ConnectBlueCallBack callBack) { if

(!isBlueEnable()){ return ; } BluetoothDevice btDev =

mBluetoothAdapter.getRemoteDevice(address); connect(btDev, callBack); }

通信

1.读取数据线程

/**读取线程 * Created by zqf on 2018/7/7. */ public class ReadTask extends

AsyncTask { private static final String TAG =

ReadTask.class.getName(); private ReadCallBack callBack; private

BluetoothSocket socket; public ReadTask(ReadCallBack callBack, BluetoothSocket

socket){ this.callBack = callBack; this.socket = socket; } @Override protected

String doInBackground(String... strings) { BufferedInputStream in = null; try {

StringBuffer sb = new StringBuffer(); in = new

BufferedInputStream(socket.getInputStream()); int length = 0; byte[] buf = new

byte[1024]; while ((length = in.read()) != -1) { sb.append(new

String(buf,0,length)); } return sb.toString(); } catch (IOException e) {

e.printStackTrace(); }finally { try { in.close(); } catch (IOException e) {

e.printStackTrace(); } } return "读取失败"; } @Override protected void

onPreExecute() { Log.d(TAG,"开始读取数据"); if (callBack != null)

callBack.onStarted(); } @Override protected void onPostExecute(String s) {

Log.d(TAG,"完成读取数据"); if (callBack != null){ if ("读取失败".equals(s)){

callBack.onFinished(false, s); }else { callBack.onFinished(true, s); } } } }

2.写入数据线程

/**写入线程 * Created by zqf on 2018/7/7. */ public class WriteTask extends

AsyncTask{ private static final String TAG =

WriteTask.class.getName(); private WriteCallBack callBack; private

BluetoothSocket socket; public WriteTask(WriteCallBack callBack,

BluetoothSocket socket){ this.callBack = callBack; this.socket = socket; }

@Override protected String doInBackground(String... strings) { String string =

strings[0]; OutputStream outputStream = null; try{ outputStream =

socket.getOutputStream(); outputStream.write(string.getBytes()); } catch

(IOException e) { Log.e("error", "ON RESUME: Exception during write.", e);

return "发送失败"; }finally { try { outputStream.close(); } catch (IOException e) {

e.printStackTrace(); } } return "发送成功"; } @Override protected void

onPreExecute() { if (callBack != null) callBack.onStarted(); } @Override

protected void onPostExecute(String s) { if (callBack != null){ if

("发送成功".equals(s)){ callBack.onFinished(true, s); }else {

callBack.onFinished(false, s); } } } }

以上就是经典蓝牙的开发流程和部分代码,后期会提供demo下载。若有不当之处,请留言讨论,一起学习进步。

android pin码 经典蓝牙_Android蓝牙开发—经典蓝牙详细开发流程相关推荐

  1. 码云上传代码添加标签_[Android] 发布码云(Gitee)项目到JitPack(最全完整流程)

    最近把github上的代码都转移到了码云上,而且github上的仓库可以很方便的迁移到码云,所以老代码的迁移问题不用考虑. 之前使用 JCenter 发布了一个 GitHub 开源项目,JCenter ...

  2. android pin码 经典蓝牙_Android 蓝牙 pin 自动配 setPin()方法有时候无效

    2018-08-09 Android  蓝牙pin自动配对ClsUtils类中的 static public boolean setPin(Class btClass, BluetoothDevice ...

  3. 3加密狗计算pin码_6 个芯片打造复古经典计算机:215 色显示,能编程能玩小游戏...

    机器之心报道 机器之心编辑部 在很多人看来,打造一台家用的计算机需要太多硬件:主板.CPU 等等.但实现一个 8 位的计算机远没有这么复杂.近日,一位名为 Matt Sarnoff 的开发者就仅用了 ...

  4. 安卓航班Android开发经典教程大总结2----游戏基础入门及高级编程

    前总结的是Android基础编程及深入,基本都是一些控件的使用,本次将全面对Android中游戏开发进行总结,马上就春节了,在这里代表安卓航班给大家拜年,祝大家阖家欢乐,工作顺利,早日发大财!下面就开 ...

  5. android开发环境建立以及开发工具的使用--怎样使用eclipse来开发android源码

    /** 版本:1.0 日期:2009-04-01 作者:HKjinzhao 备注: 转自:http://blog.csdn.net/hkjinzhao/article/details/4043997 ...

  6. 蓝牙安全入门详解 超详细

    1.基本概念 蓝牙是个啥: 蓝牙是一个无线通信协议,让传输数据从有线到无线,让通信更加便捷. 其他无线协议:Wifi ZigBee. 视频演示:https://space.bilibili.com/4 ...

  7. 车载蓝牙PIN码是什么

    目前大多数汽车都安装了车载蓝牙,但是在初期连接使者需要车主提供 PIN 码,那么车载蓝牙 PIN 码是什么?如果车载蓝牙 PIN 码忘记了怎么办呢?PIN 码分类?手机蓝牙和车载蓝牙连接的方法是什么? ...

  8. Android源码的Binder权限是如何控制,附超全教程文档

    从初中级到高级,移动端程序员的进阶宝典 想要成为一名优秀的Android开发,你需要一份完备的 知识体系,在这里,让我们一起成长为自己所想的那样. 下面我们就以 Android 开发为例,从硬技能和软 ...

  9. 蓝牙配对模式 java_【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码...

    目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备  &  直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...

最新文章

  1. MySQL主从复制的常用拓扑结构
  2. Xcode6中添加pch文件
  3. LUA 利用#遍历表的问题
  4. java 导入world数据_java读取world文件,把world文件中的内容,原样输出到页面上。...
  5. PHP 利用cron 实现文章同步至新浪、网易等微博
  6. Python常用第三方库大盘点
  7. 计算机二级python什么水平_计算机二级python好过吗 通过率是多少
  8. 项目管理系统、工作台、经营看板、质量管理、合同管理、合同审核、新建合同、分包商管理、立项审批、创建项目、项目模板、项目统计、计划管理、结项申请、审批流程、审批记录、审批状态、参数设置、axure原型
  9. 数据库原理—SQL数据定义功能(九)
  10. 2021年中国电力线通信(PLC)市场趋势报告、技术动态创新及2027年市场预测
  11. python表白代码-如何用Python代码向心爱的姑娘花式表白?
  12. “叔叔,你来监考了!”
  13. 1159 最大全0子矩阵
  14. c8815 android os,华为C8815官方原厂固件rom系统刷机包_最新升级包降级包下载
  15. MySQL索引原理总结
  16. linux vi文件加密和文件解密
  17. css文字多余显示,css设置文字多余部分显示省略号
  18. 使用tftpd32烧写内核(拯救你的“砖”)
  19. Vue Typescript @Prop
  20. JavaFX之Scene Builder的使用(开发一款GUI小工具原来这么简单)

热门文章

  1. React之let语句
  2. python爬取大众点评数据_利用Node.js制作爬取大众点评的爬虫
  3. 服务及进程介绍及使用
  4. 做视频素材资源(free视频,音频,图片)
  5. RDA TDT TOT
  6. 查看Windows 的正盗版的区别
  7. Android--内存泄露分析
  8. C++控制台字符输入方法
  9. ansys 19.0 ansys multiphsics utility 在哪
  10. matlab contourf(data_100);,contourf以及griddata生成网格问题