欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android蓝牙通信之搜索蓝牙设备

程序员文章站 2023-12-14 12:50:40
一:注意事项       1:android6.0使用蓝牙时,需要开启gps定位权限,不然无法搜索其它蓝牙设备。 二:...

一:注意事项

      1:android6.0使用蓝牙时,需要开启gps定位权限,不然无法搜索其它蓝牙设备。

二:权限

      1:权限配置

<!--允许程序连接到已配对的蓝牙设备-->
<uses-permission android:name="android.permission.bluetooth" />
<!-- 允许程序发现和配对蓝牙设备 -->
<uses-permission android:name="android.permission.bluetooth_admin" />
 <!--android 6.0 涉及到的权限-->
<uses-permission android:name="android.permission.access_fine_location" />
<uses-permission android:name="android.permission.access_coarse_location" />
<!-- 在sdcard中创建与删除文件的权限 -->
<uses-permission android:name="android.permission.mount_unmount_filesystems"/>
<!-- 往sdcard写入数据的权限 -->
<uses-permission android:name="android.permission.write_external_storage"/>

    2:动态权限代码

    由于需要用到存储卡,定位等,android6.0以上需要代码动态设置。

   a)获取定位设置

if (build.version.sdk_int >= 23) {
  boolean islocat = islocationopen(getapplicationcontext());
  toast.maketext(mcontext, "islo:" + islocat, toast.length_long).show();
   //开启位置服务,支持获取ble蓝牙扫描结果
  if (!islocat) {
  intent enablelocate = new intent(settings.action_location_source_settings);
  startactivityforresult(enablelocate, 1);
  }
}
 /**
  * 判断位置信息是否开启
  *
  * @param context
  * @return
  */
 private static boolean islocationopen(final context context) {
  locationmanager manager = (locationmanager) context.getsystemservice(context.location_service);
  //gps定位
  boolean isgpsprovider = manager.isproviderenabled(locationmanager.gps_provider);
  //网络定位
  boolean isnetworkprovider = manager.isproviderenabled(locationmanager.network_provider);
  return isgpsprovider || isnetworkprovider;
 }

b)存储卡权限设置

if (build.version.sdk_int >= 23) {
   int write = checkselfpermission(manifest.permission.write_external_storage);
   int read = checkselfpermission(manifest.permission.read_external_storage);
   //动态请求读写sd卡权限
   if (write != packagemanager.permission_granted || read != packagemanager.permission_granted) {
    requestpermissions(new string[]{manifest.permission.write_external_storage, manifest.permission.read_external_storage}, sd_card);
   }
}

然后通过onrequestpermissionsresult()方法获取动态权限的结果:

@override
 public void onrequestpermissionsresult(int requestcode, string[] permissions, int[] grantresults) {
  switch (requestcode){
   case sd_card:
    if(grantresults.length>0&&grantresults[0] == packagemanager.permission_granted){
     //允许访问
    }else{
     toast.maketext(mcontext,"您拒绝了程序访问存储卡",toast.length_long).show();
    }
    break;
   case coares_location:
    break;
  }
 }

 三:蓝牙搜索

android.bluetooth.bluetoothadapter 是蓝牙开发用得比较多,并且比较重要的一个类,可以设备蓝牙名称,打开,关闭,搜索等常规操作。

  1 蓝牙打开,以及搜索

     蓝牙打开和关闭信息使用bluetoothadapter.action_state_changed去接收广播

bluetoothadapter mbluetoothadapter = bluetoothadapter.getdefaultadapter();
mbluetoothadapter.setname("bluetestphone"); 
//判断蓝牙是否打开
boolean originalbluetooth = (mbluetoothadapter != null && mbluetoothadapter.isenabled());
if (originalbluetooth) {
 mbluetoothadapter.startdiscovery();
} else if (originalbluetooth == false) {
 mbluetoothadapter.enable();
}

蓝牙打开后,我们可以获取设备的蓝牙信息

stringbuilder sb = new stringbuilder();
 //获取本机蓝牙名称
 string name = mbluetoothadapter.getname();
//获取本机蓝牙地址
 string address = mbluetoothadapter.getaddress();

搜索完成后,通过bluetoothdevice.action_found广播去接收结果,广播代码如下(注意:可能出现设备搜索不到的情况,设备需要开启允许周围设备搜索,或者通过程序来控制允许搜索的时间范围)

Android蓝牙通信之搜索蓝牙设备

 /*确保蓝牙被发现,在荣耀8手机上,设置了还是默认的2分钟,所以以下几句代码程序中没有,*/
