Android实现和下位机蓝牙通讯

采得百花成蜜后,为谁辛苦为谁甜。这篇文章主要讲述Android实现和下位机蓝牙通讯相关的知识,希望能为你提供帮助。
1.在程序配置文件中声明蓝牙权限。

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

2.新建通用的扫描选择蓝牙设备的布局和活动。
activity_bt.xml
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> < Button android:id="@+id/btnQueryBt" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="直接进入软件" android:layout_marginTop="16dp"/> < Button android:id="@+id/btnSearchBt" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="扫描蓝牙设备" android:layout_marginTop="16dp"/> < TextView android:id="@+id/txtConnectState" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp"/> < ListView android:id="@+id/lstBtName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp"> < /ListView> < /LinearLayout>

BtActivity.java
public class BtActivity extends BaseActivity { private Button btnSearchBt; //初始界面的扫描按钮 private Button btnIntoQuery; //初始界面的进入查询按钮 private TextView txtConnectState; private ListView lstBtName; private BtOperation btOperation = new BtOperation(); private BluetoothReceiver mBluetoothReceiver = new BluetoothReceiver(); ArrayList< String> btNameList = new ArrayList< > (); @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_bt); //checkBtUnable(); //initButton(); }@Override protected void onDestroy() { super.onDestroy(); //unregisterReceiver(mBluetoothReceiver); }class BluetoothReceiver extends 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); btNameList.add(device.getName()); btNameList.add(device.getAddress()); //如果设备还没绑定,则将设备显示到列表中,并提醒用户配对 if(device.getBondState()!=BluetoothDevice.BOND_BONDED){ArrayAdapter< String> adapter = new ArrayAdapter< String> ( BtActivity.this,android.R.layout.simple_list_item_1,btNameList); lstBtName.setAdapter(adapter); txtConnectState.setText("选择设备进行配对"); } //如果设备已经配对,直接显示在列表中,然后直接跳转到主界面 else { ArrayAdapter< String> adapter = new ArrayAdapter< String> ( BtActivity.this,android.R.layout.simple_list_item_1,btNameList); lstBtName.setAdapter(adapter); txtConnectState.setText("配对成功"); //RunActivity.actionStart(BtActivity.this,device.getAddress()); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { txtConnectState.setText("蓝牙设备搜索完毕"); } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { txtConnectState.setText("正在扫描蓝牙设备"); } else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if(device.getBondState()== BluetoothDevice.BOND_BONDING){ txtConnectState.setText("正在配对中"); }else if(device.getBondState() == BluetoothDevice.BOND_BONDED){ txtConnectState.setText("配对成功"); //RunActivity.actionStart(BtActivity.this,device.getAddress()); } } } } /** * 检查用户设备是否支持蓝牙,如果不支持,就退出程序,并提示用户。如果支持,直接打开蓝牙。 */ private void checkBtUnable(){if(!btOperation.checkBt()){ Toast.makeText(this,"你的设备不支持蓝牙!请更换设备!",Toast.LENGTH_LONG).show(); //finish(); } }/** * 初始化启动界面的两个按钮 */ private void initButton(){ txtConnectState = (TextView)findViewById(R.id.txtConnectState); //蓝牙设备清单,点击特定名称,可以连接设备 lstBtName = (ListView)findViewById(R.id.lstBtName); lstBtName.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView< ?> adapterView, View view, int i, long l) { if(btNameList.get(i).equals("HC-05")){ btOperation.devBond(btNameList.get(i+1)); } } }); //蓝牙操作按钮 btnSearchBt = (Button)findViewById(R.id.btnSearchBt); btnSearchBt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { btOperation.openBt(); } }); btnIntoQuery = (Button)findViewById(R.id.btnQueryBt); //进入查询数据界面 btnIntoQuery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Intent intent = new Intent(BtActivity.this,QueryActivity.class); //startActivity(intent); } }); btOperation.registerBtReceiver(this,mBluetoothReceiver); //初始化最后直接打开蓝牙,如果之前绑定过蓝牙,会直接进入,否则需要点击扫描按钮来打开蓝牙 btOperation.openBt(); }}

设备配对后,还需要开启后台蓝牙消息服务
SerialBtService.java
/** * 的到一个远程设备地址后,和地址建立连接,建立输入输出流, * < p> 提供发送蓝牙信息的封装< /p> * < p> 将接收的蓝牙信息拆包并用内部广播发送出去< /p> */ public class SerialBtService extends Service { private static final UUID SerialBlueToothDev_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private String devAddr = null; private OutputStream mOutputStream=null; private InputStream mInputStream=null; private BluetoothAdapter mBluetoothAdapter=null; private BluetoothSocket mBluetoothSocket=null; private boolean mFlag=true; private int[] dataRec = new int[100]; private int couts = 0; /** * 启动蓝牙传输服务类所需要的蓝牙设备地址 */ public static final String DEV_ADDR = "devAddr"; /** * 向外发送蓝牙信息的广播Intent中,信息的标识符 */ public static final String BT_SEND_MESS = "BT_CMD"; /** * 从外部接收的蓝牙信息的广播Intent中,信息的标识符 * < p> 表示一个拆包的信息已经发送了,需要的模块可以接收< /p> */ public static final String BT_RECEIVE_MESS = "BT_DATA"; /** * 向外发送蓝牙信息时的注册广播标识符 */ public static final String BT_SEND_BROADCAST = "com.jiaweiqiang.tools.SEND_MSG"; /** * 接收外部蓝牙信息时的注册广播标识符 */ public static final StringBT_RECEIVE_BROADCAST = "com.jiaweiqiang.fycdy.RECEIVE_MSG"; public SerialBtService() { } //接收其他活动传来的要发送的蓝牙信息的广播接收器 private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //String btMessage = intent.getStringExtra(BT_SEND_MESS); int[] btMessage = intent.getIntArrayExtra(BT_SEND_MESS); if(btMessage==null||btMessage.equals("")){ Toast.makeText(MyApplication.getContext(),"无效输入",Toast.LENGTH_SHORT).show(); }else { writeSingleData(btMessage); }} }; @Override public void onDestroy() { super.onDestroy(); try{ mBluetoothSocket.close(); }catch (IOException e){ e.printStackTrace(); } MyApplication.getLocalBroadcastManager().unregisterReceiver(mReceiver); }/** * 启动本服务的启动函数 * @param context 启动服务的上下位 * @param devAddr 蓝牙设备的mac地址 */ public static void startService(Context context,String devAddr){ Intent intent = new Intent(MyApplication.getContext(),SerialBtService.class); intent.putExtra(DEV_ADDR,devAddr); context.startService(intent); } public static void stopService(Context context){ Intent intent = new Intent(context,SerialBtService.class); context.stopService(intent); }/** * 通过服务发送蓝牙数据 * @param mess 要发送的字符串数据 */ public static void sendStringMess(String mess){ int[] data = https://www.songbingjia.com/android/Convert.stringToIntArray(mess); sendIntArrayMess(data,data.length); }/** * 发送byte数组出去,将每个byte的值存入int数组中,将字节数组发送出去 * @param mess 要发送的字节数组 * @param lenth 发送字节的长度 */ public static void sendIntArrayMess(int[] mess, int lenth){ int[] copyMess = new int[lenth]; System.arraycopy(mess,0,copyMess,0,lenth); Intent intent = new Intent(BT_SEND_BROADCAST); intent.putExtra(SerialBtService.BT_SEND_MESS,copyMess); MyApplication.getLocalBroadcastManager().sendBroadcast(intent); }@Override public int onStartCommand(Intent intent, int flags, int startId) { devAddr = intent.getStringExtra(DEV_ADDR); //通过建立Service,Intent传入蓝牙地址 //声明并注册发送蓝牙信息的广播接收器,以便接收到广播后,将信息发送出去 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BT_SEND_BROADCAST); MyApplication.getLocalBroadcastManager().registerReceiver(mReceiver,intentFilter); mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter(); //为接收蓝牙信息单独开启一个线程 SerialBtThread thread = new SerialBtThread(); thread.start(); //Toast.makeText(MyApplication.getContext(),"服务已经启动",Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); }@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); }/** * 向外发送蓝牙信息,这是以string的形式发送的 * @param msg 要发送的信息 */ private void writeSerialBt(String msg){ try{ mOutputStream.write(msg.getBytes()); mOutputStream.flush(); }catch (IOException e){ e.printStackTrace(); } }/** * 传入int数组,以单个字节形式循环把数组发送出去 * @param msg */ private void writeSingleData(int[] msg){ try{ for (int i= 0; i< msg.length; i++){ mOutputStream.write(msg[i]); } mOutputStream.flush(); }catch (IOException e){ e.printStackTrace(); } }private class SerialBtThread extends Thread{ @Override public void run() { super.run(); //在线程中初始化蓝牙设备,和socket try{ BluetoothDevice device=mBluetoothAdapter.getRemoteDevice(devAddr); mBluetoothSocket=device.createRfcommSocketToServiceRecord(SerialBlueToothDev_UUID); }catch (Exception e){ e.printStackTrace(); mFlag=false; }mBluetoothAdapter.cancelDiscovery(); //连接远程设备,建立socket try{ mBluetoothSocket.connect(); }catch (IOException e){ e.printStackTrace(); try{ mBluetoothSocket.close(); mFlag=false; }catch (IOException e1){ e1.printStackTrace(); } } //如果建立过程没有异常,则得到输入流和输出流 if(mFlag){ try { mInputStream=mBluetoothSocket.getInputStream(); mOutputStream=mBluetoothSocket.getOutputStream(); }catch (IOException e){ e.printStackTrace(); } } //开启循环接收蓝牙信息,间隔30ms while(true){ readSerialBlueTooth(); try { Thread.sleep(30); }catch (Exception e){ e.printStackTrace(); } } } }/** * 在线程中读取蓝牙数据 */ private void readSerialBlueTooth() { int ret=0; int data; try { ret=mInputStream.available(); for(int i=0; i< ret; i++){ data = https://www.songbingjia.com/android/mInputStream.read(); readPackage(data); } }catch (IOException e){ e.printStackTrace(); } }/** * 接收单个的byte数据,不断添加到数组中,不断判断是否数据包已经完成 * 进行拆包,把拆包后的信息发送出去 * @param n */ private void readPackage(int n){dataRec[couts] = n; couts++; if(couts > = 4){ if(dataRec[couts-1] == 0x3c){ if(dataRec[couts-2] == 0xc3){ Log.d("btTest", "readPackage: 收到包"); int[] copyDataRec = new int[couts-3]; //将数据包拆包,并取得包内数据,复制到新的数组中 System.arraycopy(dataRec,1,copyDataRec,0,couts-3); couts = 0; //将包内数据通过蓝牙发送出去 Intent intent = new Intent(BT_RECEIVE_BROADCAST); intent.putExtra(BT_RECEIVE_MESS,copyDataRec); Log.d("btTest", "readPackage: 把数组放入intent"); MyApplication.getLocalBroadcastManager().sendBroadcast(intent); } } }} }

别忘了在程序配置文件中注册活动和服务
< activity android:name=".BtActivity" android:launchMode="singleInstance"> < /activity> < service android:name="com.jiaweiqiang.tools.SerialBtService" />

【Android实现和下位机蓝牙通讯】 

    推荐阅读