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

一:注意事项

      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广播去接收结果,广播代码如下(注意:可能出现设备搜索不到的情况,设备需要开启允许周围设备搜索,或者通过程序来控制允许搜索的时间范围)

/*确保蓝牙被发现,在荣耀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不清楚能否实现自动匹配,因为我只有这个测试设备)。

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代码下载:github

总结

以上所述是小编给大家介绍的Android蓝牙通信之搜索蓝牙设备,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

以上是 Android蓝牙通信之搜索蓝牙设备 的全部内容, 来源链接: utcz.com/z/358405.html

回到顶部