Android 蓝牙通信及自定义消息协议的解析和生成

Socket通信几本协议:



首先解释下为什么Socket通信需要一定的协议才能理解消息的内容

1. 安全性, 协议中有判断内容安全的字段(比如报文的长度), 这样可以进行验证,如果被网络连接和篡改,这样的消息就是不安全的,不予处理

2. Socket通信, 消息达到一定的长度会分多次接收, 用协议的方式可以可以解决报文被截断的问题

3. 其他可能的原因


另外Socket在客户端一般用阻塞模式, 在服务器主动关闭时, 客户端会读取到-1长度的值, 此时会主动抛出异常

Socket服务器用的非阻塞模式


消息协议的封装方法:

public class ProtocolUtil {

    public static String bluetoothString(String content) {
        String data = null;
        String msgtype = "C";
        data = String.format("%06x", calculatePlaces(msgtype));
        data += msgtype;
        data += String.format("%06x", calculatePlaces(content));
        data += content;

        data = String.format("%06x", calculatePlaces(data) + 1) + data;
        return data;
    }

    public static int calculatePlaces(String str) {
        int m = 0;
        char arr[] = str.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            char c = arr[i];
            //中文字符
            if ((c >= 0x0391 && c <= 0xFFE5)) {
                m = m + 3;
            } else if ((c >= 0x0000 && c <= 0x00FF)) { //英文字符
                m = m + 1;
            }
        }
        return m;
    }

}
 
消息协议的解析方法:
// 接收完后
String message = new String(bytes, "UTF-8");

// 消息总长度
int length = Integer.parseInt(message.substring(0, 6), 16);


// 消息类型

int typelen = Integer.parseInt( message.substring(6, 12), 16 );

String type = message.substring(12, 12 + typelen);
			

// 消息内容

int datalen = Integer.parseInt( message.substring(12 + typelen, 12 + typelen + 6), 16 );

String data = message.substring(18+typelen, message.length());
 

蓝牙通信步骤:

private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

// 开始搜索
private void startDiscovery() {

    if (mBluetoothAdapter.isDiscovering()) {
        mBluetoothAdapter.cancelDiscovery();
    } else {
	// ListView适配器
        mBluetoothDeviceAdapter.clear();

        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

        if (pairedDevices != null && pairedDevices.size() > 0) {

            for (BluetoothDevice device : pairedDevices) {
                BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(device.getName() + "\n" + device.getAddress(), true);
                mBluetoothDeviceAdapter.addDevice(deviceInfo);
            }
        } else {
            BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo("No devices have been paired.", true);
            mBluetoothDeviceAdapter.addDevice(deviceInfo);
        }

        mBluetoothAdapter.startDiscovery();
    }

}

private final UUID socketUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothServerSocket mServerSocket;
private BluetoothSocket mSocket;

private ReceiveThread receiveThread;

private ServerThread serverThread;
private ClientThread clientThread;

private void startConnect(String address, boolean isServer) {

    if (isServer) {

        shutdownServer();
        serverThread = new ServerThread();
        serverThread.start();
    } else {

        shutdownClient();
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        clientThread = new ClientThread(device);
        clientThread.start();
    }
}

