android 经典传统蓝牙开发 (附示例源码)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28334473/article/details/86626434

        最近在开发蓝牙,由于是使用的模块开发,但是andriod的系统的经典蓝牙也需要熟悉和知道。在这个背景下,参考了网络上的一些资料,完善了demo,方便了后来者能初步运用相关的蓝牙。站在巨人的肩旁上,才能走的更远。

一、整体思路和对应相关方法

1、获得BluetoothAdapter:BluetoothAdapter.getDefaultAdapter();

2、打开蓝牙:询问用户打开(推荐)或直接bluetoothAdapter.enable();

3、查询已绑定设备,发现新设备:bluetoothAdapter.getBondedDevices();bluetoothAdapter.startDiscovery();

4、配对相关的设备,自定配对相关的类,配对设置pin值配对蓝牙设备。 ClsUtils.createBond(btDevice.getClass(), btDevice);

5.1、服务端,一直监听请求,当该端主动发出请求时,关闭该端的监听,角色转为客户端:

bluetoothDevice.createRfcommSocketToServiceRecord(UUID);


45.2、客户端,点击目标设备,配对连接:

bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID);

6、通过BluetoothSocket通信:IO流读写

二、开发详解

1、声明权限,注意可能需要的运行时权限

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


android 6.0以上设备发现新蓝牙时,需加入运行时权限,否则无法监听ACTION_FOUND广播

        if (Build.VERSION.SDK_INT >= 6.0) {
            ActivityCompat.requestPermissions(getActivity(), 
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                             Params.MY_PERMISSION_REQUEST_CONSTANT);
        }
 
        public void onRequestPermissionsResult(int requestCode, String permissions[],
                                               int[] grantResults) {
           switch (requestCode) {
              case Params.MY_PERMISSION_REQUEST_CONSTANT: {
                  if (grantResults.length > 0 
                          && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                       // 运行时权限已授权
                   }
                  return;
               }
           }
        }


2、打开蓝牙,推荐用对话框形式让用户打开

       bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
       // 蓝牙未打开,询问打开
       if (!bluetoothAdapter.isEnabled()) {
            Intent turnOnBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(turnOnBtIntent, Params.REQUEST_ENABLE_BT);
        }
 
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case Params.REQUEST_ENABLE_BT: {
                    //用户打开蓝牙
                    if (resultCode == RESULT_OK) {
                        //显示已绑定蓝牙设备
                        showBondDevice();
                    }
                    break;
                }
                case Params.REQUEST_ENABLE_VISIBILITY: {
                    //设置该蓝牙设备可被其他设备发现,600是设置的设备可发现时间(博客最后有简单说明)
                    if (resultCode == 600) {
                        toast("蓝牙已设置可见");
                    } else if (resultCode == RESULT_CANCELED) {
                        toast("蓝牙设置可见失败,请重试");
                    }
                    break;
                }
            }
        }


3、通过BluetoothAdapter获取已绑定的蓝牙设备

        private void showBondDevice() {
            deviceList.clear();
            // 所有已绑定设备,一个Set集合
            Set<BluetoothDevice> tmp = bluetoothAdapter.getBondedDevices();
            for (BluetoothDevice d : tmp) {
                deviceList.add(d);
            }
            //更新列表
            listAdapter.notifyDataSetChanged();
        }


4、发现蓝牙设备,发现一个设备,会发送一条ACTION_FOUND广播,注册广播接收器,可获得对应蓝牙设备信息。接收者添加PAIRING_REQUEST的广播接收,从而可以处理相关的配对情况。
   

private class MyBtReceiver extends BroadcastReceiver {
    MakePariBlueToothListener mMakePariListener;

    public void SetPairlistener(MakePariBlueToothListener makePariBlueToothListener) {
        this.mMakePariListener = makePariBlueToothListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice btDevice = null;  //创建一个蓝牙device对象
        // 从Intent中获取设备对象
        btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

        if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
            mtoast.toast("开始搜索 ...");
        } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
            mtoast.toast("搜索结束");
        } else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (isNewDevice(device)) {
                deviceList.add(device);
                listAdapter.notifyDataSetChanged();
                Log.e(TAG, "---------------- " + device.getName());
            }
        } else if (ACTIONFILTER.equals(action)) {
            Log.e("action2=", action);
            Log.e("here", "btDevice.getName()");
            try {
                //1.确认配对
                ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
                //2.终止有序广播
                Log.i("order...", "isOrderedBroadcast:" + isOrderedBroadcast() + ",isInitialStickyBroadcast:" + isInitialStickyBroadcast());
                abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
                //3.调用setPin方法进行配对...
                boolean ret = ClsUtils.setPin(btDevice.getClass(), btDevice, pin);

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {

            switch (btDevice.getBondState()) {
                case BluetoothDevice.BOND_BONDING:// 正在配对
                    mMakePariListener.whilePari(btDevice);
                    break;
                case BluetoothDevice.BOND_BONDED:// 配对结束
                    mMakePariListener.pairingSuccess(btDevice);
                    break;
                case BluetoothDevice.BOND_NONE:// 取消配对/未配对
                    mMakePariListener.cancelPari(btDevice);
                default:
                    break;
            }
        }
    }
}


5、设备连接,服务器端开启线程一直等待连接,客户端点击某个目标设备,关闭服务器线程监听,并开启线程,发出连接请求。 

注意:客户端连接前,一定cancelDiscovery()


        // 蓝牙已开启
        if (bluetoothAdapter.isEnabled()) {
            showBondDevice();
            // 默认开启服务线程监听
            if (serverThread != null) {
                serverThread.cancel();
            }
            serverThread = new ServerThread(bluetoothAdapter, uiHandler);
            new Thread(serverThread).start();
        }
 
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, 
                                    int position, long id) {
                // 关闭服务器监听
                if (serverThread != null) {
                    serverThread.cancel();
                    serverThread=null;
                }
                BluetoothDevice device = deviceList.get(position);
                // 开启客户端线程,连接点击的远程设备
                clientThread = new ClientThread(bluetoothAdapter, device, uiHandler);
                new Thread(clientThread).start();
 
                // 通知 ui 连接的服务器端设备
                Message message = new Message();
                message.what = Params.MSG_CONNECT_TO_SERVER;
                message.obj = device;
                uiHandler.sendMessage(message);
            }
        });


6、建立BluetoothSocket连接以后,使用IO流数据传输,服务器和客户端读写数据类似,贴一部分代码供参考


        public void writeData(String dataSend) {
            if (serverThread != null) {
                serverThread.write(dataSend);
            } else if (clientThread != null) {
                clientThread.write(dataSend);
            }
        }
        //写数据
        public void write(String data){
            try {
                out.write(data.getBytes("utf-8"));            
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        new Thread(new Runnable() {
                @Override
                public void run() {
                    byte[] buffer = new byte[1024];
                    int len;
                    String content;
                    try {
                        //读数据
                        while ((len=in.read(buffer)) != -1) {
                            content=new String(buffer, 0, len);
                            Message message = new Message();
                            message.what = Params.MSG_CLIENT_REV_NEW;
                            message.obj = content;
                            //更新 ui
                            uiHandler.sendMessage(message);
                        }
 
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();


7、其他说明
(1)新设备绑定,也可以使用bluetoothDevice.createBond()

(2)设置设备可被发现的时间:

Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
enableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);  
startActivityForResult(enableIntent, Params.REQUEST_ENABLE_VISIBILITY); 


(3)服务器获得远端设备,bluetoothSocket.getRemoteDevice() 

(4)通过MAC获得蓝牙设备,bluetoothAdapter.getRemoteDevice(String address) 

(5)关闭蓝牙,bluetoothAdapter.disable()()

(6)使用相关的连接结果Toast提示。

(7)使用了Rxbinding的防止重复点击。

三、源码示例下载

相关Demo 下载地址:https://github.com/tangrunfa/BluetoothStudy

四、效果图


本文在原文上修改,原文地址:https://blog.csdn.net/qiao_jim/article/details/73008695 

猜你喜欢

转载自blog.csdn.net/qq_28334473/article/details/86626434