美文网首页
android的蓝牙匹配连接

android的蓝牙匹配连接

作者: sunny635533 | 来源:发表于2022-02-15 16:37 被阅读0次

    1、声明权限

      <uses-permission android:name="android.permission.INTERNET"/>
        <!--蓝牙连接要用到权限-->
        <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
        <!--蓝牙搜索要用到权限-->
        <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
        <!--蓝牙基本的权限-->
        <uses-permission android:name="android.permission.BLUETOOTH"/>
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
        <!-- If your app targets Android 9 or lower, you can declare
             ACCESS_COARSE_LOCATION instead. -->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <!--获取本设备的mac地址的权限-->
        <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"
            tools:ignore="ProtectedPermissions" />
    
    <!--    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />-->
    <!--    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />-->
        <!--    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />-->
    

    注意:定位权限是必须的,否则无法使用蓝牙的搜索功能

    2、获取蓝牙已匹配过的设备和搜索可匹配的设备列表
    需要判断蓝牙是否启用,工具类如下:

    package com.org.testbluetooth;
    
    import android.Manifest;
    import android.app.Activity;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothManager;
    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.util.Log;
    
    import androidx.annotation.RequiresApi;
    
    import java.lang.reflect.Method;
    
    public class BluetoothUtils {
    
       public static final String TAG = BluetoothUtils.class.getSimpleName();
       /**
        * 获取系统蓝牙适配器管理类
        */
       public BluetoothAdapter mBluetoothAdapter;
       private BluetoothManager bluetoothManager;
    
       private static class Holder {
           public static BluetoothUtils INSTANCE = new BluetoothUtils();
       }
    
       public static BluetoothUtils getInstance() {
           return Holder.INSTANCE;
       }
    
       public void init(Activity context) {
           if (bluetoothManager == null) {
               bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
           }
           mBluetoothAdapter = bluetoothManager.getAdapter();
           // 询问打开蓝牙
           if (!isBlueEnable()) {
               openBlueSync(context, 1);
           }
       }
    
       public BluetoothAdapter getBlueAdapter(){
           return mBluetoothAdapter;
       }
    
       /**
        * 设备是否支持蓝牙  true为支持
        *
        * @return
        */
       public boolean isSupportBlue() {
           return mBluetoothAdapter != null;
       }
    
       /**
        * 蓝牙是否打开   true为打开
        *
        * @return
        */
       public boolean isBlueEnable() {
           return isSupportBlue() && mBluetoothAdapter.isEnabled();
       }
    
       /**
        * 开启广播
        */
       public void openBroadCast(Activity activity, BroadcastReceiver scanBlueReceiver) {
           IntentFilter intentFilter = new IntentFilter();
           intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//获得扫描结果
           intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//绑定状态变化
           intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描
           intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束
           activity.registerReceiver(scanBlueReceiver, intentFilter);
       }
    
       /**
        * 自动打开蓝牙(同步)
        * 这个方法打开蓝牙会弹出提示
        * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功
        */
       public void openBlueSync(Activity activity, int requestCode) {
           Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
           activity.startActivityForResult(intent, requestCode);
       }
    
       /**
        * 配对(配对成功与失败通过广播返回)
        *
        * @param device
        */
       public void pinBlue(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");
                   createBondMethod.invoke(device);
               } catch (Exception e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
                   Log.e(TAG, "attemp to bond fail!");
               }
           }
       }
    
       /**
        * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
        *
        * @param device
        */
       public void cancelPinBlue(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");
                   removeBondMethod.invoke(device);
               } catch (Exception e) {
                   e.printStackTrace();
                   Log.e(TAG, "attemp to cancel bond fail!");
               }
           }
       }
    
       @RequiresApi(Build.VERSION_CODES.M)
       public Boolean hasPermissions(Activity activity,int requestCode) {
           if (!hasLocationPermissions(activity)) {
               requestLocationPermission(activity,requestCode);
               return false;
           }
           return true;
       }
       @RequiresApi(Build.VERSION_CODES.M)
       public Boolean hasLocationPermissions(Activity activity) {
           return activity.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
       }
    
       @RequiresApi(Build.VERSION_CODES.M)
       public void requestLocationPermission(Activity activity,int requestCode) {
           activity.requestPermissions(
                   new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                   requestCode
           );
       }
    }
    
    

    3、activity里的实现
    布局

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.core.widget.NestedScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <androidx.appcompat.widget.LinearLayoutCompat
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/selectBluetoothBtn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#ff0f00"
            android:text="获取已配对设备信息"
            android:layout_marginTop="50dp"/>
    <!--    <Button-->
    <!--        android:id="@+id/setBlueVisableBtn"-->
    <!--        android:layout_width="match_parent"-->
    <!--        android:layout_height="50dp"-->
    <!--        android:background="#ff0f00"-->
    <!--        android:text="设置设备可见"-->
    <!--        android:layout_marginTop="20dp"/>-->
        <Button
            android:id="@+id/startSearchBtn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#ff0f00"
            android:text="开始蓝牙搜索"
            android:layout_marginTop="20dp"/>
    
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="已匹配的设备列表"
            android:layout_marginTop="30dp"/>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycleview"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/startSearchBtn"
            android:layout_marginTop="10dp"/>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="搜索到的设备列表"
            android:layout_marginTop="30dp"/>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/searchRecycleview"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/startSearchBtn"
            android:layout_marginTop="10dp"/>
    
    </androidx.appcompat.widget.LinearLayoutCompat>
    </androidx.core.widget.NestedScrollView>
    

    MainAcivity类

    package com.org.testbluetooth
    
    import android.Manifest
    import android.bluetooth.*
    import android.content.BroadcastReceiver
    import android.content.Context
    import android.content.Intent
    import android.content.IntentFilter
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.util.Log
    import android.widget.Button
    import android.widget.Toast
    import java.io.IOException
    import java.util.*
    import android.bluetooth.BluetoothAdapter
    import androidx.recyclerview.widget.LinearLayoutManager
    import kotlinx.android.synthetic.main.activity_main.*
    import android.bluetooth.BluetoothDevice
    import android.content.pm.PackageManager
    import android.os.Build
    import android.os.Message
    import androidx.annotation.RequiresApi
    import java.io.InputStream
    import java.lang.Exception
    
    
    class MainActivity : AppCompatActivity() {
    
       var bluetoothUtils: BluetoothUtils?=null
    
       private val REQUEST_ENABLE_BT = 100
       private val REQUEST_FINE_LOCATION = 0x124
    
       var TAG = "MainActivity"
    
       var searchDevList = mutableListOf<BluetoothDevice>()
    
       private val receiver = object : BroadcastReceiver() {
           override fun onReceive(context: Context?, intent: Intent?) {
               var action: String? = intent?.action
               println("============== onReceive ========action=$action")
               when (action) {
                   BluetoothDevice.ACTION_FOUND -> {
                       val device: BluetoothDevice? =
                           intent?.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
                       val deviceName = device?.name
                       val deviceHardwareAddress = device?.address // MAC address
                       println("========= 通过receiver发现设备 ======${deviceName}  ${deviceHardwareAddress}")
                       if (device != null && !deviceName.isNullOrEmpty()) {
                           searchDevList.add(device)
                       }
                   }
                   BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
                       println("============== onReceive ACTION_DISCOVERY_FINISHED========蓝牙设备搜索完成=$action")
                       initSearchRecycleView(searchDevList)
                   }
               }
           }
       }
    
       @RequiresApi(Build.VERSION_CODES.M)
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(R.layout.activity_main)
    
           bluetoothUtils = BluetoothUtils.getInstance()
           bluetoothUtils?.init(this)
    
           selectBluetoothBtn.setOnClickListener { getBluetoothAdapter() }
           startSearchBtn.setOnClickListener { startScanBluetooth() }
    
          bluetoothUtils?.openBroadCast(this,receiver)
    
           //获取已匹配过的蓝牙设备集合
           getBluetoothAdapter()
       }
    
       /**
        * 获取已匹配的蓝牙设备
        */
       @RequiresApi(Build.VERSION_CODES.M)
       fun getBluetoothAdapter() {
           //以检查当前是否已启用蓝牙。如果此方法返回 false,则表示蓝牙处于停用状态
          var hasPer = bluetoothUtils?.hasPermissions(this,REQUEST_FINE_LOCATION)
           if(!hasPer!!){
               Toast.makeText(this,"没有权限",Toast.LENGTH_SHORT).show()
               return;
           }
    
           var bluetoothAdapter = bluetoothUtils?.mBluetoothAdapter
           //获取本机蓝牙名称
           var localBlueName = bluetoothAdapter?.name
           //获取本机蓝牙地址
           var localAaddress = bluetoothAdapter?.address
           println("==== 本机蓝牙信息:本机蓝牙名称 =$localBlueName 本机蓝牙地址 =$localAaddress")
    
           println("========已匹配的设备条数==========" + bluetoothAdapter?.bondedDevices?.size)
           val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
           pairedDevices?.forEach { device ->
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
               println("=======name=>$deviceName")
               println("=======address=>$deviceHardwareAddress")
           }
    
           var list = pairedDevices?.toList();
           if (list != null) {
               initRecycleView(list)
           }
       }
    
       /**
        * 开启蓝牙搜索
        */
       fun startScanBluetooth() {
           var bluetoothAdapter = bluetoothUtils?.mBluetoothAdapter
           // 判断是否在搜索,如果在搜索,就取消搜索
           if (bluetoothAdapter == null) {
               println("======= bluetoothAdapter为空 =======")
               return;
           }
           if (bluetoothAdapter?.isDiscovering == true) {
               bluetoothAdapter?.cancelDiscovery()
           }
           searchDevList.clear()
           bluetoothAdapter?.startDiscovery()
       }
    
       /**
        * 设置蓝牙可见性,允许外部发现本设备
        * 有时候扫描不到某设备,这是因为该设备对外不可见或者距离远,需要设备该蓝牙可见,这样该才能被搜索到。
        * 可见时间默认值为120s,最多可设置300。
        */
    //    fun setVisableToBluetooth() {
    //        println("=========scanMode =========" + bluetoothAdapter?.scanMode)
    ////    if (bluetoothAdapter?.scanMode !=
    ////        BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
    //        var discoverableIntent = Intent(
    //            BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE
    //        )
    //        discoverableIntent.putExtra(
    //            BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120
    //        )
    ////        startActivityForResult(discoverableIntent,REQUEST_LOCAL_VISABLE)
    //        startActivity(discoverableIntent)
    ////    }
    //    }
    
       @RequiresApi(Build.VERSION_CODES.M)
       override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
           super.onActivityResult(requestCode, resultCode, data)
           println("========= onActivityResult =======resultCode:$resultCode, requestCode:$requestCode")
           if (resultCode == RESULT_OK) {
               if (requestCode == REQUEST_ENABLE_BT) {
                   Toast.makeText(this, "蓝牙开启成功", Toast.LENGTH_LONG).show()
               }else  if (requestCode == REQUEST_FINE_LOCATION) {
                   Toast.makeText(this, "定位权限开启成功", Toast.LENGTH_LONG).show()
                   getBluetoothAdapter()
               }
           }
       }
    
       override fun onDestroy() {
           super.onDestroy()
           unregisterReceiver(receiver)
       }
    
    
       /**
        * 客户端连接
        */
       private inner class ConnectThread(device: BluetoothDevice) : Thread() {
           lateinit var bluetoothDevice: BluetoothDevice;
    
           val MY_UUID = UUID.fromString("0f14d0ab-9605-4a62-a9e4-5ed26688389b")
           private val mmScoket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
               bluetoothDevice = device;
               device.createRfcommSocketToServiceRecord(MY_UUID)
           }
    
           override fun run() {
               super.run()
               // Cancel discovery because it otherwise slows down the connection.
               var bluetoothAdapter = bluetoothUtils?.mBluetoothAdapter
               bluetoothAdapter?.cancelDiscovery()
    
               try {
                   mmScoket?.use { socket ->
                       //Connect to the remote device through the socket. This call blocks until it succeeds or throws an exception
                       socket.connect()
    
                       println("========= 连接设备 =========" + bluetoothDevice.name);
    
                       if(socket.isConnected){//连接成功
    //                        isConnect=true;
    //                        val message = Message()
    //                        message.what =0;
    //                        message.obj =bluetoothDevice.getAddress();
    //                        mHandler.sendMessage(message);
    
                           var inputStream: InputStream = socket.inputStream //获取蓝牙设备发送的数据
                           var buffer = ByteArray(1024)
                           var len:Int = 0
                           var content:String
                           while (len != -1) {
                               len=inputStream.read(buffer)
                               content = String(buffer, 0, len)
    //                            val message = Message()
    //                        message.what =0;
    //                        message.obj =bluetoothDevice.getAddress();
    //                        mHandler.sendMessage(message);
                           }
    
                       }
                   }
               } catch (e: Exception) {
                   try {//关闭这个socket
                       mmScoket?.close()
                   } catch (e2: IOException) {
                       e2.printStackTrace();
                   }
                   return
               }finally {
                   mmScoket?.close()
               }
           }
    
           fun cancel() {
               try {
                   mmScoket?.close()
               } catch (e: IOException) {
                   Log.e(TAG + "_ConnectThread", "Could not close the client socket", e)
               }
    
           }
       }
    
       /**
        * 服务端接收数据
        */
       private inner class AcceptThread : Thread() {
           /**
            *
           name – service name for SDP record
           uuid – uuid for SDP record
            */
           var NAME = "lockName"
           val MY_UUID = UUID.fromString("000000")
           private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) {
               var bluetoothAdapter = bluetoothUtils?.mBluetoothAdapter
               bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID)
           }
    
           override fun run() {
               // Keep listening until exception occurs or a socket is returned.
               var shouldLoop = true
               while (shouldLoop) {
                   val socket: BluetoothSocket? = try {
                       mmServerSocket?.accept()
                   } catch (e: IOException) {
                       Log.e(TAG + "_AcceptThread", "Socket's accept() method failed", e)
                       shouldLoop = false
                       null
                   }
                   socket?.also {
    //                    manageMyConnectedSocket(it)
                       mmServerSocket?.close()
                       shouldLoop = false
                   }
               }
           }
    
           // Closes the connect socket and causes the thread to finish.
           fun cancel() {
               try {
                   mmServerSocket?.close()
               } catch (e: IOException) {
                   Log.e(TAG, "Could not close the connect socket", e)
               }
           }
       }
    
       /**
        * 已匹配过的列表
        */
       fun initRecycleView(list: List<BluetoothDevice>) {
           recycleview.layoutManager = LinearLayoutManager(this)
           var adapter = DeviceAdapter(list, DeviceAdapter.ItemClickListener {
               var device: BluetoothDevice = list.get(it)
    //            var connectThread = ConnectThread(device);
    //            connectThread.start()
               bluetoothUtils?.cancelPinBlue(device)
           })
           recycleview.adapter = adapter
       }
    
       /**
        * 能匹配过的列表
        */
       fun initSearchRecycleView(list: List<BluetoothDevice>) {
           searchRecycleview.layoutManager = LinearLayoutManager(this)
           var adapter = DeviceAdapter(list, DeviceAdapter.ItemClickListener {
               var device: BluetoothDevice = list.get(it)
               bluetoothUtils?.pinBlue(device)
           })
           searchRecycleview.adapter = adapter
       }
    
    }
    

    相关文章

      网友评论

          本文标题:android的蓝牙匹配连接

          本文链接:https://www.haomeiwen.com/subject/fkrllrtx.html