赞
踩
项目要求实现蓝牙设备搜索连接,Android为蓝牙技术提供了4个工具类,分别是蓝牙适配器BluetoothAdapter、蓝牙设备BluetoothDevice、蓝牙服务端套接字BluetoothServerSocket和蓝牙客户端套接字BluetoothSocket。
蓝牙适配器BluetoothAdapter
BluetoothAdapter的作用其实跟其它的**Manger差不多,可以把它当作蓝牙管理器。下面是BluetoothAdapter的常用方法说明。
getDefaultAdapter:静态方法,获取默认的蓝牙适配器对象;
enable:打开蓝牙功能;
disable:关闭蓝牙功能;
isEnable:判断蓝牙功能是否打开;
startDiscovery:开始搜索周围的蓝牙设备;
cancelDiscovery:取消搜索操作;
isDiscovering:判断当前是否正在搜索设备;
getBondedDevices:获取已绑定的设备列表;
setName:设置本机的蓝牙名称;
getName:获取本机的蓝牙名称;
getAddress:获取本机的蓝牙地址;
getRemoteDevice:根据蓝牙地址获取远程的蓝牙设备;
getState:获取本地蓝牙适配器的状态;
listenUsingRfcommWithServiceRecord:根据名称和UUID创建并返回BluetoothServiceSocket;
listenUsingRfcommOn:根据渠道编号创建并返回BluetoothServiceSocket。
蓝牙设备BluetoothDevice
BluetoothDevice用于指代某个蓝牙设备,通常表示对方设备。BluetoothAdapter管理的是本机蓝牙设备。下面是BluetoothDevice的常用方法说明。
蓝牙服务器套接字BluetoothServiceSocket
BluetoothServiceSocket是服务端的Socket,用来接收客户端的Socket连接请求。下面是常用的方法说明。
accept:监听外部的蓝牙连接请求;
close:关闭服务端的蓝牙监听。
蓝牙客户端套接字BluetoothSocket
BluetoothSocket是客户端的Socket,用于与对方设备进行数据通信。下面是常用的方法说明。
layout\activity_bluetooth.xml界面布局代码如下:界面布局代码如下:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- >
-
- <!--头部-->
- <RelativeLayout
- android:id="@+id/rl_title"
- android:layout_width="match_parent"
- android:layout_height="55dp"
- android:background="@color/color_2570fd"
- >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_name"
- android:textColor="@color/white"
- android:textSize="22sp"
- android:layout_centerVertical="true"
- android:layout_marginLeft="10dp"
- />
-
- </RelativeLayout>
-
- <LinearLayout
- android:id="@+id/ll_switch"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="5dp"
- android:layout_below="@id/rl_title"
- >
-
- <CheckBox
- android:id="@+id/ck_bluetooth"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:button="@null"
- android:checked="false"
- android:drawableLeft="@drawable/ck_status_selector"
- android:text="蓝牙"
- android:textColor="#ff000000"
- android:textSize="17sp" />
-
- <TextView
- android:id="@+id/tv_discovery"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="right|center"
- android:textColor="#ff000000"
- android:textSize="17sp" />
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/ll_text"
- android:layout_width="match_parent"
- android:layout_height="40dp"
- android:orientation="horizontal"
- android:layout_below="@id/ll_switch"
- >
-
- <TextView
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="4"
- android:gravity="center"
- android:text="名称"
- android:textColor="#ff000000"
- android:textSize="17sp" />
-
- <TextView
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="5"
- android:gravity="center"
- android:text="地址"
- android:textColor="#ff000000"
- android:textSize="17sp" />
-
- <TextView
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="2"
- android:gravity="center"
- android:text="状态"
- android:textColor="#ff000000"
- android:textSize="17sp" />
- </LinearLayout>
-
- <ListView
- android:id="@+id/lv_bluetooth"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/ll_text"
- android:layout_above="@+id/ll_bottom"
- android:listSelector="@null"
- />
-
- <LinearLayout
- android:id="@+id/ll_bottom"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:layout_alignParentBottom="true"
- android:orientation="horizontal">
- <Button
- android:id="@+id/bt_search"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- android:text="搜索"
- android:textColor="#ff000000"
- android:textSize="14sp" />
-
- <Button
- android:id="@+id/bt_pair"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- android:text="配对"
- android:textColor="#ff000000"
- android:textSize="14sp" />
-
- <Button
- android:id="@+id/bt_connect"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- android:text="连接"
- android:textColor="#ff000000"
- android:textSize="14sp" />
-
- <Button
- android:id="@+id/bt_cancel"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- android:text="取消配对"
- android:textColor="#ff000000"
- android:textSize="14sp" />
- </LinearLayout>
-
- </RelativeLayout>
BluetoothActivity.java逻辑代码如下:
- package com.example.bluetoothtest;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.UUID;
-
- import android.Manifest;
- import android.bluetooth.BluetoothAdapter;
- import android.bluetooth.BluetoothDevice;
- import android.bluetooth.BluetoothSocket;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.content.pm.PackageManager;
- import android.os.Build;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.AbsListView;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.Button;
- import android.widget.CheckBox;
- import android.widget.CompoundButton;
- import android.widget.ListView;
- import android.widget.CompoundButton.OnCheckedChangeListener;
- import android.widget.TextView;
- import android.widget.Toast;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
- import androidx.core.app.ActivityCompat;
- import androidx.core.content.ContextCompat;
-
- import com.example.bluetoothtest.adapter.BlueListAdapter;
- import com.example.bluetoothtest.bean.BlueDevice;
- import com.example.bluetoothtest.thread.ReadThread;
- import com.example.bluetoothtest.thread.WriteThread;
- import com.example.bluetoothtest.util.CommonUtil;
-
- public class BluetoothActivity extends AppCompatActivity implements
- OnClickListener, OnItemClickListener, OnCheckedChangeListener {
- private static final String TAG = "BluetoothActivity ";
- private CheckBox ck_bluetooth;
- private TextView tv_discovery;
- private ListView lv_bluetooth;
- private Button bt_search;
- private Button bt_pair;
- private Button bt_connect;
- private Button bt_cancel;
- private BluetoothAdapter mBluetooth;
- private ArrayList<BlueDevice> mDeviceList = new ArrayList<BlueDevice>();
- private BlueListAdapter adapter;
- private BluetoothDevice bluetoothDevice;
-
- private BluetoothSocket mBlueSocket;
- private InputStream inputStream;//输入流
- private OutputStream outputStream;//输出流
-
- private WriteThread writeThread;
- private ReadThread readThread;
- private boolean isConnect = false;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_bluetooth);
- bluetoothPermissions();
- ck_bluetooth = findViewById(R.id.ck_bluetooth);
- tv_discovery = findViewById(R.id.tv_discovery);
- lv_bluetooth = findViewById(R.id.lv_bluetooth);
- bt_starmap = findViewById(R.id.bt_starmap);
- bt_location = findViewById(R.id.bt_location);
- bt_search = findViewById(R.id.bt_search);
- bt_pair = findViewById(R.id.bt_pair);
- bt_connect = findViewById(R.id.bt_connect);
- bt_cancel = findViewById(R.id.bt_cancel);
- bt_starmap.setOnClickListener(this);
- bt_location.setOnClickListener(this);
- bt_search.setOnClickListener(this);
- bt_pair.setOnClickListener(this);
- bt_connect.setOnClickListener(this);
- bt_cancel.setOnClickListener(this);
-
- if (CommonUtil.getBlueToothStatus(this) == true) {
- ck_bluetooth.setChecked(true);
- }
- ck_bluetooth.setOnCheckedChangeListener(this);
- mBluetooth = BluetoothAdapter.getDefaultAdapter();
- if (mBluetooth == null) {
- Toast.makeText(this, "本机未找到蓝牙功能", Toast.LENGTH_SHORT).show();
- finish();
- }
- beginDiscovery();
- }
-
- // 定义获取基于地理位置的动态权限
- private void bluetoothPermissions() {
- if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED
- || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED
-
- ) {
- ActivityCompat.requestPermissions(this, new String[]{
- android.Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1);
- }
- }
-
-
- /**
- * 重写onRequestPermissionsResult方法
- * 获取动态权限请求的结果,再开启蓝牙
- */
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- if (CommonUtil.getBlueToothStatus(this) == true) {
- ck_bluetooth.setChecked(true);
- }
- ck_bluetooth.setOnCheckedChangeListener(this);
- mBluetooth = BluetoothAdapter.getDefaultAdapter();
- if (mBluetooth == null) {
- Toast.makeText(this, "本机未找到蓝牙功能", Toast.LENGTH_SHORT).show();
- finish();
- }
- beginDiscovery();
- } else {
- Toast.makeText(this, "用户拒绝了权限", Toast.LENGTH_SHORT).show();
- }
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (buttonView.getId() == R.id.ck_bluetooth) {
- if (isChecked == true) {
- beginDiscovery();
- Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- startActivityForResult(intent, 1);
- } else {
- cancelDiscovery();
- CommonUtil.setBlueToothStatus(this, false);
- mDeviceList.clear();
- adapter.notifyDataSetChanged();
- }
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- if (requestCode == 1) {
- if (resultCode == RESULT_OK) {
- Toast.makeText(this, "允许本地蓝牙被附近的其它蓝牙设备发现", Toast.LENGTH_SHORT).show();
- } else if (resultCode == RESULT_CANCELED) {
- Toast.makeText(this, "不允许蓝牙被附近的其它蓝牙设备发现", Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- private void beginDiscovery() {
- if (mBluetooth.isDiscovering() != true) {
- mDeviceList.clear();
- adapter = new BlueListAdapter(BluetoothActivity.this, mDeviceList);
- lv_bluetooth.setAdapter(adapter);
- lv_bluetooth.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
- tv_discovery.setText("正在搜索蓝牙设备");
- mBluetooth.startDiscovery();
- }
- }
-
- private void cancelDiscovery() {
- // tv_discovery.setText("取消搜索蓝牙设备");
- if (mBluetooth.isDiscovering() == true) {
- mBluetooth.cancelDiscovery();
- }
- }
-
- @Override
- protected void onStart() {
- super.onStart();
-
- blueReceiver = new BluetoothReceiver();
- //需要过滤多个动作,则调用IntentFilter对象的addAction添加新动作
- IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
- foundFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- foundFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- registerReceiver(blueReceiver, foundFilter);
- }
-
- private BluetoothReceiver blueReceiver;
-
- private class BluetoothReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- // Log.d(TAG, "onReceive action=" + action);
- // 获得已经搜索到的蓝牙设备
- if (action.equals(BluetoothDevice.ACTION_FOUND)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- BlueDevice item = new BlueDevice(device.getName(), device.getAddress(), device.getBondState() - 10);
-
- for (int i = 0; i < mDeviceList.size(); i++) {
- if (item.address.equals(mDeviceList.get(i).address)) {
- mDeviceList.remove(i);//去掉重复项
- }
- }
- mDeviceList.add(item);
-
- adapter = new BlueListAdapter(BluetoothActivity.this, mDeviceList);
- lv_bluetooth.setAdapter(adapter);
- lv_bluetooth.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
- lv_bluetooth.setOnItemClickListener(BluetoothActivity.this);
-
- } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
- tv_discovery.setText("蓝牙设备搜索完成");
- } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
- tv_discovery.setText("正在配对" + device.getName());
- } else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
- tv_discovery.setText("完成配对" + device.getName());
- refreshAddress(device.getAddress(), BlueListAdapter.BINDED);
- } else if (device.getBondState() == BluetoothDevice.BOND_NONE) {
- tv_discovery.setText("取消配对" + device.getName());
- }
- }
- }
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- cancelDiscovery();
- BlueDevice item = mDeviceList.get(position);
- bluetoothDevice = mBluetooth.getRemoteDevice(item.address);
- adapter.setSelectedItem(position);
- adapter.notifyDataSetChanged();
- // Toast.makeText(BluetoothActivity.this, "选择" + bluetoothDevice.getAddress(), Toast.LENGTH_SHORT).show();
- }
-
- public void createBond(BluetoothDevice device) {
- Method createBondMethod = null;
- try {
- createBondMethod = BluetoothDevice.class.getMethod("createBond");
- Boolean result = (Boolean) createBondMethod.invoke(device);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void cancelBond(BluetoothDevice device) {
- Method createBondMethod = null;
- try {
- createBondMethod = BluetoothDevice.class.getMethod("removeBond");
- Boolean returnValue = (Boolean) createBondMethod.invoke(device);
-
- tv_discovery.setText("取消配对" + device.getAddress());
- refreshAddress(device.getAddress(), BlueListAdapter.UNBIND);
- isConnect = false;
-
- if (readThread != null) {
- readThread.interrupt();
- readThread = null;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void connetBle(final BluetoothDevice device) {
-
- Log.d(TAG, "---开始连接蓝牙=" + device.getName());
-
- try {
- UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); // bluetooth serial port service
- final BluetoothSocket socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID); //加密传输,Android系统强制配对,弹窗显示配对码
-
- //这里建立蓝牙连接 socket.connect()
- new Thread() {
- @Override
- public void run() {
- try {
- socket.connect();
- inputStream = socket.getInputStream();
- outputStream = socket.getOutputStream();
-
- if (readThread != null) {
- readThread.interrupt();
- readThread = null;
- }
- readThread = new ReadThread(inputStream);
- readThread.start();
-
- writeThread = new WriteThread(outputStream);
- writeThread.start();
- } catch (IOException e) {
- Log.d(TAG, "---connetBle e=" + e.toString());
- }
- }
- }.start();
-
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(BluetoothActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
- onBlueConnect(device.getAddress(), socket);
- }
- });
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- //客户端主动连接
- public void onBlueConnect(String address, BluetoothSocket socket) {
- mBlueSocket = socket;
- tv_discovery.setText("连接成功");
- isConnect = true;
- refreshAddress(address, BlueListAdapter.CONNECTED);
- }
-
- //刷新蓝牙状态
- private void refreshAddress(String address, int state) {
- for (int i = 0; i < mDeviceList.size(); i++) {
- BlueDevice item = mDeviceList.get(i);
- if (item.address.equals(address) == true) {
- item.state = state;
- mDeviceList.set(i, item);
- }
- }
- adapter.notifyDataSetChanged();
- }
-
- @Override
- public void onClick(View v) {
- int id = v.getId();
- switch (id) {
- case R.id.bt_search:
- beginDiscovery();
- break;
- case R.id.bt_pair:
- createBond(bluetoothDevice);
- break;
- case R.id.bt_connect:
- connetBle(bluetoothDevice);
- break;
- case R.id.bt_cancel:
- cancelBond(bluetoothDevice);
- break;
- default:
- break;
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- cancelDiscovery();
- unregisterReceiver(blueReceiver);
-
- if (mBlueSocket != null) {
- try {
- mBlueSocket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- }
添加蓝牙所需的相应权限:
- <!-- 蓝牙 -->
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
- <uses-permission android:name="android.permission.BLUETOOTH"/>
- <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
-
- <!--基于地理位置-->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
6.0以上系统记得动态获取ACCESS_COARSE_LOCATION权限,不然可能会出现蓝牙设备检测不到。
Demo程序运行效果界面截图如下:
socket.connect();蓝牙连接成功之后,根据自己的需要做后续处理,楼主这里是通过InputStream和OutputStream来做数据的读写操作,所以各自开了一个读写进程。关于蓝牙连接就这么多,希望对大家有帮助呀~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。