// 停止服务器
private void shutdownServer() {

    if (serverThread != null) {
        serverThread.interrupt();
        serverThread = null;
    }

    if (receiveThread != null) {
        receiveThread.interrupt();
        receiveThread = null;
    }

    if (mSocket != null) {
        try {
            mSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mSocket = null;
    }

    if (mServerSocket != null) {
        try {
            mServerSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mServerSocket = null;
    }
}

// 停止客户端
private void shutdownClient() {

    // btExternalOpera.setText("等待连接");
    if (clientThread != null) {
        clientThread.interrupt();
        clientThread = null;
    }

    if (receiveThread != null) {
        receiveThread.interrupt();
        receiveThread = null;
    }

    if (mSocket != null) {
        try {
            mSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mSocket = null;
    }
}

// 停止接收消息
    private void stopReceive() {
        if (receiveThread != null) {
            receiveThread.interrupt();
            receiveThread = null;
        }
    }

    // 开始接收消息
    private void startReceive() {
        stopReceive();
        receiveThread = new ReceiveThread();
        receiveThread.start();
    }

    private class ServerThread extends Thread {

        @Override
        public void run() {

            try {
                mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM, socketUUID);

                mSocket = mServerSocket.accept();

                startReceive();
            } catch (Exception e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(ActivityDeviceControl.this, "未知异常!", Toast.LENGTH_SHORT).show();
                    }
                });
            }

        }
    }

    // 启动客户端线程+读取消息
    private class ClientThread extends Thread {

        private BluetoothDevice device;

        public ClientThread(BluetoothDevice device) {
            this.device = device;
        }

        @Override
        public void run() {

            InputStream readInput = null;
            try {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_connect_status.setText("连接中...");
                    }
                });

                mSocket = this.device.createInsecureRfcommSocketToServiceRecord(socketUUID);
                mSocket.connect();// 无异常表示连接成功

                receiveThread = new ReceiveThread();
                receiveThread.start();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        statusCategory = STATUS_CATEGORY_BLUETOOTH;
                        resetStatus(statusCategory);
                        tv_connect_status.setText("已连接(" + device.getName() + ")!");
                        Prefs.putBluetoothAddress(ActivityDeviceControl.this, device.getAddress());
                        Toast.makeText(ActivityDeviceControl.this, "已连接到蓝牙!", Toast.LENGTH_SHORT).show();
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        statusCategory = STATUS_CATEGORY_NET;
                        resetStatus(statusCategory);
                        tv_connect_status.setText("连接已断开!");
                        Toast.makeText(ActivityDeviceControl.this, "连接失败!", Toast.LENGTH_SHORT).show();
                    }
                });
            } finally {
                if (readInput != null) {
                    try {
                        readInput.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }



    private class ReceiveThread extends Thread {

        @Override
        public void run() {

            InputStream readInput = null;
            try {

                // 限制在500字以内
                byte[] buffer = new byte[1024];
                int bytes;// 读取到的字节数
                readInput = mSocket.getInputStream();
                while (true) {
                    if ((bytes = readInput.read(buffer)) > 0) {
                        final String str = new String(buffer, 0, bytes);
                        CLog.i(TAG, "receive:" + str);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {// 可能是服务器主动断开
                if (readInput != null) {
                    try {
                        readInput.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                shutdownClient();
            }
        }
    }

    // The BroadcastReceiver that listens for discovered devices and
    // changes the title when discovery is finished
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // If it's already paired, skip it, because it's been listed already
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo(device.getName() + "\n" + device.getAddress(), false);
                    mBluetoothDeviceAdapter.addDevice(deviceInfo);
                }
                // When discovery is finished, change the Activity title
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                setProgressBarIndeterminateVisibility(false);
                if (mBluetoothDeviceAdapter.getCount() == 0) {
                    BluetoothDeviceInfo deviceInfo = new BluetoothDeviceInfo("没有发现蓝牙设备", false);
                    mBluetoothDeviceAdapter.addDevice(deviceInfo);
                }
            }
        }
    };
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的 Android 蓝牙通信代码示例: 首先,你需要在你的 AndroidManifest.xml 文件中添加以下权限: ```xml <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> ``` 然后,你需要在你的 Activity 中实现蓝牙通信的逻辑。示例代码如下: ```java import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; public class BluetoothActivity extends AppCompatActivity { // 蓝牙适配器 BluetoothAdapter mBluetoothAdapter; // 蓝牙设备 BluetoothDevice mBluetoothDevice; // 蓝牙套接字 BluetoothSocket mBluetoothSocket; // 输入流 InputStream mInputStream; // 输出流 OutputStream mOutputStream; // 读取的数据 String mReadData; // 读取数据的线程 ReadThread mReadThread; // 服务端 UUID UUID mServerUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); Button mConnectButton; Button mSendButton; EditText mEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth); mConnectButton = findViewById(R.id.connect_button); mSendButton = findViewById(R.id.send_button); mEditText = findViewById(R.id.edit_text); mConnectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 检查是否支持蓝牙 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Log.e("BluetoothActivity", "设备不支持蓝牙"); return; } // 检查蓝牙是否已开启 if (!mBluetoothAdapter.isEnabled()) { Log.e("BluetoothActivity", "蓝牙未开启"); return; } // 获取蓝牙设备 mBluetoothDevice = mBluetoothAdapter.getRemoteDevice("设备的 MAC 地址"); try { // 创建蓝牙套接字 mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(mServerUUID); // 连接蓝牙设备 mBluetoothSocket.connect(); // 获取输入流 mInputStream = mBluetoothSocket.getInputStream(); // 获取输出流 mOutputStream = mBluetoothSocket.getOutputStream(); // 启动读取数据的线程 mReadThread = new ReadThread(); mReadThread.start(); } catch (IOException e) { e.printStackTrace(); } } }); mSendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 发送数据 String sendData = mEditText.getText().toString(); try { mOutputStream.write(sendData.getBytes()); } catch (IOException e) { e.printStackTrace(); } } }); } // 读取数据的线程 class ReadThread extends Thread { @Override public void run() { byte[] buffer = new byte[1024]; int bytes; while (true) { try { // 读取数据 bytes = mInputStream.read(buffer); mReadData = new String(buffer, 0, bytes); // 将读取的数据发送给主线程处理 mHandler.obtainMessage(1, mReadData).sendToTarget(); } catch (IOException e) { e.printStackTrace(); break; } } } } // 处理读取到的数据 Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case 1: // 显示读取到的数据 String readData = (String) msg.obj; Log.d("BluetoothActivity", "读取到的数据:" + readData); break; } return false; } }); } ``` 在上面的代码中,我们使用 BluetoothAdapter 类来获取蓝牙适配器,使用 BluetoothDevice 类来获取蓝牙设备,使用 BluetoothSocket 类来创建和连接蓝牙套接字,使用 InputStream 和 OutputStream 类来读取和发送数据。同时,我们还创建了一个 ReadThread 线程来持续读取蓝牙设备发送过来的数据,并使用 Handler 回调来处理读取到的数据

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值