经典蓝牙通信代码篇

好记性不如烂笔头,既然不够聪明,就乖乖的做笔记,温故而知新。公司一代产品用的经典蓝牙通信,特点就是基于socket连接,传输速率快,缺点就是,额,,,耗电!虽然已经被取代了?,但还是记录一下经典蓝牙通信基本原理缅怀一下吧。

好了,全军出击!

蓝牙权限

蓝牙权限不属于危险权限,所以写在清单文件即可,Android6.0不需要动态申请。但是搜索周边蓝牙设备是需要定位权限的,而且要求gps打开。

  允许程序连接到已配对的蓝牙设备。

允许程序发现和配对蓝牙设备



初始化蓝牙

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

 if (null == mBluetoothAdapter) {
Toast.makeText(this.getApplicationContext(), R.string.not_support_bluetooth, Toast.LENGTH_SHORT).show();
  return;
 }

开启蓝牙

 if(!mBluetoothAdapter.isEnabled()){
            Toast.makeText(MainActivity.this, getString(R.string.open_bluetooth), 2000).show();
            return;
        }

或者            

 mBluetoothAdapter.enable()

搜索蓝牙

mBluetoothAdapter.startDiscovery();

 //TODO:搜索蓝牙之前需要判断定位权限和GPS开关 MIUI权限需要定制处理

if (PermissionUtil.getInstance().checkGPSPermission(MainActivity.this)) {
    if (!AppUtil.isGpsOPen(MainActivity.this) && PermissionUtil.getInstance().isOverMarshmallow()) {
        permissionDialog = new PermissionDialog(MainActivity.this, R.style.Dialog);
        permissionDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                permissionDialog.setTvContent(getResources().getString(R.string.forbid_tip_gps_open));
                permissionDialog.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //跳转GPS设置界面
                        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        startActivityForResult(intent, GPS_OPEN_CODE);
                    }
                });
            }
        });
        permissionDialog.show();
        return;
    }
}

停止搜索

mBluetoothAdapter.cancelDiscovery();

//BluetoothAdapter.ACTION_DISCOVERY_FINISHED会回调


注册广播 

IntentFilter filter = new IntentFilter();
//发现设备
filter.addAction(BluetoothDevice.ACTION_FOUND);
//设备连接状态改变
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//蓝牙设备状态改变
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

//扫描结束

filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHEDD);

registerReceiver(mBluetoothReceiver, filter);

接收广播

//接受蓝牙状态信息并更新界面
    private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case BluetoothDevice.ACTION_FOUND:
                    // TODO: 2017/11/3 需要请求位置权限才能弹对话框  在这里找到指定public address的蓝牙设备进行连接哦!
                    BluetoothDevice device1 = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    LogUtil.e(TAG, "address is " + device1.getAddress() + "\tname is " + device1.getName());
                  


                    break;
                case BluetoothDevice.ACTION_BOND_STATE_CHANGED: {
                    BluetoothDevice device = intent
                            .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    switch (device.getBondState()) {
                        case BluetoothDevice.BOND_BONDING:
                            LogUtil.i(TAG, "正在与" + device.getName() + "__" + device.getAddress() + "配对");
                            break;
                        case BluetoothDevice.BOND_BONDED:
                            LogUtil.i(TAG, "与" + device.getName() + "__" + device.getAddress() + "完成配对");
                            HideDialog();
                            break;
                        case BluetoothDevice.BOND_NONE:
                            LogUtil.i(TAG, "取消与" + device.getName() + "__" + device.getAddress() + "配对");
                        default:
                            break;
                    }
                    break;
                }
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                    LogUtil.e(TAG, "扫描完成!!!");
                    if (!mFound) {
      CToast.makeText(MainActivity.this, getString(R.string.please_set_bt_visiable), CToast.LIGHT_WHITE).show();   
                    }
                    break;
            }
        }
    };


前期的准备工作已经完成,来张美图消遣一下♨️

经典蓝牙通信代码篇_第1张图片

    


    其实我还是觉得白衬衫有点长,哈哈。收起淫荡的笑容,咱们继续

   设置蓝牙可见

   只有设置当前蓝牙可见才能被其他设备搜索到,设置蓝牙可见也能提高部分机型配对对话框弹出概率。

if (mBluetoothAdapter.isEnabled()) {
if (mBluetoothAdapter.getScanMode() != 
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
startActivity(discoverableIntent);
}
}

客户端

经典蓝牙通信有客户端和服务端的概念,一般情况下手机作为客户端,手表或其他设备作为服务端。客户端创建一个BluetoothSocket去连接服务端的 BluetoothServerSocket.
创建BluetoothSocket有两种方式:createRfcommSocketToServiceRecord和createInsecureRfcommSocketToServiceRecord。前者比较安全,需要配对才能连接,后者可不配对,但是不安全。
这里采用前者创建BluetoothSocket。
Log.e(TAG, "sendMessage: 1");
if (null == mBluetoothDevice) {
    mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
}
Log.e(TAG, "sendMessage: 2");

if (mBluetoothSocket == null) {
    mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
    mBluetoothSocket.connect();
    mOutputStream = mBluetoothSocket.getOutputStream();
}



服务端

private final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");//uuid 相当于端口号
    private final String NAME = "bluetooth_socket";//serverSocket name



 private class AcceptThread extends Thread {
        private BluetoothServerSocket mBluetoothServerSocket;
        private BluetoothSocket bluetoothSocket;
        private InputStream is;
        private OutputStream os;
        private boolean isContinue;

        AcceptThread() {
            try {
                mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            while (true) {
                try {
                    if (mBluetoothServerSocket == null) {
                        return;
                    }
                    bluetoothSocket = mBluetoothServerSocket.accept();
                    Log.e(TAG, "run: accept");
                    is = bluetoothSocket.getInputStream();
                    os = bluetoothSocket.getOutputStream();
                    isContinue = true;
                    while (isContinue) {
                        byte[] buffer = new byte[128];
                        int count = is.read(buffer);
                        Message message = new Message();
                        message.obj = new String(buffer, 0, count, "utf-8");
                        mHandler.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    isContinue = false;
                } finally {
                    try {
                        if (bluetoothSocket != null) {
                            bluetoothSocket.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }
数据传输:

/**
     * 发送信息到另一个蓝牙设备
     *
     * @param address 蓝牙设备地址
     * @param message 信息
     */
    private void sendMessage(String address, String message) {
        try {
            if (mBluetoothAdapter.isDiscovering()) {
                mBluetoothAdapter.cancelDiscovery();
            }
            Log.e(TAG, "sendMessage: 1");
            if (null == mBluetoothDevice) {
                mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
            }
            Log.e(TAG, "sendMessage: 2");

            if (mBluetoothSocket == null) {
                mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID);
                mBluetoothSocket.connect();
                mOutputStream = mBluetoothSocket.getOutputStream();
            }
            Log.e(TAG, "sendMessage: 3");

            if (!mBluetoothSocket.isConnected()) {
                resetSocket();
            }
            Log.e(TAG, "sendMessage: 4");

            if (mOutputStream != null) {
                try {
                    mOutputStream.write((message.getBytes("utf-8")));
                    Log.e(TAG, "onItemClick: " + mBluetoothAdapter.getName() + ":" + message);
                } catch (Exception e) {
	e.printStackTrace;               
  }
} } catch (Exception e) { e.printStackTrace(); } }


服务端和客户端都要起一个线程去监听mBluetoothSocket.getInputStream()。捕捉到异常则连接失败。示范代码如下:

@Override
    public void run() {
        int dataType;
        int requestType;
        Utils.log(TAG, "start receive the message ---client >>>>>>>");
        while (!mClosed) {
            try {
                dataType = mInput.read();
                requestType = mInput.read();
                Utils.log(TAG,"dataType = " + dataType + ", requestType ="+requestType);
                switch (requestType) {
                case WearableControlHelper.WCS_OPCODE_CONNECT:
                    //handleConnectRequest();
                    break;
                case WearableControlHelper.WCS_OPCODE_DISCONNECT:
                    //handleDisconnectRequest();
                    break;
                case WearableControlHelper.WCS_OPCODE_SEND:
                case WearableControlHelper.WCS_OPCODE_SEND_FINAL:
                   //if (payload != null) {
                     handleSendRequest(requestType, dataType);
                   // }
                    break;
                case WearableControlHelper.WCS_OPCODE_GET:
                case WearableControlHelper.WCS_OPCODE_GET_FINAL:
                    //handleGetRequest(requestType);
                    break;
                default:
                    break;
                }
            } catch (IOException e) {
                Utils.log(TAG, "receive message error: " + e);
                mClosed = true;
                Message msg = Message.obtain(mCallBack, BluetoothWcsTransfer.MSG_RFCOMM_ERROR);//FIXME !!! disconnected
                msg.sendToTarget();
                return;
            }
        }


最最最简陋的DEMO



你可能感兴趣的:(simon)