• Android 蓝牙技术 实现终端间数据传输


    蓝牙技术在智能硬件方面有很多用武之地,今天我就为大家分享一下蓝牙技术在Android系统下的使用方法技巧。蓝牙是一种短距离的无线通信技术标准,蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。

    Android 支持的蓝牙协议栈有:

    蓝牙协议栈说明
    Bluz Linux官方蓝牙协议栈,最成熟的开源蓝牙协议栈,灵活高效。
    BlueDroid 从Android 4.2开始,Google在Android中推出了它和博通公司一起开发的BlueDroid以替代BlueZ,框架结构变得更为简洁和清晰。
    BLE 低功耗蓝牙协议栈,传输距离远,速率快。

    1.Android系统蓝牙本地操作

    Android 系统本地蓝牙代表本地的蓝牙适配器,也是所有蓝牙交互的入口点,可以对本地或者其他终端设备进行操作。其中 BluetoothAdapter 是重要的类,代表本地蓝牙适配器。

    1.判断本地蓝牙是否打开

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // null:表示不支持蓝牙
    boolean enabled = mBluetoothAdapter.isEnabled(); // true:处于打开状态, false:处于关闭状态

    2.调用系统对话框启动本地蓝牙

    // 添加蓝牙权限,不需要动态授权
    // <uses-permission android:name="android.permission.BLUETOOTH" />
    // <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);

    3.静默开启本地蓝牙 不会有对话框

    在AndroidManifest文件中添加需要的权限:

    <!-- 适配Android6.0/7.0 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true" />
    • 1

    由于蓝牙所需要的权限包含Dangerous Permissions,所以我们需要在Java代码中进行动态授权处理:

    if (ContextCompat.checkSelfPermission(context,
            Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(context,
                new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
    }
    • 1

    接下来我们就可以静默开启和关闭本地蓝牙了:

    mBluetoothAdapter.enable(); // 开启
    //mBluetoothAdapter.disable(); // 关闭

    4.本地蓝牙主动搜索周边蓝牙

    搜索分为主动搜索和被动搜索。我们开始进行主动搜索:

    1.创建 BluetoothAdapter 对象,首先获取已经配对的蓝牙设备:

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices(); // 获取已经配对的蓝牙设备
    • 1

    2.下面我们定义广播接收器

    // 设置广播信息过滤
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一个设备就会发送一个该广播
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//当全部搜索完后发送该广播
    filter.setPriority(Integer.MAX_VALUE);//设置优先级
    // 注册蓝牙搜索广播接收者,接收并处理搜索结果
    this.registerReceiver(receiver, filter);

    3.开始搜索周边蓝牙:

    //如果当前在搜索,就先取消搜索
    if (mBluetoothAdapter.isDiscovering()) {
        mBluetoothAdapter.cancelDiscovery();
    }
    //开启搜索
    mBluetoothAdapter.startDiscovery();

    搜索蓝牙设备

    2.Android系统蓝牙远程操作

    1.蓝牙的UUID

    两个蓝牙设备进行连接时需要使用同一个UUID。但很多读者可能发现,有很多型号的手机(可能是非Android系统的手机)之间使用了不同的程序也可以使用蓝牙进行通讯。从表面上看,它们之间几乎不可能使用同一个UUID。

    UUID的格式如下:

    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    

    UUID的格式被分成5段,其中中间3段的字符数相同,都是4,第1段是8个字符,最后一段是12个字符。所以UUID实际上是一个8-4-4-4-12的字符串。

    实际上,UUID和TCP的端口一样,也有一些默认的值。例如,将蓝牙模拟成串口的服务就使用了一个标准的UUID:

    00001101-0000-1000-8000-00805F9B34FB
    

    除此之外,还有很多标准的UUID,如下面就是两个标准的UUID:

    信息同步服务:00001104-0000-1000-8000-00805F9B34FB
    文件传输服务:00001106-0000-1000-8000-00805F9B34FB
    

    2.本地蓝牙与周边蓝牙间数据传输

    通过蓝牙传输数据与Socket类似。在网络中使用Socket和ServerSocket控制客户端和服务端的数据读写。而蓝牙通讯也由客户端和服务端Socket来完成。蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket。这两个类都在android.bluetooth包中。

    无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,Universally Unique Identifier),UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。

    我们开始进行模拟一个蓝牙数据的传输:

    首先来看客户端:

    (1)定义全局常量变量

    private ListView lvDevices;
    private BluetoothAdapter mBluetoothAdapter;
    private List<String> bluetoothDevices = new ArrayList<String>();
    private ArrayAdapter<String> arrayAdapter;
    private final UUID MY_UUID = UUID
            .fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//随便定义一个
    private BluetoothSocket clientSocket;
    private BluetoothDevice device;  
    private OutputStream os;//输出流
    • 1

    (2)在onCreate方法中做初始化操作

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
    lvDevices = (ListView) findViewById(R.id.lv_devices);
    //获取已经配对的蓝牙设备
    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    if (pairedDevices.size() > 0) {
        for (BluetoothDevice device : pairedDevices) {
            bluetoothDevices.add(device.getName() + ":"+ device.getAddress());
        }
    }
    arrayAdapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices);
    lvDevices.setAdapter(arrayAdapter);
    lvDevices.setOnItemClickListener(this);//Activity实现OnItemClickListener接口
    
    //每搜索到一个设备就会发送一个该广播
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    this.registerReceiver(receiver, filter);
    //当全部搜索完后发送该广播
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    this.registerReceiver(receiver, filter);
    • 1

    蓝牙设备的广播接收器如下:

    /**
     * 定义广播接收器
     */
    private final BroadcastReceiver receiver = new 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);
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    bluetoothDevices.add(device.getName() + ":" + device.getAddress());
                    arrayAdapter.notifyDataSetChanged();//更新适配器
                }
    
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                //已搜素完成
            }
        }
    };

    (4)我们创建一个Button按钮,当点击Button时进行搜索,Button点击事件如下:

    //如果当前在搜索,就先取消搜索
    if (mBluetoothAdapter.isDiscovering()) {
        mBluetoothAdapter.cancelDiscovery();
    }
    //开启搜索
    mBluetoothAdapter.startDiscovery();
    • 1

    (5)接下来我们设置列表的点击事件:

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        String s = arrayAdapter.getItem(position);
        String address = s.substring(s.indexOf(":") + 1).trim();//把地址解析出来
        //主动连接蓝牙服务端
        try {
            //判断当前是否正在搜索
            if (mBluetoothAdapter.isDiscovering()) {
                mBluetoothAdapter.cancelDiscovery();
            }
            try {
                if (device == null) {
                    //获得远程设备
                    device = mBluetoothAdapter.getRemoteDevice(address);
                }
                if (clientSocket == null) {
                    //创建客户端蓝牙Socket
                    clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
                    //开始连接蓝牙,如果没有配对则弹出对话框提示我们进行配对
                    clientSocket.connect();
                    //获得输出流(客户端指向服务端输出文本)
                    os = clientSocket.getOutputStream();
                }
            } catch (Exception e) {
            }
            if (os != null) {
                //往服务端写信息
                os.write("蓝牙信息来了".getBytes("utf-8"));
            }
        } catch (Exception e) {
        }
    }

    (2)定义服务端线程类:

    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            Toast.makeText(getApplicationContext(), String.valueOf(msg.obj),
                    Toast.LENGTH_LONG).show();
            super.handleMessage(msg);
        }
    };
    
    //服务端监听客户端的线程类
    private class AcceptThread extends Thread {
        public AcceptThread() {
            try {
                serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            } catch (Exception e) {
            }
        }
        public void run() {
            try {
                socket = serverSocket.accept();
                is = socket.getInputStream();
                while(true) {
                    byte[] buffer =new byte[1024];
                    int count = is.read(buffer);
                    Message msg = new Message();
                    msg.obj = new String(buffer, 0, count, "utf-8");
                    handler.sendMessage(msg);
                }
            }
            catch (Exception e) {
            }
        }
    }

    (3)在onCreate方法中初始化线程类并开启

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    acceptThread = new AcceptThread();
    acceptThread.start();
    • 1
    • 2
    • 3

    我们运行程序看一下效果图:

    client

    点击“搜索蓝牙设备”按钮,就会搜索到另一台手机的蓝牙信息,我们点击条目,另一台手机会出现如下变化:

    server

    弹出Toast,此时证明我们的蓝牙数据已经传输过来了。

  • 相关阅读:
    jQuery操作CheckBox的方法(选中,取消,取值)详解
    checkAll操作
    java 去掉重复的数字
    multiselect多选下拉框
    toggle() 隐藏和收缩
    Test 6.29 T4 简单数据结构练习
    Test 6.29 T3 小学生
    Test 6.29 T2 染色
    Test 6.29 T1 预算方案
    [洛谷P3338] ZJOI2014 力
  • 原文地址:https://www.cnblogs.com/ldq2016/p/6945155.html
Copyright © 2020-2023  润新知