Android 蓝牙通信的开发与应用

Android 蓝牙通信的开发与使用

日常App开发很少应用到蓝牙的,大都需要去连接硬件才使用的到,在这儿讲一些Android 蓝牙的基本通信与使用:

1、使用蓝牙,应该先理清一个使用的基本流程,大致如下:

  • 扫描其他蓝牙设备
  • 查询本地蓝牙适配器的配对蓝牙设备
  • 建立 RFCOMM 通道
当然有些还会有以下连接的需求:

  • 与其他设备进行双向数据传输
  • 管理多个连接

2、明确了蓝牙的基本使用流程,我们就要了解一下我们实际代码中常用的一些类和方法(API里已经讲的很清楚了):

    BluetoothAdapter

表示本地蓝牙适配器(蓝牙无线装置)。 BluetoothAdapter 是所有蓝牙交互的入口点。 利用它可以发现其他蓝牙设备,查询绑定(配对)设备的列表,使用已知的 MAC 地址实例化 BluetoothDevice,以及创建 BluetoothServerSocket 以侦听来自其他设备的通信。

BluetoothDevice
表示远程蓝牙设备。利用它可以通过 BluetoothSocket 请求与某个远程设备建立连接,或查询有关该设备的信息,例如设备的名称、地址、类和绑定状态等。
BluetoothSocket
表示蓝牙套接字接口(与 TCP Socket 相似)。这是允许应用通过 InputStream 和 OutputStream 与其他蓝牙设备交换数据的连接点。
BluetoothServerSocket
表示用于侦听传入请求的开放服务器套接字(类似于 TCP ServerSocket)。 要连接两台 Android 设备,其中一台设备必须使用此类开放一个服务器套接字。 当一台远程蓝牙设备向此设备发出连接请求时, BluetoothServerSocket 将会在接受连接后返回已连接的 BluetoothSocket
BluetoothClass
描述蓝牙设备的一般特征和功能。 这是一组只读属性,用于定义设备的主要和次要设备类及其服务。 不过,它不能可靠地描述设备支持的所有蓝牙配置文件和服务,而是适合作为设备类型提示。
BluetoothProfile
表示蓝牙配置文件的接口。 蓝牙配置文件是适用于设备间蓝牙通信的无线接口规范。 免提配置文件便是一个示例。 如需了解有关配置文件的详细讨论,请参阅使用配置文件
BluetoothHeadset
提供蓝牙耳机支持,以便与手机配合使用。 其中包括蓝牙耳机和免提(1.5 版)配置文件。
BluetoothA2dp
定义高质量音频如何通过蓝牙连接和流式传输,从一台设备传输到另一台设备。“A2DP”代表高级音频分发配置文件。
BluetoothHealth
表示用于控制蓝牙服务的健康设备配置文件代理。
BluetoothHealthCallback
用于实现 BluetoothHealth 回调的抽象类。您必须扩展此类并实现回调方法,以接收关于应用注册状态和蓝牙通道状态变化的更新内容。
BluetoothHealthAppConfiguration
表示第三方蓝牙健康应用注册的应用配置,以便与远程蓝牙健康设备通信。
BluetoothProfile.ServiceListener
在 BluetoothProfile IPC 客户端连接到服务(即,运行特定配置文件的内部服务)或断开服务连接时向其发送通知的接口。

3、老规矩,少不了的权限:

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

4、接下来就是按照咱讲好的流程使用就是了:
  •  设置蓝牙,先获取    BluetoothAdapter ,判断设备是否支持蓝牙
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
    //不支持的话到这就拜拜咯
}
  • 既然支持蓝牙,就该启动蓝牙了。调用 isEnabled() 以检查当前是否已启用蓝牙。 如果此方法返回 false,则表示蓝牙处于停用状态:
if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
  • 蓝牙都打开了,开始查找搜索,要发起连接,BlueToothDevice 对象仅仅需要提供 MAC 地址。将保存为显示给用户的 ArrayAdapter 的一部分。 之后可提取该 MAC 地址,以便发起连接

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
    for (BluetoothDevice device : pairedDevices) {
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
    }
}

  • 发现设备,都搜索了,也差不多该有结果了,这里需要调用 startDiscovery()。该方法会立即返回一个布尔值,指示是否已成功启动发现操作
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
        }
    }
};
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);

(必须针对 ACTION_FOUND Intent 注册一个 BroadcastReceiver,以便接收每台发现的设备的相关信息。 针对每台设备,系统将会广播ACTION_FOUND Intent。此 Intent 将携带额外字段 EXTRA_DEVICE 和 EXTRA_CLASS,二者分别包含 BluetoothDevice 和 BluetoothClass要发起连接,BluetoothDevice 对象仅仅需要提供 MAC 地址。它将保存为显示给用户的 ArrayAdapter 的一部分。 之后可提取该 MAC 地址,以便发起连接。 您可以在有关连接设备的部分详细了解如何创建连接。)

  • 开始连接:

要在两台设备上的应用之间创建连接,必须同时实现服务器端和客户端机制,因为其中一台设备必须开放服务器套接字,而另一台设备必须发起连接(使用服务器设备的 MAC 地址发起连接)。 当服务器和客户端在同一 RFCOMM 通道上分别拥有已连接的 BluetoothSocket 时,二者将被视为彼此连接。 这种情况下,每台设备都能获得输入和输出流式传输,并且可以开始传输数据,在有关管理连接的部分将会讨论这一主题。 本部分介绍如何在两台设备之间发起连接。服务器设备和客户端设备分别以不同的方法获得需要的 BluetoothSocket。服务器将在传入连接被接受时收到套接字。 客户端将在其打开到服务器的 RFCOMM 通道时收到该套接字。


