温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

android蓝牙简单开发的方法是什么

发布时间:2021-12-08 15:14:02 来源:亿速云 阅读:157 作者:iii 栏目:开发技术

本篇内容介绍了“android蓝牙简单开发的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

概述

前段时间学习了一些蓝牙开发的知识,记录一下Android中蓝牙的简单开发。下面是最重要的两个类。

BluetoothAdapter : 蓝牙适配器,通过getDefaultAdapter ()去获取一个实例,如果设备不支持蓝牙的话,返回的是一个null对象,通过它,可以打开、关闭蓝牙,扫描设备、向指定设备创建socket通道…

BluetoothDevice : 代表一个设备对象,可以通过它获取设备的名字、地址、类型等,也可以创建匹配,建立socket通道等等。

1、权限申请

<uses-permission android:name="android.permission.BLUETOOTH"/> 使用蓝牙所需要的权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 使用扫描和设置蓝牙的权限(申明这一个权限必须申明上面一个权限)

Android6以上版本,扫描其他蓝牙还需要位置权限

// Android 9 以下版本
<user-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
// Android 9 以上
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

2、打开蓝牙

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 如果设备不支持蓝牙
if (mBluetoothAdapter == null){
    return;
}
// 设备支持蓝牙功能,调用startActivityForResult去启动蓝牙
if (!mBluetoothAdapter.isEnabled()){
    startBlueTooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
}

打开蓝牙功能是通过startActivity去启动的,但是startActivity这个函数已经过期了,所以我使用官方推荐的Activity Result替代它

ActivityResultLauncher<Intent> startBlueTooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result==null){
                        Toast.makeText(BlueToothActivity.this, "open failed", Toast.LENGTH_SHORT).show();
                    }else {
                        if (result.getResultCode() == RESULT_CANCELED){
                            Toast.makeText(BlueToothActivity.this,"用户取消",Toast.LENGTH_SHORT);
                        }
                    }
                }
            });

3、接收蓝牙状态的改变

通过广播去接收蓝牙状态的改变

class BluetoothStateChangeReceiver extends BroadcastReceiver{
    public int DEFAULT_VALUE_BLUETOOTH = 1000;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,DEFAULT_VALUE_BLUETOOTH);

            switch(state){
                case BluetoothAdapter.STATE_ON:
                    Log.d(TAG, "onReceive: open");
                    break;
                case BluetoothAdapter.STATE_OFF:
                    Log.d(TAG, "onReceive: off");
                    break;
                case BluetoothAdapter.STATE_TURNING_ON :
                    Log.d(TAG, "onReceive: 正在打开");
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    Log.d(TAG, "onReceive: 正在关闭");
                    break;
            }
        }
    }
}

别忘了广播的注册和解注册

IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
stateReceiver = new BluetoothStateChangeReceiver() ;
registerReceiver(stateReceiver,filter);

4、扫描其他的设备

同样通过广播接收,action是BluetoothDevice.ACTION_FOUND

class MyReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 从intent对象中获取蓝牙设备的信息
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 当发现新设备不存在于配对列表中时添加
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    blueNames.add(device.getName()+"\t"+device.getAddress());
                }
                blueAdpater.notifyDataSetChanged();
                Log.d(TAG, "onReceive: " + device.getName());
            }
        }
    }

动态注册广播

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver,filter);

开启扫描

mBluetoothAdapter.startDiscovery();

5、蓝牙配对

public class BondReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch(device.getBondState()){
                    case BluetoothDevice.BOND_BONDED:
                        Log.d(TAG, "onReceive: 配对完成");
                        break;
                    case BluetoothDevice.BOND_BONDING:
                        Log.d(TAG, "onReceive: 正在配对");
                        break;
                    case BluetoothDevice.BOND_NONE:
                        Log.d(TAG, "onReceive: 取消配对");
                        break;
                }
            }
        }
    }

6、获取已经配对的设备

已经配对的设备会被存储起来,通过BluetoothAdpater直接获取即可

Set<BluetoothDevice> paireDevices = mBluetoothAdapter.getBondedDevices();
if (paireDevices.size()>0){
                        for (BluetoothDevice pairedDevice : pairedDevices) {
                        blueNames.add(pairedDevice.getName()+"  "+pairedDevice.getAddress());
                        Log.d(TAG, "onClick: "+pairedDevice.getName());
                    }
}

7、连接设备

想要在两台设备之间创建连接,必须实现客户端和服务端机制,他们之间使用套接字机制进行连接,服务端开放服务器套接字,客户端通过MAC地址向服务端发起连接。客户端和服务端以不同的方式获得BluetoothSocket,当客户端和服务端在同一个RFCOMM通道上分别拥有已连接的BluetoothSocket时,将他们视为彼此已经连接,于是每台设备都获得输入和输出流式传输,并开始传输数据。

连接技术

一种实现技术是自动将每台设备准备为一个服务器,从而使每台设备开放一个服务套接字并侦听连接,在此情况下,任何一台设备都可以发起与另一台设备的连接并称为客户端。

服务器

设置服务器套接字并接受连接,步骤依次如下

