您的位置:首页 > 移动开发 > Android开发

Android 6.0后蓝牙的开发,搜索,配对,连接发送数据等(一)

2017-12-06 11:47 976 查看
最近在项目中需要使用蓝牙链接蓝牙打印机 , 所有对蓝牙的开发做了一下整理以供学习 . 

**如果是小米手机请先手动在应用权限里打开定位权限, 下一篇博客告诉你原因和我踩过的坑**

首先在Android 6.0以后对手机权限做了修改 , 蓝牙的搜索需要需要在清单配置里面添加两个定位的权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

蓝牙设备自己的权限

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

android里面蓝牙是通过BluetoothAdapter来进行操作的,首先我们需要获取到BluetoothAdapter的实例

BluetoothAdapter blueToothAdapter = BluetoothAdapter.getDefaultAdapter();

在搜索之前,我们可以先获取与之前已经配对过的蓝牙设备

Set<BluetoothDevice> bondedDevices = blueToothAdapter.getBondedDevices();

打开蓝牙的方式有三种:

//第一种打开方式
blueToothAdapter.enable();
//第二种打开方式

//会以dialog的形式打开一个activity,并且如果我们通过startActivityForResult的形式的话
//还能查看蓝牙是否被打开,或者处理蓝牙被打开之后的操作
//如果是result_ok的话那么是打开,反之打开失败
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);//第三种打开方式
//第三种打开方式 设置本地设备可以被其它设备搜索,可被搜索的时间是有限的,最多为300s
//效果和第二种类似
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);startActivity(discoverableIntent);
关闭蓝牙

blueToothAdapter.disable();

蓝牙的搜索

blueToothAdapter.startDiscovery();

取消蓝牙搜索
blueToothAdapter.cancelDiscovery();

我们要在代码里面注册这个广播接收器,在调用蓝牙的搜索方法,就能够进行蓝牙的搜索了

//注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //本地蓝牙适配器已经完成设备的搜寻过程。
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//动作状态发生了变化
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(bluetoothReceiver, intentFilter);

通过接收广播的形式来接收。所以我们应该自定义一个广播接收器,

private final BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
showToast("找到新设备了"+device.getName()+"..."+device.getAddress());
boolean addFlag = true;
for (BluetoothDevice bluetoothDevice : strArr) {
if (device.getAddress().equals(bluetoothDevice.getAddress())) {
addFlag = false;
}
}

if (addFlag) {
strArr.add(device);
adapter.notifyDataSetChanged();
}
} else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()) {
case BluetoothDevice.BOND_NONE:
Log.e(getPackageName(), "取消配对");
break;
case BluetoothDevice.BOND_BONDING:
Log.e(getPackageName(), "配对中");
break;
case BluetoothDevice.BOND_BONDED:
Log.e(getPackageName(), "配对成功");
break;
}

}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
showToast("收搜结束");
}else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
showToast("收搜开始");
}
}
};

这里需要注意的是,如果你的代码将运行在(Build.VERSION.SDK_INT >= 23)的设备上,那么务必加上以下权限,并在代码中动态的申请权限

private void requestPermission() {

if (Build.VERSION.SDK_INT >= 23) {
//校验是否已具有模糊定位权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)   //可读
!= PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)  //可写
!= PackageManager.PERMISSION_GRANTED
) {
//申请ACCESS_FINE_LOCATION权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_PERMISSION_ACCESS_LOCATION);
} else {
//具有权限,开始收搜
search();
}
} else {
//系统不高于6.0直接执行
search();
}

}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int
b838
[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_ACCESS_LOCATION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showToast("权限开启");
//开始收搜
search();
} else {
showToast("没有定位权限,请先开启!");
}
}
}

}

蓝牙的配对,通过反射的形式来调用BluetoothDevice的createBondde()方法,我们要监听配对的过程,就可以在广播接收器再注册一个action。在上面的广播注册已给出代码

try {
Method method = BluetoothDevice.class.getMethod("createBond");
Log.e(getPackageName(), "开始配对");
method.invoke(strArr.get(i));
} catch (Exception e) {
e.printStackTrace();
}

向已配对的设备发送数据

发送数据分为服务端和客户端,通过socket来进行消息的交互。

服务端:

new Thread(new Runnable() {
@Override
public void run() {
InputStream is = null;
try {
BluetoothServerSocket serverSocket = blueToothAdapter.listenUsingRfcommWithServiceRecord("serverSocket", uuid);
mHandler.sendEmptyMessage(startService);
BluetoothSocket accept = serverSocket.accept();
is = accept.getInputStream();

byte[] bytes = new byte[1024];
int length = is.read(bytes);

Message msg = new Message();
msg.what = getMessageOk;
msg.obj = new String(bytes, 0, length);
mHandler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();

客户端

new Thread(new Runnable() {
@Override
public void run() {
OutputStream os = null;
try {
BluetoothSocket socket = strArr.get(i).createRfcommSocketToServiceRecord(uuid);
socket.connect();
os = socket.getOutputStream();
os.write("testMessage".getBytes());
os.flush();
mHandler.sendEmptyMessage(sendOver);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();

可以看到无论是服务端还是客户端,都需要新起一个子线程来操作。那么服务端和客户端是怎么识别对方的呢,那么就需要用到UUID了,只有当服务端和客户端的UUID相同的时候才能够建立连接。

蓝牙开发demo下载 :demo下载

下一篇博客说说我在蓝牙发开时遇到的坑
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: