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

最近在项目中需要使用蓝牙链接蓝牙打印机 , 所有对蓝牙的开发做了一下整理以供学习 . 

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

首先在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[] 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下载


下一篇博客说说我在蓝牙发开时遇到的坑


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值