intent discoverableintent = new intent(bluetoothadapter.action_request_discoverable);
//设置可见状态的持续时间为300秒,但是最多是300秒
discoverableintent.putextra(bluetoothadapter.extra_discoverable_duration, 300);
startactivityforresult(discoverableintent, request_discoverable_bluetooth);
private void initsearchbroadcast() {
  intentfilter intentfilter = new intentfilter();
  //发现设备
  intentfilter.addaction(bluetoothdevice.action_found);
  //设备配对状态改变
  intentfilter.addaction(bluetoothdevice.action_bond_state_changed);
  //蓝牙设备状态改变
  intentfilter.addaction(bluetoothadapter.action_state_changed);
  //开始扫描
  intentfilter.addaction(bluetoothadapter.action_discovery_started);
  //结束扫描
  intentfilter.addaction(bluetoothadapter.action_discovery_finished);
  //其它设备请求配对
  intentfilter.addaction(action_pairing_request);
  //intentfilter.addaction(bluetoothadapter.connection_state_changed);
  registerreceiver(bluetoothreceiver, intentfilter);
 }
private broadcastreceiver bluetoothreceiver = new broadcastreceiver() {
  @override
  public void onreceive(context context, intent intent) {
   string action = intent.getaction();
   logger.e(tag + "mbluetoothreceiver action =" + action);
   try {
    if (bluetoothadapter.action_discovery_started.equals(action)) {//开始扫描
     setprogressbarindeterminatevisibility(true);
     log1.settext("正在扫描设备,请稍候...");
    } else if (bluetoothadapter.action_discovery_finished.equals(action)) {//结束扫描
     logger.e(tag + "设备搜索完毕");
     setprogressbarindeterminatevisibility(false);
     log1.settext("扫描完成");
     bondadapter.notifydatasetchanged();
     unbondadapter.notifydatasetchanged();
     scanstatus = false;
    } else if (bluetoothdevice.action_found.equals(action)) {//发现设备
     finddevice(intent);
    } else if (bluetoothdevice.action_bond_state_changed.equals(action)) {//蓝牙配对状态的广播
     bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device);
     logger.e(tag + device.getname() + "蓝牙配对广播:" + device.getbondstate());
     switch (device.getbondstate()) {
      case bluetoothdevice.bond_bonding:
       logger.e(tag + device.getname() + "蓝牙配对广播 正在配对......");
       break;
      case bluetoothdevice.bond_bonded:
       logger.e(tag + device.getname() + "蓝牙配对广播 完成配对,本机自动配对");
       bonddevices.add(device);
       unbonddevices.remove(device);
       bondadapter.notifydatasetchanged();
       unbondadapter.notifydatasetchanged(); 
       break;
      case bluetoothdevice.bond_none:
       logger.e(tag + device.getname() + "蓝牙配对广播 取消配对");
       unbonddevices.add(device);
       bonddevices.remove(device);
       unbondadapter.notifydatasetchanged();
       bondadapter.notifydatasetchanged();
      default:
       break;
     }
    } else if (action.equals(action_pairing_request)) {//其它设备蓝牙配对请求
     bluetoothdevice btdevice = intent.getparcelableextra(bluetoothdevice.extra_device);
     int state = intent.getintextra(bluetoothdevice.extra_bond_state, bluetoothdevice.bond_none); //当前的配对的状态
     try {
      string path = environment.getexternalstoragedirectory() + "/bluetest/";
      string devicename = btdevice.getname();
      logger.e(tag + "蓝牙 匹配信息:" + devicename + "," + btdevice.getaddress() + ",state:" + state);
      //1.确认配对,高版本无效,蓝牙配对不是zuk的问题,而是安卓6.0的bug,凡是遇到蓝牙适配问题的,请同时打开蓝牙和定位,再去配对,基本90%都没有问题了。
      object object = clsutils.setpairingconfirmation(btdevice.getclass(), btdevice, true);
      //2.终止有序广播,如果没有将广播终止,则会出现一个一闪而过的配对框。
      abortbroadcast();
      //3.调用setpin方法进行配对...
      boolean ret = clsutils.setpin(btdevice.getclass(), btdevice, pwd);
     } catch (exception e) {
      // todo auto-generated catch block
      e.printstacktrace();
      toast.maketext(mcontenxt, "error:" + btdevice + "," + state, toast.length_long).show();
     }
    } else if (action.equals(bluetoothadapter.action_state_changed)) {//蓝牙开关状态
     // bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device);
     int statue = mbluetoothadapter.getstate();
     switch (statue) {
      case bluetoothadapter.state_off:
       logger.e("蓝牙状态:,蓝牙关闭");
       clsutils.closediscoverabletimeout(mbluetoothadapter);
       break;
      case bluetoothadapter.state_on:
       logger.e("蓝牙状态:,蓝牙打开");
       clsutils.setdiscoverabletimeout(1000 * 60, mbluetoothadapter);
       scanbluetooth();
       break;
      case bluetoothadapter.state_turning_off:
       logger.e("蓝牙状态:,蓝牙正在关闭");
       mbluetoothadapter.canceldiscovery();
       break;
      case bluetoothadapter.state_turning_on:
       logger.e("蓝牙状态:,蓝牙正在打开");
       break;
     }
    }
   } catch (exception e) {
    e.printstacktrace();
   }
  }
 };
//发现设备的代码如下
 private void finddevice(intent intent) throws exception{
 //获取到设备对象
 bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device);
 string str = device.getname() + "|" + device.getaddress();
 logger.e("扫描到设备:" + str);
 if (device.getbondstate() == bluetoothdevice.bond_bonded) {//判断当前设备地址下的device是否已经配对
  if (!bonddevices.contains(device)) {
   bonddevices.add(device);
  }
 } else {
  if (!unbonddevices.contains(device)) {
   unbonddevices.add(device);
  }
  if (device.getname().equals(test_device_name)) {
   boolean bondstatus = clsutils.createbond(device.getclass(), device);
   logger.i(tag + " bondstatus:" + bondstatus);
  }
 }
 log.e("error", "搜索完毕,准备刷新!");
 bondadapter.notifydatasetchanged();
 unbondadapter.notifydatasetchanged();
}

四:蓝牙配对

   正常情况下,蓝牙匹配需要弹出一个匹配确认框,如下图,但我想实现的是,匹配其中一方,不能手动点击配对,因为发起蓝牙连接的设备是android设备,是不能触摸的,所以就要通过程序来解决这个问题,特别声明:(测试的android设备,版本为5.x,并且已经root,没有root的设备,或者不是android5.x不清楚能否实现自动匹配,因为我只有这个测试设备)。

Android蓝牙通信之搜索蓝牙设备

1 当我们搜索到目标手机的蓝牙后,android设备主动发起连接请求,代码如下

 if (device.getname().equals(test_device_name)) {
    boolean bondstatus = clsutils.createbond(device.getclass(), device);
    logger.i(tag + " bondstatus:" + bondstatus);
 }
//发起蓝牙匹配请求 
public boolean createbond(class btclass, bluetoothdevice btdevice)
   throws exception {
  method createbondmethod = btclass.getmethod("createbond");
  boolean returnvalue = (boolean) createbondmethod.invoke(btdevice);
  return returnvalue.booleanvalue();
}

2 当被匹配方点击配对后,系统会通过bluetoothdevice.action_bond_state_changed广播告诉android设备,此时android设备就可以自动确认,通过这个流程来完成整个蓝牙的配对,具体代码如下

 bluetoothdevice btdevice = intent.getparcelableextra(bluetoothdevice.extra_device);
     int state = intent.getintextra(bluetoothdevice.extra_bond_state, bluetoothdevice.bond_none); //当前的配对的状态
     try {
      string path = environment.getexternalstoragedirectory() + "/bluetest/";
      string devicename = btdevice.getname();
      logger.e(tag + "蓝牙 匹配信息:" + devicename + "," + btdevice.getaddress() + ",state:" + state); 
      if(devicename.equals(test_device_name)){//test_device_name 为被匹配蓝牙设备的名称,自己手动定义
       object object = clsutils.setpairingconfirmation(btdevice.getclass(), btdevice, true);
       abortbroadcast();
       boolean ret = clsutils.setpin(btdevice.getclass(), btdevice, pwd);
      }
     } catch (exception e) {
      // todo auto-generated catch block
      e.printstacktrace();
      toast.maketext(mcontenxt, "error:" + btdevice + "," + state, toast.length_long).show();
     }
//确认配对
public object setpairingconfirmation(class<?> btclass, bluetoothdevice device, boolean isconfirm) throws exception {
  method setpairingconfirmation = btclass.getdeclaredmethod("setpairingconfirmation", boolean.class);
  object object = setpairingconfirmation.invoke(device, isconfirm);
   return object;
 }
//配对需要调用的方法
public boolean setpin(class<? extends bluetoothdevice> btclass, bluetoothdevice btdevice,
         string str) throws exception {
  try {
   method removebondmethod = btclass.getdeclaredmethod("setpin",
     new class[]
       {byte[].class});
   boolean returnvalue = (boolean) removebondmethod.invoke(btdevice,
     new object[]
       {str.getbytes()});
   log.e("returnvalue", "" + returnvalue);
  } catch (securityexception e) {
   // throw new runtimeexception(e.getmessage());
   e.printstacktrace();
  } catch (illegalargumentexception e) {
   // throw new runtimeexception(e.getmessage());
   e.printstacktrace();
  } catch (exception e) {
   // todo auto-generated catch block
   e.printstacktrace();
  }
  return true;
 }     

      到目前为止,蓝牙权限,以及动态权限,蓝牙的打开,关闭,搜索,以及自动配对(特别声明:(自动配对的android设备,版本为5.x,并且已经root,没有root的设备,或者不是android5.x不清楚能否实现自动匹配,因为我只有这个测试设备)。)代码至此结束。

demo代码下载:

总结

以上所述是小编给大家介绍的android蓝牙通信之搜索蓝牙设备,希望对大家有所帮助

上一篇:

下一篇: