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

10 篇文章 0 订阅
转载

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

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

开发流程

  • 开启蓝牙
  • 扫描蓝牙
  • 配对蓝牙
  • 连接蓝牙
  • 通信

开启蓝牙

1.获取BluetoothAdapter对象

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
 

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


 
 
  1. /**
  2. * 设备是否支持蓝牙 true为支持
  3. * @return
  4. */
  5. public boolean isSupportBlue(){
  6. return mBluetoothAdapter != null;
  7. }

3.判断蓝牙是否开启


 
 
  1. /**
  2. * 蓝牙是否打开 true为打开
  3. * @return
  4. */
  5. public boolean isBlueEnable(){
  6. return isSupportBlue() && mBluetoothAdapter.isEnabled();
  7. }

4.开启蓝牙

  • 异步自动开启蓝牙

 
 
  1. /**
  2. * 自动打开蓝牙(异步:蓝牙不会立刻就处于开启状态)
  3. * 这个方法打开蓝牙不会弹出提示
  4. */
  5. public void openBlueAsyn(){
  6. if (isSupportBlue()) {
  7. mBluetoothAdapter.enable();
  8. }
  9. }
  • 同步提示开启蓝牙

 
 
  1. /**
  2. * 自动打开蓝牙(同步)
  3. * 这个方法打开蓝牙会弹出提示
  4. * 需要在onActivityResult 方法中判断resultCode == RESULT_OK true为成功
  5. */
  6. public void openBlueSync(Activity activity, int requestCode){
  7. Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  8. activity.startActivityForResult(intent, requestCode);
  9. }

5.权限处理

  • 处理6.0以下版本的权限

    在AndroidManifest里面添加权限


 
 
  1. <!-- 使用蓝牙的权限 -->
  2. <uses-permission android:name="android.permission.BLUETOOTH" />
  3. <!-- 扫描蓝牙设备或者操作蓝牙设置 -->
  4. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  • 处理6.0以上版本的权限

    (1)在AndroidManifest里面添加权限


 
 
  1. <!-- 使用蓝牙的权限 -->
  2. <uses-permission android:name="android.permission.BLUETOOTH" />
  3. <!-- 扫描蓝牙设备或者操作蓝牙设置 -->
  4. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  5. <!--模糊定位权限,仅作用于6.0+-->
  6. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  7. <!--精准定位权限,仅作用于6.0+-->
  8. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    (2)动态检查权限


 
 
  1. /**
  2. * 检查权限
  3. */
  4. private void checkPermissions() {
  5. String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
  6. List <String> permissionDeniedList = new ArrayList <>();
  7. for (String permission : permissions) {
  8. int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
  9. if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
  10. onPermissionGranted(permission);
  11. } else {
  12. permissionDeniedList.add(permission);
  13. }
  14. }
  15. if (!permissionDeniedList.isEmpty()) {
  16. String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
  17. ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
  18. }
  19. }
  20. /**
  21. * 权限回调
  22. * @param requestCode
  23. * @param permissions
  24. * @param grantResults
  25. */
  26. @Override
  27. public final void onRequestPermissionsResult(int requestCode,
  28. @NonNull String[] permissions,
  29. @NonNull int[] grantResults) {
  30. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  31. switch (requestCode) {
  32. case REQUEST_CODE_PERMISSION_LOCATION:
  33. if (grantResults.length > 0) {
  34. for (int i = 0; i < grantResults.length; i++) {
  35. if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
  36. onPermissionGranted(permissions[i]);
  37. }
  38. }
  39. }
  40. break;
  41. }
  42. }

    (3)开启GPS


 
 
  1. /**
  2. * 开启GPS
  3. * @param permission
  4. */
  5. private void onPermissionGranted(String permission) {
  6. switch (permission) {
  7. case Manifest.permission.ACCESS_FINE_LOCATION:
  8. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkGPSIsOpen()) {
  9. new AlertDialog.Builder(this)
  10. .setTitle("提示")
  11. .setMessage("当前手机扫描蓝牙需要打开定位功能。")
  12. .setNegativeButton("取消",
  13. new DialogInterface.OnClickListener() {
  14. @Override
  15. public void onClick(DialogInterface dialog, int which) {
  16. finish();
  17. }
  18. })
  19. .setPositiveButton("前往设置",
  20. new DialogInterface.OnClickListener() {
  21. @Override
  22. public void onClick(DialogInterface dialog, int which) {
  23. Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
  24. startActivityForResult(intent, REQUEST_CODE_OPEN_GPS);
  25. }
  26. })
  27. .setCancelable(false)
  28. .show();
  29. } else {
  30. //GPS已经开启了
  31. }
  32. break;
  33. }
  34. }

    (4)检查GPS是否开启


 
 
  1. /**
  2. * 检查GPS是否打开
  3. * @return
  4. */
  5. private boolean checkGPSIsOpen() {
  6. LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  7. if (locationManager == null)
  8. return false;
  9. return locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
  10. }

扫描蓝牙

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


 
 
  1. /**
  2. * 扫描的方法 返回true 扫描成功
  3. * 通过接收广播获取扫描到的设备
  4. * @return
  5. */
  6. public boolean scanBlue(){
  7. if (!isBlueEnable()){
  8. Log.e(TAG, "Bluetooth not enable!");
  9. return false;
  10. }
  11. //当前是否在扫描,如果是就取消当前的扫描,重新扫描
  12. if (mBluetoothAdapter.isDiscovering()){
  13. mBluetoothAdapter.cancelDiscovery();
  14. }
  15. //此方法是个异步操作,一般搜索12秒
  16. return mBluetoothAdapter.startDiscovery();
  17. }

2.取消扫描蓝牙


 
 
  1. /**
  2. * 取消扫描蓝牙
  3. * @return true 为取消成功
  4. */
  5. public boolean cancelScanBule(){
  6. if (isSupportBlue()){
  7. return mBluetoothAdapter.cancelDiscovery();
  8. }
  9. return true;
  10. }

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

    (1)注册广播


 
 
  1. IntentFilter filter1 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
  2. IntentFilter filter2 = new IntentFilter(android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  3. IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_FOUND);
  4. registerReceiver(scanBlueReceiver,filter1);
  5. registerReceiver(scanBlueReceiver,filter2);
  6. registerReceiver(scanBlueReceiver,filter3);

    (2)接收广播


 
 
  1. /**
  2. *扫描广播接收类
  3. * Created by zqf on 2018/7/6.
  4. */
  5. public class ScanBlueReceiver extends BroadcastReceiver {
  6. private static final String TAG = ScanBlueReceiver.class.getName();
  7. private ScanBlueCallBack callBack;
  8. public ScanBlueReceiver(ScanBlueCallBack callBack){
  9. this.callBack = callBack;
  10. }
  11. //广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行
  12. @Override
  13. public void onReceive(Context context, Intent intent) {
  14. String action = intent.getAction();
  15. Log.d(TAG, "action:" + action);
  16. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  17. switch (action){
  18. case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
  19. Log.d(TAG, "开始扫描...");
  20. callBack.onScanStarted();
  21. break;
  22. case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
  23. Log.d(TAG, "结束扫描...");
  24. callBack.onScanFinished();
  25. break;
  26. case BluetoothDevice.ACTION_FOUND:
  27. Log.d(TAG, "发现设备...");
  28. callBack.onScanning(device);
  29. break;
  30. }
  31. }
  32. }

配对蓝牙

1.开始配对


 
 
  1. /**
  2. * 配对(配对成功与失败通过广播返回)
  3. * @param device
  4. */
  5. public void pin(BluetoothDevice device){
  6. if (device == null){
  7. Log.e(TAG, "bond device null");
  8. return;
  9. }
  10. if (!isBlueEnable()){
  11. Log.e(TAG, "Bluetooth not enable!");
  12. return;
  13. }
  14. //配对之前把扫描关闭
  15. if (mBluetoothAdapter.isDiscovering()){
  16. mBluetoothAdapter.cancelDiscovery();
  17. }
  18. //判断设备是否配对,没有配对在配,配对了就不需要配了
  19. if (device.getBondState() == BluetoothDevice.BOND_NONE) {
  20. Log.d(TAG, "attemp to bond:" + device.getName());
  21. try {
  22. Method createBondMethod = device.getClass().getMethod("createBond");
  23. Boolean returnValue = (Boolean) createBondMethod.invoke(device);
  24. returnValue.booleanValue();
  25. } catch (Exception e) {
  26. // TODO Auto-generated catch block
  27. e.printStackTrace();
  28. Log.e(TAG, "attemp to bond fail!");
  29. }
  30. }
  31. }

2.取消配对


 
 
  1. /**
  2. * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
  3. * @param device
  4. */
  5. public void cancelPinBule(BluetoothDevice device){
  6. if (device == null){
  7. Log.d(TAG, "cancel bond device null");
  8. return;
  9. }
  10. if (!isBlueEnable()){
  11. Log.e(TAG, "Bluetooth not enable!");
  12. return;
  13. }
  14. //判断设备是否配对,没有配对就不用取消了
  15. if (device.getBondState() != BluetoothDevice.BOND_NONE) {
  16. Log.d(TAG, "attemp to cancel bond:" + device.getName());
  17. try {
  18. Method removeBondMethod = device.getClass().getMethod("removeBond");
  19. Boolean returnValue = (Boolean) removeBondMethod.invoke(device);
  20. returnValue.booleanValue();
  21. } catch (Exception e) {
  22. // TODO Auto-generated catch block
  23. e.printStackTrace();
  24. Log.e(TAG, "attemp to cancel bond fail!");
  25. }
  26. }
  27. }

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

    (1)注册广播


 
 
  1. IntentFilter filter4 = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
  2. IntentFilter filter5 = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
  3. registerReceiver(pinBlueReceiver,filter4);
  4. registerReceiver(pinBlueReceiver,filter5);

    (2)接收广播


 
 
  1. /**配对广播接收类
  2. * Created by zqf on 2018/7/7.
  3. */
  4. public class PinBlueReceiver extends BroadcastReceiver {
  5. private String pin = "0000"; //此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
  6. private static final String TAG = PinBlueReceiver.class.getName();
  7. private PinBlueCallBack callBack;
  8. public PinBlueReceiver(PinBlueCallBack callBack){
  9. this.callBack = callBack;
  10. }
  11. //广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行
  12. @Override
  13. public void onReceive(Context context, Intent intent) {
  14. String action = intent.getAction();
  15. Log.d(TAG, "action:" + action);
  16. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  17. if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
  18. try {
  19. callBack.onBondRequest();
  20. //1.确认配对
  21. // ClsUtils.setPairingConfirmation(device.getClass(), device, true);
  22. Method setPairingConfirmation = device.getClass().getDeclaredMethod("setPairingConfirmation",boolean.class);
  23. setPairingConfirmation.invoke(device,true);
  24. //2.终止有序广播
  25. Log.d("order...", "isOrderedBroadcast:"+isOrderedBroadcast()+",isInitialStickyBroadcast:"+isInitialStickyBroadcast());
  26. abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
  27. //3.调用setPin方法进行配对...
  28. // boolean ret = ClsUtils.setPin(device.getClass(), device, pin);
  29. Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
  30. Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
  31. } catch (Exception e) {
  32. // TODO Auto-generated catch block
  33. e.printStackTrace();
  34. }
  35. }else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
  36. switch (device.getBondState()) {
  37. case BluetoothDevice.BOND_NONE:
  38. Log.d(TAG, "取消配对");
  39. callBack.onBondFail(device);
  40. break;
  41. case BluetoothDevice.BOND_BONDING:
  42. Log.d(TAG, "配对中");
  43. callBack.onBonding(device);
  44. break;
  45. case BluetoothDevice.BOND_BONDED:
  46. Log.d(TAG, "配对成功");
  47. callBack.onBondSuccess(device);
  48. break;
  49. }
  50. }
  51. }
  52. }

连接蓝牙

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

1.连接线程


 
 
  1. /**连接线程
  2. * Created by zqf on 2018/7/7.
  3. */
  4. public class ConnectBlueTask extends AsyncTask <BluetoothDevice, Integer, BluetoothSocket> {
  5. private static final String TAG = ConnectBlueTask.class.getName();
  6. private BluetoothDevice bluetoothDevice;
  7. private ConnectBlueCallBack callBack;
  8. public ConnectBlueTask(ConnectBlueCallBack callBack){
  9. this.callBack = callBack;
  10. }
  11. @Override
  12. protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
  13. bluetoothDevice = bluetoothDevices[0];
  14. BluetoothSocket socket = null;
  15. try{
  16. Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);
  17. socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(ClassicsBluetooth.UUID));
  18. if (socket != null && !socket.isConnected()){
  19. socket.connect();
  20. }
  21. }catch (IOException e){
  22. Log.e(TAG,"socket连接失败");
  23. try {
  24. socket.close();
  25. } catch (IOException e1) {
  26. e1.printStackTrace();
  27. Log.e(TAG,"socket关闭失败");
  28. }
  29. }
  30. return socket;
  31. }
  32. @Override
  33. protected void onPreExecute() {
  34. Log.d(TAG,"开始连接");
  35. if (callBack != null) callBack.onStartConnect();
  36. }
  37. @Override
  38. protected void onPostExecute(BluetoothSocket bluetoothSocket) {
  39. if (bluetoothSocket != null && bluetoothSocket.isConnected()){
  40. Log.d(TAG,"连接成功");
  41. if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
  42. }else {
  43. Log.d(TAG,"连接失败");
  44. if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败");
  45. }
  46. }
  47. }

2.启动连接线程


 
 
  1. /**
  2. * 连接 (在配对之后调用)
  3. * @param device
  4. */
  5. public void connect(BluetoothDevice device, ConnectBlueCallBack callBack){
  6. if (device == null){
  7. Log.d(TAG, "bond device null");
  8. return;
  9. }
  10. if (!isBlueEnable()){
  11. Log.e(TAG, "Bluetooth not enable!");
  12. return;
  13. }
  14. //连接之前把扫描关闭
  15. if (mBluetoothAdapter.isDiscovering()){
  16. mBluetoothAdapter.cancelDiscovery();
  17. }
  18. new ConnectBlueTask(callBack).execute(device);
  19. }

3.判断是否连接成功


 
 
  1. /**
  2. * 蓝牙是否连接
  3. * @return
  4. */
  5. public boolean isConnectBlue(){
  6. return mBluetoothSocket != null && mBluetoothSocket.isConnected();
  7. }

4.断开连接


 
 
  1. /**
  2. * 断开连接
  3. * @return
  4. */
  5. public boolean cancelConnect(){
  6. if (mBluetoothSocket != null && mBluetoothSocket.isConnected()){
  7. try {
  8. mBluetoothSocket.close();
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. return false;
  12. }
  13. }
  14. mBluetoothSocket = null;
  15. return true;
  16. }

5.MAC地址连接


 
 
  1. /**
  2. * 输入mac地址进行自动配对
  3. * 前提是系统保存了该地址的对象
  4. * @param address
  5. * @param callBack
  6. */
  7. public void connectMAC(String address, ConnectBlueCallBack callBack) {
  8. if (!isBlueEnable()){
  9. return ;
  10. }
  11. BluetoothDevice btDev = mBluetoothAdapter.getRemoteDevice(address);
  12. connect(btDev, callBack);
  13. }

通信

1.读取数据线程


 
 
  1. /**读取线程
  2. * Created by zqf on 2018/7/7.
  3. */
  4. public class ReadTask extends AsyncTask <String, Integer, String> {
  5. private static final String TAG = ReadTask.class.getName();
  6. private ReadCallBack callBack;
  7. private BluetoothSocket socket;
  8. public ReadTask(ReadCallBack callBack, BluetoothSocket socket){
  9. this.callBack = callBack;
  10. this.socket = socket;
  11. }
  12. @Override
  13. protected String doInBackground(String... strings) {
  14. BufferedInputStream in = null;
  15. try {
  16. StringBuffer sb = new StringBuffer();
  17. in = new BufferedInputStream(socket.getInputStream());
  18. int length = 0;
  19. byte[] buf = new byte[1024];
  20. while ((length = in.read()) != -1) {
  21. sb.append(new String(buf,0,length));
  22. }
  23. return sb.toString();
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }finally {
  27. try {
  28. in.close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. return "读取失败";
  34. }
  35. @Override
  36. protected void onPreExecute() {
  37. Log.d(TAG,"开始读取数据");
  38. if (callBack != null) callBack.onStarted();
  39. }
  40. @Override
  41. protected void onPostExecute(String s) {
  42. Log.d(TAG,"完成读取数据");
  43. if (callBack != null){
  44. if ("读取失败".equals(s)){
  45. callBack.onFinished(false, s);
  46. }else {
  47. callBack.onFinished(true, s);
  48. }
  49. }
  50. }
  51. }

2.写入数据线程


 
 
  1. /**写入线程
  2. * Created by zqf on 2018/7/7.
  3. */
  4. public class WriteTask extends AsyncTask <String, Integer, String>{
  5. private static final String TAG = WriteTask.class.getName();
  6. private WriteCallBack callBack;
  7. private BluetoothSocket socket;
  8. public WriteTask(WriteCallBack callBack, BluetoothSocket socket){
  9. this.callBack = callBack;
  10. this.socket = socket;
  11. }
  12. @Override
  13. protected String doInBackground(String... strings) {
  14. String string = strings[0];
  15. OutputStream outputStream = null;
  16. try{
  17. outputStream = socket.getOutputStream();
  18. outputStream.write(string.getBytes());
  19. } catch (IOException e) {
  20. Log.e("error", "ON RESUME: Exception during write.", e);
  21. return "发送失败";
  22. }finally {
  23. try {
  24. outputStream.close();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. return "发送成功";
  30. }
  31. @Override
  32. protected void onPreExecute() {
  33. if (callBack != null) callBack.onStarted();
  34. }
  35. @Override
  36. protected void onPostExecute(String s) {
  37. if (callBack != null){
  38. if ("发送成功".equals(s)){
  39. callBack.onFinished(true, s);
  40. }else {
  41. callBack.onFinished(false, s);
  42. }
  43. }
  44. }
  45. }

 

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值