5、前文中有提到 管理多个连接在成功连接多个设备后,每台设备都会有一个已连接的 BluetoothSocket。 这表示可以在设备之间共享数据。 利用BluetoothSocket,传输任意数据:
  1. 获取 InputStream 和 OutputStream,二者分别通过套接字以及 getInputStream() 和  getOnputStream()  来处理数据传输。
  2. 使用 read(byte[]) 和 write(byte[]) 读取数据并写入到流式传输。


在这再贴个代码,这是一个手机连接一个蓝牙可操控的LED灯的小Demo,供大家参考:


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.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 蓝牙的操作流程
 * 1 你的设备要支持蓝牙 然后打开蓝牙
 * 2 扫描设备
 * 3 连接设备
 * 4 数据交换(通过 socket 传输流)
 */

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_ENABLE_BT = 1000;//启动蓝牙的请求码
    private BluetoothAdapter mBluetoothAdapter;//蓝牙是入口
    private MyBroadCastReciver myBroadCastReciver;//用于接收设备的广播
    private List<BluetoothDevice> mList;//存放蓝牙设备的集合
    private ListView listView;
    private MyAdapter myAdapter;
    private BluetoothDevice mBluetoothDevice;//将要连接的指定设备
    private OutputStream outputStream;
    private BluetoothSocket mBluethoothSocket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//获取默认的  蓝牙adapter
        if (mBluetoothAdapter == null) {//如果返回空,代表设备不支持蓝牙
            Toast.makeText(this, "什么破手机,连个蓝牙都不支持,给我一百万,我帮你砸了", Toast.LENGTH_SHORT).show();
            return;
        }
        listView = (ListView) findViewById(R.id.listview);//用于显示所有蓝牙设备的列表
        mList = new ArrayList<>();
        myAdapter = new MyAdapter(mList, this);
        listView.setAdapter(myAdapter);
        IntentFilter mIntentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//发现蓝牙设备的意图过滤器
        mIntentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播
        mIntentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束的广播
        myBroadCastReciver = new MyBroadCastReciver();
        registerReceiver(myBroadCastReciver, mIntentFilter);//注册广播
    }

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.startdis://开始扫描
                mList.clear();//清理掉集合
                if (!mBluetoothAdapter.isEnabled()) {// 如果蓝牙被禁用,应该要求用户启用蓝牙
                    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
                }
                // mBluetoothAdapter.enable();//启用蓝牙.但是不推荐这种方式
                mBluetoothAdapter.startDiscovery();//启动扫描
                break;
            case R.id.openlight://开灯
                //01 99 01 00 99  十六进制
                sendControl(new byte[]{0x01, (byte) 0x99, 0x01, 0x00, (byte) 0x99});
                break;
            case R.id.closelight://关灯
                //01 99 01 01 99 十六进制
                sendControl(new byte[]{0x01, (byte) 0x99, 0x01, 0x01, (byte) 0x99});
                break;
        }
    }

    /**
     * 发送指令
     *
     * @param bs
     */
    private void sendControl(byte[] bs) {
        //应该在子线程中执行
        if (mBluetoothDevice != null) {//如果发现了指定的设备
            try {
                if (mBluethoothSocket == null) {//如果没有建立网络连接,就创建
                    mBluethoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                    //开始交换数据
                    mBluethoothSocket.connect();//连接
                    //获取输出流

                    outputStream = mBluethoothSocket.getOutputStream();
                }
                if (outputStream != null) {
                    outputStream.write(bs);//写入数据
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 用于接收蓝牙设备的广播
     */
    private class MyBroadCastReciver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //在这里处理收到的蓝牙设备即可
            switch (intent.getAction()) {
                case BluetoothDevice.ACTION_FOUND://匹配一个发现蓝牙设备的广播
                    BluetoothDevice mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//通过意图获取到被发现的蓝牙设备
                    Log.e("自定义标签", "类名==MyBroadCastReciver" + "方法名==onReceive=====:" + "name===" + mBluetoothDevice.getName() + "add==" + mBluetoothDevice.getAddress());
                    if ("BRK05".equals(mBluetoothDevice.getName()) || "98:D3:31:20:7E:F1".equals(mBluetoothDevice.getAddress())) {
                        //如果是我想要的设备
                        MainActivity.this.mBluetoothDevice = mBluetoothDevice;
                    }
                    mList.add(mBluetoothDevice);
                    myAdapter.notifyDataSetChanged();
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
                    Toast.makeText(MainActivity.this, "开始扫描蓝牙", Toast.LENGTH_SHORT).show();
                    //  Log.e("自定义标签", "类名==MyBroadCastReciver" + "方法名==onReceive=====:" + "开始扫描蓝牙");
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                    Toast.makeText(MainActivity.this, "蓝牙扫描结束", Toast.LENGTH_SHORT).show();
                    // Log.e("自定义标签", "类名==MyBroadCastReciver" + "方法名==onReceive=====:" + "蓝牙扫描结束");

                    break;
            }
        }
    }

    /**
     * 释放资源
     */
    @Override
    protected void onDestroy() {
        unregisterReceiver(myBroadCastReciver);
        outputStream = null;
        mBluethoothSocket = null;
        mBluetoothDevice = null;
        myBroadCastReciver = null;
        super.onDestroy();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值