IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android实现蓝牙(BlueTooth)设备检测连接 -> 正文阅读

[移动开发]Android实现蓝牙(BlueTooth)设备检测连接

项目要求实现蓝牙设备搜索连接,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的常用方法说明。

  • getName:获得该设备的名称;
  • getAddress:获得该设备的地址;
  • getBondState:获得该设备的绑定状态;
  • createBond:创建匹配对象;
  • createRfcommSocketToServiceRecord:根据UUID创建并返回一个BluetoothSocket。

蓝牙服务器套接字BluetoothServiceSocket

BluetoothServiceSocket是服务端的Socket,用来接收客户端的Socket连接请求。下面是常用的方法说明。

accept:监听外部的蓝牙连接请求;
close:关闭服务端的蓝牙监听。

蓝牙客户端套接字BluetoothSocket

BluetoothSocket是客户端的Socket,用于与对方设备进行数据通信。下面是常用的方法说明。

  • connect:建立蓝牙的socket连接;
  • close:关闭蓝牙的socket连接;
  • getInputStream:获取socket连接的输入流对象;
  • getOutputStream:获取socket连接的输出流对象;
  • getRemoteDevice:获取远程设备信息。

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来做数据的读写操作,所以各自开了一个读写进程。关于蓝牙连接就这么多,希望对大家有帮助呀~

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 11:46:00  更:2021-07-29 11:46:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 7:14:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码