1、调用listenUsingRfcommWithServiceRecord()获取一个BluetoothServerSocket, 该函数需要两个参数,第一个是服务器的名称,自己取一个即可,第二个是UUID,用来对信息做唯一性标识,我们可以从网上众多UUID生成器中随机的生成一个,然后使用UUID.fromString(String)初始化一个UUID。

2、通过accept()函数开始侦听连接请求

只有远程设备发送的连接请求中UUID与使用此套接字注册的UUID相匹配时服务器才会接受请求,accept函数会返回已连接的BluetoothSocket

3、连接成功后调用close()关闭BluetoothSocket

 private class AcceptThread extends Thread{

        private final BluetoothServerSocket mmServerSocket;
        private String mSocketType;

        public AcceptThread(boolean secure){
            BluetoothServerSocket tmp = null;
            mSocketType = secure ? "secure" : "Insercure";
            try{
                if (secure){
                    tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE);
                }else{
                    tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE,MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG,"socket type"+ mSocketType + "listen() failed",e);
            }

            mmServerSocket = tmp;
        }

        @Override
        public void run() {
            Log.d(TAG, "Socket Type: " + mSocketType +
                    "BEGIN mAcceptThread" + this);
            setName("AcceptThread"+ mSocketType);

            BluetoothSocket socket = null;
            Log.d(TAG, "run: 开始监听");
            while (true){
                try{
                    socket = mmServerSocket.accept();
                    Log.d("acceptThread", "run: 连接成功");
                    connected(socket,socket.getRemoteDevice(),mSocketType);
                } catch (IOException e) {
                    Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
                    break;
                }

            }
            Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
        }

        public void cancel() {
            Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
            try {
                mmServerSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
            }
        }
    }

上面的secure和Insecure只是使用了不同的UUID而已。

客户端

远程设备开启监听后,我们就发起向此设备的连接,首先必须先获得远程设备的BluetoothDevice对象,然后获取BluetoothSocket发起连接。

基本步骤如下

1、使用BluetoothDevice通过调用createRfcommSocketToServiceRecord(UUID) 获取 BluetoothSocket

2、通过connect发起连接

private class ConnectThread extends Thread{
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private String mSocketType;

        public ConnectThread(BluetoothDevice device, boolean secure){
            mmDevice = device;
            BluetoothSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";
            try {
                if (secure){
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
                }else {
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
            }
            mmSocket = tmp;
        }

        @Override
        public void run() {
            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
            setName("ConnectThred"+mSocketType);

            // 总是取消发现,因为它会减慢连接
            bluetoothAdapter.cancelDiscovery();
            // connect
            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                mmSocket.connect();
                Log.d(TAG, "run: socket连接成功");
            } catch (IOException e) {
                // Close the socket
                Log.d(TAG, "run: 关闭socket");
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() " + mSocketType +
                            " socket during connection failure", e2);
                }

                return;
            }

            connected(mmSocket,mmDevice,mSocketType);
        }

        public void cancel(){
            try{
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
            }
        }

    }

发送数据

连接成功后,我们就可以通过socket发送数据了,客户端的Socket对象是BluetoothSocket, 服务端的socket是BluetoothServerSocket,特别注意不要混淆了。使用getInputStreamgetOutputStream分别获取通过套接字处理数据传输的InputStreamOutputStream。写数据比较简单,但是读数据就需要一个单独的线程一直监听才行。

private class ConnectedThread extends Thread{
        private final BluetoothSocket mmSocket;
        private InputStream mmInStream;
        private OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket, String socketType) throws IOException {
            Log.d(TAG, "create ConnectedThread: " + socketType);
            mmSocket = socket;

            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try{
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();

                if (socket != null){
                    tmpOut.write(new String("hello").getBytes());
                    Log.d(TAG, "ConnectedThread: socket不是null");
                }
            } catch (IOException e) {
                Log.e(TAG,"temp socket not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;

            // mmOutStream.write(new String("hello").getBytes());
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            while (true){
                try{
                    bytes = mmInStream.read(buffer);
                    // send the bytes to the ui Activity
                    String text = encodeByteToString(buffer,bytes);
                    Log.d(TAG, "run: 收到消息:"+ text);
                    chatItems.add(text);
                    mHandler.sendMessage(mHandler.obtainMessage());
                } catch (IOException e) {
                    Log.d(TAG, "run: 没有收到消息");
                    e.printStackTrace();
                    break;
                }
            }
        }

        public String encodeByteToString(byte[] data,int length) {
            byte[] temp = new byte[length];
            for (int i = 0; i < length; i++) {
                temp[i] = data[i];
            }
            try {
                return new String(temp,"utf-8");
            } catch (UnsupportedEncodingException e) {
                return "";
            }
        }


        public void write(byte[] buffer){
            try{
                mmOutStream.write(buffer);

                // mHandler.obtainMessage(Constants.MESSAGE_WRITE,-1,-1,buffer).sendToTarget();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void cancel(){
            try{
                mmSocket.close();
                Log.d(TAG, "cancel: connectedThread");
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }

“android蓝牙简单开发的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI