android蓝牙简单开发示例教程

目录
  • 概述
  • 1、权限申请
  • 2、打开蓝牙
  • 3、接收蓝牙状态的改变
  • 4、扫描其他的设备
  • 5、蓝牙配对
  • 6、获取已经配对的设备
  • 7、连接设备

概述

前段时间学习了一些蓝牙开发的知识,记录一下Android中蓝牙的简单开发。下面是最重要的两个类。

BluetoothAdapter : 蓝牙适配器,通过getDefaultAdapter ()去获取一个实例,如果设备不支持蓝牙的话,返回的是一个null对象,通过它,可以打开、关闭蓝牙,扫描设备、向指定设备创建socket通道…

BluetoothDevice : 代表一个设备对象,可以通过它获取设备的名字、地址、类型等,也可以创建匹配,建立socket通道等等。

1、权限申请

<uses-permission android:name="android.permission.BLUETOOTH"/> 使用蓝牙所需要的权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 使用扫描和设置蓝牙的权限(申明这一个权限必须申明上面一个权限)

Android6以上版本,扫描其他蓝牙还需要位置权限

// Android 9 以下版本
<user-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
// Android 9 以上
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

2、打开蓝牙

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 如果设备不支持蓝牙
if (mBluetoothAdapter == null){
    return;
}
// 设备支持蓝牙功能,调用startActivityForResult去启动蓝牙
if (!mBluetoothAdapter.isEnabled()){
    startBlueTooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
}

打开蓝牙功能是通过startActivity去启动的,但是startActivity这个函数已经过期了,所以我使用官方推荐的Activity Result替代它

    ActivityResultLauncher<Intent> startBlueTooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result==null){
                        Toast.makeText(BlueToothActivity.this, "open failed", Toast.LENGTH_SHORT).show();
                    }else {
                        if (result.getResultCode() == RESULT_CANCELED){
                            Toast.makeText(BlueToothActivity.this,"用户取消",Toast.LENGTH_SHORT);
                        }
                    }
                }
            });

3、接收蓝牙状态的改变

通过广播去接收蓝牙状态的改变

class BluetoothStateChangeReceiver extends BroadcastReceiver{
    public int DEFAULT_VALUE_BLUETOOTH = 1000;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,DEFAULT_VALUE_BLUETOOTH);

            switch(state){
                case BluetoothAdapter.STATE_ON:
                    Log.d(TAG, "onReceive: open");
                    break;
                case BluetoothAdapter.STATE_OFF:
                    Log.d(TAG, "onReceive: off");
                    break;
                case BluetoothAdapter.STATE_TURNING_ON :
                    Log.d(TAG, "onReceive: 正在打开");
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    Log.d(TAG, "onReceive: 正在关闭");
                    break;
            }
        }
    }
}

别忘了广播的注册和解注册

IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
stateReceiver = new BluetoothStateChangeReceiver() ;
registerReceiver(stateReceiver,filter);

4、扫描其他的设备

同样通过广播接收,action是BluetoothDevice.ACTION_FOUND

    class MyReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // 从intent对象中获取蓝牙设备的信息
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 当发现新设备不存在于配对列表中时添加
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    blueNames.add(device.getName()+"\t"+device.getAddress());
                }
                blueAdpater.notifyDataSetChanged();
                Log.d(TAG, "onReceive: " + device.getName());
            }
        }
    }

动态注册广播

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver,filter);

开启扫描

mBluetoothAdapter.startDiscovery();

5、蓝牙配对

    public class BondReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch(device.getBondState()){
                    case BluetoothDevice.BOND_BONDED:
                        Log.d(TAG, "onReceive: 配对完成");
                        break;
                    case BluetoothDevice.BOND_BONDING:
                        Log.d(TAG, "onReceive: 正在配对");
                        break;
                    case BluetoothDevice.BOND_NONE:
                        Log.d(TAG, "onReceive: 取消配对");
                        break;
                }
            }
        }
    }

6、获取已经配对的设备

已经配对的设备会被存储起来,通过BluetoothAdpater直接获取即可

Set<BluetoothDevice> paireDevices = mBluetoothAdapter.getBondedDevices();
if (paireDevices.size()>0){
                        for (BluetoothDevice pairedDevice : pairedDevices) {
                        blueNames.add(pairedDevice.getName()+"  "+pairedDevice.getAddress());
                        Log.d(TAG, "onClick: "+pairedDevice.getName());
                    }
}

7、连接设备

想要在两台设备之间创建连接,必须实现客户端和服务端机制,他们之间使用套接字机制进行连接,服务端开放服务器套接字,客户端通过MAC地址向服务端发起连接。客户端和服务端以不同的方式获得BluetoothSocket,当客户端和服务端在同一个RFCOMM通道上分别拥有已连接的BluetoothSocket时,将他们视为彼此已经连接,于是每台设备都获得输入和输出流式传输,并开始传输数据。

连接技术

一种实现技术是自动将每台设备准备为一个服务器,从而使每台设备开放一个服务套接字并侦听连接,在此情况下,任何一台设备都可以发起与另一台设备的连接并称为客户端。

服务器

设置服务器套接字并接受连接,步骤依次如下

1、调用listenUsingRfcommWithServiceRecord()获取一个BluetoothServerSocket, 该函数需要两个参数,第一个是服务器的名称,自己取一个即可,第二个是UUID,用来对信息做唯一性标识,我们可以从网上众多UUID生成器中随机的生成一个,然后使用UUID.fromString(String)初始化一个UUID。

2、通过accept()函数开始侦听连接请求

只有远程设备发送的连接请求中UUID与使用此套接字注册的UUID相匹配时服务器才会接受请求,accept函数会返回已连接的BluetoothSocket

3、连接成功后调用close()关闭BluetoothSocket

 private class AcceptThread extends Thread{

        private final BluetoothServerSocket mmServerSocket;
        private String mSocketType;

        public AcceptThread(boolean secure){
            BluetoothServerSocket tmp = null;
            mSocketType = secure ? "secure" : "Insercure";
            try{
                if (secure){
                    tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE);
                }else{
                    tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_INSECURE,MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG,"socket type"+ mSocketType + "listen() failed",e);
            }

            mmServerSocket = tmp;
        }

        @Override
        public void run() {
            Log.d(TAG, "Socket Type: " + mSocketType +
                    "BEGIN mAcceptThread" + this);
            setName("AcceptThread"+ mSocketType);

            BluetoothSocket socket = null;
            Log.d(TAG, "run: 开始监听");
            while (true){
                try{
                    socket = mmServerSocket.accept();
                    Log.d("acceptThread", "run: 连接成功");
                    connected(socket,socket.getRemoteDevice(),mSocketType);
                } catch (IOException e) {
                    Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
                    break;
                }

            }
            Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
        }

        public void cancel() {
            Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
            try {
                mmServerSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
            }
        }
    }

上面的secure和Insecure只是使用了不同的UUID而已。

客户端

远程设备开启监听后,我们就发起向此设备的连接,首先必须先获得远程设备的BluetoothDevice对象,然后获取BluetoothSocket发起连接。

基本步骤如下

1、使用BluetoothDevice通过调用createRfcommSocketToServiceRecord(UUID) 获取 BluetoothSocket

2、通过connect发起连接

private class ConnectThread extends Thread{
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private String mSocketType;

        public ConnectThread(BluetoothDevice device, boolean secure){
            mmDevice = device;
            BluetoothSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";
            try {
                if (secure){
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
                }else {
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
                }
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
            }
            mmSocket = tmp;
        }

        @Override
        public void run() {
            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
            setName("ConnectThred"+mSocketType);

            // 总是取消发现,因为它会减慢连接
            bluetoothAdapter.cancelDiscovery();
            // connect
            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                mmSocket.connect();
                Log.d(TAG, "run: socket连接成功");
            } catch (IOException e) {
                // Close the socket
                Log.d(TAG, "run: 关闭socket");
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                    Log.e(TAG, "unable to close() " + mSocketType +
                            " socket during connection failure", e2);
                }

                return;
            }

            connected(mmSocket,mmDevice,mSocketType);
        }

        public void cancel(){
            try{
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
            }
        }

    }

发送数据

连接成功后,我们就可以通过socket发送数据了,客户端的Socket对象是BluetoothSocket, 服务端的socket是BluetoothServerSocket,特别注意不要混淆了。使用getInputStreamgetOutputStream分别获取通过套接字处理数据传输的InputStreamOutputStream。写数据比较简单,但是读数据就需要一个单独的线程一直监听才行。

private class ConnectedThread extends Thread{
        private final BluetoothSocket mmSocket;
        private InputStream mmInStream;
        private OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket, String socketType) throws IOException {
            Log.d(TAG, "create ConnectedThread: " + socketType);
            mmSocket = socket;

            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try{
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();

                if (socket != null){
                    tmpOut.write(new String("hello").getBytes());
                    Log.d(TAG, "ConnectedThread: socket不是null");
                }
            } catch (IOException e) {
                Log.e(TAG,"temp socket not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;

            // mmOutStream.write(new String("hello").getBytes());
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            while (true){
                try{
                    bytes = mmInStream.read(buffer);
                    // send the bytes to the ui Activity
                    String text = encodeByteToString(buffer,bytes);
                    Log.d(TAG, "run: 收到消息:"+ text);
                    chatItems.add(text);
                    mHandler.sendMessage(mHandler.obtainMessage());
                } catch (IOException e) {
                    Log.d(TAG, "run: 没有收到消息");
                    e.printStackTrace();
                    break;
                }
            }
        }

        public String encodeByteToString(byte[] data,int length) {
            byte[] temp = new byte[length];
            for (int i = 0; i < length; i++) {
                temp[i] = data[i];
            }
            try {
                return new String(temp,"utf-8");
            } catch (UnsupportedEncodingException e) {
                return "";
            }
        }

        public void write(byte[] buffer){
            try{
                mmOutStream.write(buffer);

                // mHandler.obtainMessage(Constants.MESSAGE_WRITE,-1,-1,buffer).sendToTarget();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void cancel(){
            try{
                mmSocket.close();
                Log.d(TAG, "cancel: connectedThread");
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }

上面的例子我主要是学习官网上的蓝牙聊天项目写的代码,大家也可以直接看官网项目。从上面的例子中可知,接受到的数据流都是一些二进制,要用到实际的项目中还需要进行一定的编码和转换。也就是自己编写一些协议,学过socket编程的同学一定都懂,其实蓝牙已经有很多的好用的协议了,就比如AVRCP(Audio Video Remote Control Profile),定义了蓝牙设备和audio/video控制功能通信的特点和过程, 结合MediaSession 可以很容易的实现设备音视频控制。

到此这篇关于android蓝牙简单开发示例教程的文章就介绍到这了,更多相关android蓝牙开发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android实现蓝牙(BlueTooth)设备检测连接

    无论是WIFI还是4G网络,建立网络连接后都是访问互联网资源,并不能直接访问局域网资源.比如两个人在一起,A要把手机上的视频传给B,通常情况是打开手机QQ,通过QQ传送文件给对方.不过上传视频很耗流量,如果现场没有可用的WIFI,手机的数据流量又不足,那又该怎么办呢?为了解决这种邻近传输文件的问题,蓝牙技术应运而生.蓝牙技术是一种无线技术标准,可实现设备之间的短距离数据交换. Android为蓝牙技术提供了4个工具类,分别是蓝牙适配器BluetoothAdapter.蓝牙设备BluetoothD

  • Android 蓝牙BLE开发完全指南

    目录  介绍 连接模式 GATT协议 使用过程 扫描 连接 设备连接 发现服务 数据传输 其他 断开连接 参考 总结  介绍 1.BLE 是 Bluetooth Low Energy 的缩写,意思为低功耗蓝牙.由蓝牙技术联盟(Bluetooth SIG)设计的无线通讯技术,主要用于医疗,健身,安全和家庭娱乐行业. 与传统蓝牙相比,蓝牙低功耗旨在大幅降低功耗和成本,同时也能够达到相同的通讯效果. 支持多个平台,包括 IOS,Android,Windows Phone 和 BlackBerry 以及

  • android实现蓝牙app代码

    本文实例为大家分享了android实现蓝牙app的具体代码,供大家参考,具体内容如下 private BluetoothGatt bluetoothGatt; private BluetoothGattService gattService; private BluetoothGattCharacteristic gattCharacteristic; private BluetoothManager bluetoothManager; private BluetoothAdapter blue

  • Android获取蓝牙设备列表的方法

    最近换了一家公司,主要内容是做关于移动端室内定位的相关sdk,刚进来的时候信心满满,誓要干出一番天地!!!结果进来快一个多月了,根本没轮到我施展拳脚,给我搁置在一旁自己弄自己的.行吧,既然是做室内定位的话那无非就是(gps,蓝牙,wifi等)这些技术来实现嘛,然后我们就可以有本篇的切入点了: android如何获取蓝牙设备了? 我们一步一步来分析,首先蓝牙属于一种短距离的无线通信技术,那作为我们android系统是否对此有过封装了?答案那肯定是有了! BluetoothAdapter andro

  • android蓝牙简单开发示例教程

    目录 概述 1.权限申请 2.打开蓝牙 3.接收蓝牙状态的改变 4.扫描其他的设备 5.蓝牙配对 6.获取已经配对的设备 7.连接设备 概述 前段时间学习了一些蓝牙开发的知识,记录一下Android中蓝牙的简单开发.下面是最重要的两个类. BluetoothAdapter : 蓝牙适配器,通过getDefaultAdapter ()去获取一个实例,如果设备不支持蓝牙的话,返回的是一个null对象,通过它,可以打开.关闭蓝牙,扫描设备.向指定设备创建socket通道- BluetoothDevic

  • Java Spring开发环境搭建及简单入门示例教程

    本文实例讲述了Java Spring开发环境搭建及简单入门示例.分享给大家供大家参考,具体如下: 前言 虽然之前用过Spring,但是今天试着去搭建依然遇到了困难,而且上网找教程,很多写的是在web里使用Spring MVC的示例,官方文档里的getting start一开始就讲原理去了(可能打开的方法不对).没办法,好不容易实验成功了,记下来免得自己以后麻烦. 添加依赖包 进入spring官网,切换到projects下点击 spring framework.官网上写的是以maven依赖的形式写

  • android视频播放简单实现示例(VideoView&MediaPlayer)

    如果你看过我的<android音乐播放简单实现(MediaPlayer)>,那么本篇将会毫无压力. 首先是主界面的三个按钮和一个播放控件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sche

  • Android 蓝牙开发实例解析

    在使用手机时,蓝牙通信给我们带来很多方便.那么在Android手机中怎样进行蓝牙开发呢?本文以实例的方式讲解Android蓝牙开发的知识.        1.使用蓝牙的响应权限 XML/HTML代码 <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN&qu

  • Android开发中CheckBox的简单用法示例

    本文实例讲述了Android开发中CheckBox的简单用法.分享给大家供大家参考,具体如下: CheckBox是一种在界面开发中比较常见的控件,Android中UI开发也有CheckBox,简单的说下它的使用,每个CheckBox都要设置监听,设置的监听为CompouButton.OnCheckedChangedListener(). package com.zhuguangwei; import android.app.Activity; import android.os.Bundle;

  • Android编程简单实现九宫格示例

    本文实例讲述了Android编程简单实现九宫格.分享给大家供大家参考,具体如下: 实现的步骤 1. 一个整体的容器部分.就是上图中包括整个图片项个各个部分,这里我们使用gridView(表格布局)来实现 2.整个界面里需要注意的是 "重复的部分",就是 各个图片项和,图片下方显示的文字了.那么我们需要描述这个部分.在描述时,要说明图片位于上方,文字位于下方. 3.迭代,或者说重复的将各项 插入(放入)到容器内. 需要添加/修改3个文件:main.xml.meunitem.xml.act

  • Android编程简单解析JSON格式数据的方法示例

    本文实例讲述了Android编程简单解析JSON格式数据的方法.分享给大家供大家参考,具体如下: 比起XML,JSON主要优势在于它的体积更小,在网络上传输的时候可以更省流量.但缺点在于,它的语义性较差,显示不如XML直观. JSON格式 : { "name_A" : "value_A","name_B" : "value_B" } 表示: name_A = value_A; name_B = value_B; 我将对下面的J

  • Android编程之View简单学习示例

    本文实例讲述了Android编程之View简单学习示例.分享给大家供大家参考,具体如下: View,是Android的一个超类,这个类几乎包含了所有的屏幕类型.每一个View都有一个用于绘图的画布,这个画布可以进行任意扩展. 在游戏开发中叶可以自定义视图(View),这个画布的功能更能满足我们在游戏开发中的需要.在Android中,任何一个View类都只需重写onDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本形式等. 游戏的核心是不断地绘图和刷新界面,An

  • Android实现简单的下拉阻尼效应示例代码

    OS的下拉上拉都会出现一个很玄的动态效果.在Android中,虽然可以实现类似的效果,但有点不同的是,如果调用overScrollBy来实现类似的阻尼效应的话,最顶部会出现一片亮的区域,让人感觉不是很爽.所以决定不采用该方法来实现而是改用自定义的方式来实现. 下面是自定义控件的代码部分: public class MyView extends ScrollView { //记录下最开始点击的位置 int initY; //移动的位置 int deltaY; int touchY; //记录第一个

随机推荐