蓝牙4.0 的一些实现

一. 蓝牙介绍

1. 蓝牙介绍
  • 1.蓝牙:BlueTooth 短距离数据传输
  • 2.应用:蓝牙耳机 蓝牙音箱
  • 3.功能:
  • 打开蓝牙:
  • 关闭蓝牙:
  • 扫描附近的蓝牙设备:
  • 配对蓝牙:
  • 传输文件:
  • 4.打开蓝牙:隐式意图打开蓝牙
  • 5.关闭蓝牙:adapter.disable()
  • 6.扫描:adapter.startDiscovery()
  • 7.配对:device.createBond()
  • 8.获取配对的设备:adapter.getBonedDevices()
  • 9.传输数据
  • (1)客户端
  • (2)服务端:
  • 一般保证蓝牙设备打开状态,不要点击关闭

简单的界面展示(左:为Demo中实现, 右为当前简单的实现界面):
在这里插入图片描述在这里插入图片描述

2. 部分代码实现
  1. 在清单文件中添加权限 4个权限
    <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- 蓝牙连接配对权限-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <!-- 扫描蓝牙设备权限-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  <!-- GPS定位权限-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <!-- 通过WIFI或基站获取位置权限-->
  1. MainActivity 中进行动态授权, 由于蓝牙会默认添加, 所以只进行位置定位的动态的授权, 代码如下:
        // 数组用于存放权限
        String[] strings = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 判断系统版本是否是6.0以上
            // 判断权限是否授权
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(strings, 101); //动态获取权限
            }
        }
  1. 初始化View控件 及点击事件, 这里用的是实现接口监听(OnClickListener),
    布局文件在最下面: 见activity_main布局
private void initView() {
        bt_open = (Button) findViewById(R.id.bt_open);
        bt_open.setOnClickListener(this);
        bt_scan = (Button) findViewById(R.id.bt_scan);
        bt_scan.setOnClickListener(this);
        bt_close = (Button) findViewById(R.id.bt_close);
        bt_close.setOnClickListener(this);
        bt_show = (Button) findViewById(R.id.bt_show);
        bt_show.setOnClickListener(this);
        lv_show = (ListView) findViewById(R.id.lv2);
        lv_showAll = (ListView) findViewById(R.id.lv);


        //显示已匹配的蓝牙设备
        show_myAdapter = new MyAdapter(this, list_show);
        lv_show.setAdapter(show_myAdapter);
        //显示所有可匹配的蓝牙设备
        showAll_myAdapter = new MyAdapter(this, list_showAll);
        lv_showAll.setAdapter(showAll_myAdapter);

        // 可匹配设备中 点击蓝牙设备 发起配对请求
        lv_showAll.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                list_showAll.get(position).createBond(); //发送配对请求
            }
        });

        // 已匹配设备中 点击蓝牙设备 发送信息, 或进行其他操作, 这里只发送信息
        lv_show.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final BluetoothDevice device = list_show.get(position);

                // 这里是客户端
                try {
                   BluetoothSocket rfcommSocketToServiceRecord = device.createRfcommSocketToServiceRecord(uuid);
                   rfcommSocketToServiceRecord.connect(); //连接
                   OutputStream outputStream = rfcommSocketToServiceRecord.getOutputStream();
                   outputStream.write("哈哈哈哈哈哈".getBytes());

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_open: //打开蓝牙
				
                break;
            case R.id.bt_scan: //搜索

                break;
            case R.id.bt_close: //关闭

                break;
            case R.id.bt_show: //显示匹配

                break;
        }
    }
  1. 获取本机蓝牙, 通过蓝牙管理者获取
		BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); //获得蓝牙管理者
        adapter = manager.getAdapter();//得到蓝牙适配器 adapter为全局变量为:BluetoothAdapter adapter;
  1. 注册广播 和解除注册实现
    5.1 注册广播
		myRecevier=new MyRecevier();  //全局 广播接收者
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//扫描到远程设备
        registerReceiver(myRecevier,intentFilter);

5.2 在Activity声明周期的onDestroy中解除注册

@Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(myReceiver); //解除注册
    }
  1. 功能实现
    6.1 打开蓝牙(使用隐示意图)
private void open() {
        Intent intent = new Intent();
        intent.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE); //设置蓝牙可用
        intent.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //设置被扫描

        intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 200); // 设置被扫描的时长
        startActivity(intent);

        // TODO 5. 创建ServerSocket监听客户端的连接
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BluetoothServerSocket serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(adapter.getName(), uuid);

                    while (true) { //等待客户端的连接, 每连接到一个就要开启线程
                        BluetoothSocket socket = serverSocket.accept();
                        new ServerThread(MainActivity.this, socket).start();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

6.2 显示已配对的设备

private void show() {
        list_show.clear();
        Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices();//获得已经配对的蓝牙设备
        list_show.addAll(bondedDevices);
        show_myAdapter.notifyDataSetChanged();
    }

6.3 关闭蓝牙

    private void close() {
        adapter.disable(); // 关闭蓝牙
    }

6.4 搜索附近设备

    private void search() {
        list_show.clear();
        adapter.startDiscovery(); // 开始搜索
//      adapter.cancelDiscovery(); // 停止搜索
    }
  1. 广播接收者: 接收系统发送的广播, 扫描到设备
class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { //扫描到一个
                // 获取远程蓝牙设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 放到list_showAll中
                list_showAll.add(device);
                showAll_myAdapter.notifyDataSetChanged(); // 通知适配器更新数据
            }
        }
    }

二. 全部代码的实现

1. 布局文件

activity_main布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="5dp"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <Button
            android:id="@+id/bt_open"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="打开蓝牙" />


        <Button
            android:id="@+id/bt_scan"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="扫描蓝牙" />

        <Button
            android:id="@+id/bt_close"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="关闭蓝牙" />
    </LinearLayout>

    <Button
        android:id="@+id/bt_show"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:text="查看已经配对的设备" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#615353"
        android:gravity="center_vertical"
        android:text="已经配对的蓝牙设备"
        android:textColor="#ffffff" />

    <ListView
        android:id="@+id/lv2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="1dp"
        android:layout_weight="1"
        android:background="#615353"
        android:gravity="center_vertical"
        android:text="扫描到设备"
        android:textColor="#ffffff" />

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10" />

</LinearLayout>
2. MainActivity中
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothServerSocket;
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.os.Parcelable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;

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

/**
 * 1.蓝牙:BlueTooth  短距离数据传输
 * 2.应用:蓝牙耳机 蓝牙音箱
 * 3.功能:
 * 打开蓝牙:
 * 关闭蓝牙:
 * 扫描附近的蓝牙设备:
 * 配对蓝牙:
 * 传输文件:
 * 4.打开蓝牙:隐式意图打开蓝牙
 * 5.关闭蓝牙:adapter.disable()
 * 6.扫描:adapter.startDiscovery()
 * 7.配对:device.createBond()
 * 8.获取配对的设备:adapter.getBonedDevices()
 * 9.传输数据
 * (1)客户端
 * (2)服务端:
 * 一般保证蓝牙设备打开状态,不要点击关闭
 **/

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private UUID uuid = UUID.fromString("00001106-0000-1000-8000-00805F9B34FB");//蓝牙通讯规范
    private Button bt_open;
    private Button bt_scan;
    private Button bt_close;
    private Button bt_show;
    private ListView lv_show; //显示已匹配的蓝牙设备
    private ListView lv_showAll;  //显示所有可匹配的蓝牙设备

    List<BluetoothDevice> list_show = new ArrayList<>(); // 用于存放已匹配的蓝牙设备
    List<BluetoothDevice> list_showAll = new ArrayList<>(); //用于存放所有可匹配的蓝牙设备

    MyAdapter showAll_myAdapter, show_myAdapter;

    BluetoothAdapter adapter; //蓝牙适配器
    MyReceiver myReceiver; //广播

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // TODO 1:动态收授权
        initEmpower(); //授权

        // TODO 2:初始化视图
        initView();

        // TODO 3:获得本机蓝牙
        getLocalBluetooth();

        // TODO 4: 注册广播 和解除广播, 解除广播在onDestroy()中进行
        registerRec();

    }

    /**
     * 注册广播
     */
    private void registerRec() {
        myReceiver = new MyReceiver();// 创建广播接收者, 全局变量, 方便用于注销
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND); //扫描到远程设备
        registerReceiver(myReceiver, intentFilter); // 注册
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(myReceiver); //解除注册
    }

    /**
     * 获得本机蓝牙
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void getLocalBluetooth() {
        BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); //获得蓝牙管理者
        adapter = manager.getAdapter();//得到蓝牙适配器
    }

    /**
     * 授权
     */
    private void initEmpower() {
        // 数组用于存放权限
        String[] strings = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 判断系统版本是否是6.0以上
            // 判断权限是否授权
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(strings, 101); //动态获取权限
            }
        }
    }

    private void initView() {
        bt_open = (Button) findViewById(R.id.bt_open);
        bt_open.setOnClickListener(this);
        bt_scan = (Button) findViewById(R.id.bt_scan);
        bt_scan.setOnClickListener(this);
        bt_close = (Button) findViewById(R.id.bt_close);
        bt_close.setOnClickListener(this);
        bt_show = (Button) findViewById(R.id.bt_show);
        bt_show.setOnClickListener(this);
        lv_show = (ListView) findViewById(R.id.lv2);
        lv_showAll = (ListView) findViewById(R.id.lv);

        //显示已匹配的蓝牙设备
        show_myAdapter = new MyAdapter(this, list_show);
        lv_show.setAdapter(show_myAdapter);
        //显示所有可匹配的蓝牙设备
        showAll_myAdapter = new MyAdapter(this, list_showAll);
        lv_showAll.setAdapter(showAll_myAdapter);

        // 可匹配设备中 点击蓝牙设备 发起配对请求
        lv_showAll.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                list_showAll.get(position).createBond(); //发送配对请求
            }
        });

        // 已匹配设备中 点击蓝牙设备 发送信息, 或进行其他操作, 这里只发送信息
        lv_show.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final BluetoothDevice device = list_show.get(position);

                // 这里是客户端
                try {
                    BluetoothSocket rfcommSocketToServiceRecord = device.createRfcommSocketToServiceRecord(uuid);
                    rfcommSocketToServiceRecord.connect(); //连接
                    OutputStream outputStream = rfcommSocketToServiceRecord.getOutputStream();
                    outputStream.write("哈哈哈哈哈哈".getBytes());

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_open: //打开蓝牙
                open();
                break;
            case R.id.bt_scan: //搜索
                search();
                break;
            case R.id.bt_close: //关闭
                close();
                break;
            case R.id.bt_show: //显示匹配
                show();
                break;
        }
    }

    /**
     * 打开蓝牙 使用隐示意图打开蓝牙
     */
    private void open() {
        Intent intent = new Intent();
        intent.setAction(BluetoothAdapter.ACTION_REQUEST_ENABLE); //设置蓝牙可用
        intent.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //设置被扫描

        intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 200); // 设置被扫描的时长
        startActivity(intent);

        // TODO 5. 创建ServerSocket监听客户端的连接
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BluetoothServerSocket serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(adapter.getName(), uuid);

                    while (true) { //等待客户端的连接, 每连接到一个就要开启线程
                        BluetoothSocket socket = serverSocket.accept();
                        new ServerThread(MainActivity.this, socket).start();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 显示已配对的设备
     */
    private void show() {
        list_show.clear();
        Set<BluetoothDevice> bondedDevices = adapter.getBondedDevices();//获得已经配对的蓝牙设备
        list_show.addAll(bondedDevices);
        show_myAdapter.notifyDataSetChanged();
    }

    /**
     * 关闭
     */
    private void close() {
        adapter.disable(); // 关闭蓝牙
    }

    /**
     * 搜索
     */
    private void search() {
        list_show.clear();
        adapter.startDiscovery(); // 开始搜索
//      adapter.cancelDiscovery(); // 停止搜索
    }


    /**
     * 广播接收者: 接收系统发送的广播, 扫描到设备
     */
    class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { //扫描到一个
                // 获取远程蓝牙设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // 放到list_showAll中
                list_showAll.add(device);
                showAll_myAdapter.notifyDataSetChanged(); // 通知适配器更新数据
            }
        }
    }
}

3. MyAdapter 中
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class MyAdapter extends BaseAdapter {
    Context context;
    List<BluetoothDevice> list;

    public MyAdapter(Context context, List<BluetoothDevice> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.layout_item, parent, false);
            holder.tv_name = convertView.findViewById(R.id.tv_name);
            holder.tv_address = convertView.findViewById(R.id.tv_address);
            convertView.setTag(holder);
        }
        holder = (ViewHolder) convertView.getTag();

        holder.tv_name.setText(list.get(position).getName());
        holder.tv_address.setText(list.get(position).getAddress());
        return convertView;
    }

    class ViewHolder {
        TextView tv_name, tv_address;
    }
}

4. ServerThread中 (线程)
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothSocket;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStream;

public class ServerThread extends Thread {
    Activity context;
    BluetoothSocket socket;

    public ServerThread(Activity context, BluetoothSocket socket) {
        this.context = context;
        this.socket = socket;
    }

    @Override
    public void run() {
        super.run();
        // 回到主线程
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "有人要给我发数据", Toast.LENGTH_SHORT).show();
            }
        });

        InputStream inputStream = null;
        try {
            inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) != -1){
                final String s = new String(bytes, 0, len);
                context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, "接收的数据是: "+s, Toast.LENGTH_SHORT).show();
                    }
                });
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

5. 适配器布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="8dp">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp" />

</LinearLayout>

编辑时间: 2019年7月23日21:29:42
Demo下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值