欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现蓝牙的搜索,配对(不需要输入PIN,自动匹配),连接,通信

程序员文章站 2022-05-25 15:48:33
android实现蓝牙的搜索,配对(不需要输入pin,自动匹配),连接,通信 一、蓝牙设置权限 需要在androidmanifest.xml配置获得蓝牙权限。 按照sdk说明需要下面两个权限就可以进...

android实现蓝牙的搜索,配对(不需要输入pin,自动匹配),连接,通信

一、蓝牙设置权限

需要在androidmanifest.xml配置获得蓝牙权限。
按照sdk说明需要下面两个权限就可以进行蓝牙的开发。

 
    

在android6.0之后为了更好的保护用户的数据安全,所有需要访问硬件唯一标识符的地方都需要申请位置权限,也就是需要申请以下权限


    

二、蓝牙搜索

1.首先需要获得蓝牙适配器。

mbluetoothadapter = bluetoothadapter.getdefaultadapter();

2.判断蓝牙是否打开,然后请求打开蓝牙

private void openbluetooth() {
        if (!mbluetoothadapter.isenabled()) {
            //通过这个方法来请求打开我们的蓝牙设备
           intent intent = new intent(bluetoothadapter.action_request_enable);
           startactivityforresult(intent,bluetooth_response);
        }
    }

通过这个方法可以判断是否允许打开蓝牙,然后进行下面相应的操作

case bluetooth_response:
    if(resultcode == result_ok){
        //获得蓝牙权限成功
        //需要再写一次,oncreate里的下面的方法无法执行
        duringdialog("正在连接蓝牙!");
        //搜索蓝牙
        searchbluetooth();
     }else if(resultcode == result_canceled){
        //获得蓝牙权限失败
        toast(controlparkingactivity.this,"蓝牙权限获取失败,请打开蓝牙!");
     }
     break;

3.搜索蓝牙

如果已经打开蓝牙上面的搜索蓝牙不会执行,所以还需在oncreate方法中写搜索方法

        //请求判断蓝牙是否提前打开
        //如果没有提前打开则不会执行这句,执行openbluetooth的响应结果
        //如果提前打开则执行下面
        if(mbluetoothadapter.isenabled()){
            duringdialog("正在连接蓝牙!");
            searchbluetooth();
        }

搜索蓝牙方法如下:

//搜索蓝牙设备
        private void searchbluetooth() {
        //判断蓝牙是否已经绑定
        if(isbond()){
            log.d(tag,"蓝牙已经绑定");
            //已经绑定,直接连接蓝牙
            log.d(tag,device.getname() + "1");

        }else{
            log.d(tag,"搜索蓝牙中");
            //搜索蓝牙设备
            mbluetoothadapter.startdiscovery();
        }
    }

三、蓝牙配对

蓝牙配对是通过广播接收器,搜索附近蓝牙设备,通过判断设备的address和name来判断是否为目标设备。之后利用clsutils工具类实现自动匹配蓝牙设备的功能。

1.动态注册广播接收器

        mbluetoothreceiver = new bluetoothreceiver();
        // 动态注册注册广播接收器。接收蓝牙发现讯息
        intentfilter btfilter = new intentfilter();
        btfilter.setpriority(1000);
        btfilter.addaction(bluetoothdevice.action_found);
        btfilter.addaction(bluetoothdevice.action_pairing_request);
        this.registerreceiver(mbluetoothreceiver,btfilter);

        //设置广播信息接口监听器
        mbluetoothreceiver.setreceivermessagelistener(this);

setpriority(1000):设置优先级,如果优先级比较低可能仍然会弹出输入pin的对话框
bluetoothdevice.action_found:发现设备时的action
bluetoothdevice.action_pairing_request:当调用createbond()后就会发起bluetoothdevice.action_pairing_request的广播

2.判断蓝牙设备是否为目标设备,并且创建绑定

        //获得action
        string action=intent.getaction();
        //获取设备
        device = intent.getparcelableextra(bluetoothdevice.extra_device);
        //获取搜索到的设备的名称和地址
        string name = device.getname();
        string address = device.getaddress();

        if(action.equals(bluetoothdevice.action_found))
        {
            log.d(tag, "发现设备:" + name);

            if ((name != null && btname.equals(name)) || btaddress.equals(address)) {
                //判断远程设备是否已经被绑定
                if(device.getbondstate() != bluetoothdevice.bond_bonded){
                    log.d(tag, "发现目标设备,开始配对!");
                    try {
                        // 调用配对的方法,此方法是异步的,系统会触发bluetoothdevice.action_pairing_request的广播
                        // 收到此广播后,设置配对的密码
                        clsutils.createbond(bluetoothdevice.class, device);

                    } catch (exception e) {
                        e.printstacktrace();
                    }
                }else{
                    //远程设备已经被绑定,取消搜索,返回信息

                }


            }

3.利用clsutils和事先获得的pin进行配对

else if(action.equals("android.bluetooth.device.action.pairing_request")){
            //createbond后再次得到action,就会等于pairing_request
            log.d(tag,"action2 = " + action);
            log.d(tag, "发现设备:" + device.getaddress() + " " + device.getname());

            if ((name != null && name.equals(btname)) || address.equals(btaddress)) {
                log.d(tag, "发现目标设备,开始配对!");
                try {

                    //1.确认配对
//                    clsutils.setpairingconfirmation(device.getclass(), device, true);
//                    //2.终止有序广播
//                    log.i("order...", "isorderedbroadcast:"+isorderedbroadcast()+",isinitialstickybroadcast:"+isinitialstickybroadcast());
                    abortbroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
                    //3.调用setpin方法进行配对...
                    boolean ret = clsutils.setpin(device.getclass(), device, pin);
                    mreceivermessage.setmessage(device);

                } catch (exception e) {
                    // todo auto-generated catch block
                    e.printstacktrace();
                    log.d(tag,"action2 = 配对失败!");
                }
            }else {
                //提示不是目标设备
                log.d(tag,"action2 = 不是目标设备!");
            }
        }

4.将绑定状态返回给activity,通知其绑定成功,可以进行蓝牙连接

广播中无法直接调用蓝牙连接的方法,在试了很多种方法后,最后通过接口实现了广播向activity传值的功能。

在bluetoothreceiver中写接口和接口监听器

public interface bluetoothreceivermessage{
        public void setmessage(bluetoothdevice device);
    }

    public void setreceivermessagelistener(bluetoothreceivermessage bluetoothreceivermessage){
        this.mreceivermessage = bluetoothreceivermessage;
    }

绑定成功后,向activity发送消息(绑定设备)

mreceivermessage.setmessage(device);

首先activity中要设置广播信息接口监听器

        //设置广播信息接口监听器
        mbluetoothreceiver.setreceivermessagelistener(this);

在activity中需要实现bluetoothreceivermessage接口,重写对应的方法,进行蓝牙连接操作。

public class controlparkingactivity extends appcompatactivity implements bluetoothreceiver.bluetoothreceivermessage

@override
    public void setmessage(bluetoothdevice device) {
        if(device != null){
            log.d(tag,"蓝牙绑定成功,开始连接!");
            this.device = device;
            mchatservice.connect(device,true);
        }
    }

四、蓝牙连接和通信

利用google官方的bluetoothservice进行蓝牙的连接和通信。

1.初始化bluetoothservice

mchatservice = new bluetoothchatservice(this, mhandler);

2.通过handle获取bluetoothservice返回的信息和接收的数据

private final handler mhandler = new handler() {
        @override
        public void handlemessage(message msg) {
            switch (msg.what) {
                case message_state_change:
                    switch (msg.arg1) {
                        case bluetoothchatservice.state_connected:
                            //蓝牙已连接

                            break;
                        case bluetoothchatservice.state_connecting:
                            //蓝牙正在连接

                            break;
                        case bluetoothchatservice.state_listen:
                        case bluetoothchatservice.state_none:
                            //蓝牙未连接

                            break;
                    }
                    break;
                case message_write:
                    //发送数据返回的结果

                    break;
                case message_read:
                    byte[] readbuf = (byte[]) msg.obj;
                    // construct a string from the valid bytes in the buffer
                    string readmessage = new string(readbuf, 0, msg.arg1);
                    //读取数据

                case message_device_name:
                    // 保存已连接的设备名称
                    mconnecteddevicename = msg.getdata().getstring(device_name);
                    toast.maketext(getapplicationcontext(), "connected to "
                            + mconnecteddevicename, toast.length_short).show();

                    break;
                case message_toast:

                    break;
            }
        }
    };

3.向蓝牙设备发送数据

private void sendmessage(string message) {
        // check that we're actually connected before trying anything
        if (mchatservice.getstate() != bluetoothchatservice.state_connected) {
            toast.maketext(this, r.string.not_connected, toast.length_short).show();
            return;
        }

        // check that there's actually something to send
        if (message.length() > 0) {
            // get the message bytes and tell the bluetoothchatservice to write
            byte[] send = message.getbytes();
            mchatservice.write(send);
        }
    }

五、结束连接、通信

动态注册广播需要在活动结束时解除注册,如果有需要也可以调用clsutils.removebond解除绑定。

@override
    protected void ondestroy() {
        super.ondestroy();
        mbluetoothadapter.canceldiscovery();
        unregisterreceiver(mbluetoothreceiver);
        try {
            log.d(tag,device + "  " + device.getbondstate());
            clsutils.removebond(device.getclass(), device);
        } catch (exception e) {
            log.d(tag,"解除绑定失败!");
            e.printstacktrace();
        }
    }

六、另附bluetoothchatservice代码

/*
 * copyright (c) 2009 the android open source project
 *
 * licensed under the apache license, version 2.0 (the "license");
 * you may not use this file except in compliance with the license.
 * you may obtain a copy of the license at
 *
 *      https://www.apache.org/licenses/license-2.0
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 */

package com.example.sharingparking.utils;

import android.bluetooth.bluetoothadapter;
import android.bluetooth.bluetoothdevice;
import android.bluetooth.bluetoothserversocket;
import android.bluetooth.bluetoothsocket;
import android.content.context;
import android.os.bundle;
import android.os.handler;
import android.os.message;
import android.util.log;

import com.example.sharingparking.activity.controlparkingactivity;

import java.io.ioexception;
import java.io.inputstream;
import java.io.outputstream;
import java.util.uuid;

/**
 * this class does all the work for setting up and managing bluetooth
 * connections with other devices. it has a thread that listens for
 * incoming connections, a thread for connecting with a device, and a
 * thread for performing data transmissions when connected.
 */
public class bluetoothchatservice{
    // debugging
    private static final string tag = "bluetoothchatservice";
    private static final boolean d = true;

    // name for the sdp record when creating server socket
    private static final string name_secure = "bluetoothchatsecure";
    private static final string name_insecure = "bluetoothchatinsecure";

    // unique uuid for this application
    private static final uuid my_uuid_secure =
        uuid.fromstring("00001101-0000-1000-8000-00805f9b34fb");
    private static final uuid my_uuid_insecure =
        uuid.fromstring("00001101-0000-1000-8000-00805f9b34fb");

    // member fields
    private final bluetoothadapter madapter;
    private final handler mhandler;
    private acceptthread msecureacceptthread;
    private acceptthread minsecureacceptthread;
    private connectthread mconnectthread;
    private connectedthread mconnectedthread;
    private int mstate;

    // constants that indicate the current connection state
    public static final int state_none = 0;       // 蓝牙未连接
    public static final int state_listen = 1;     // 正在监听来的连接
    public static final int state_connecting = 2; // 正在连接
    public static final int state_connected = 3;  // 已经连接

    /**
     * constructor. prepares a new mainactivity session.
     * @param context  the ui activity context
     * @param handler  a handler to send messages back to the ui activity
     */
    public bluetoothchatservice(context context, handler handler) {
        madapter = bluetoothadapter.getdefaultadapter();
        mstate = state_none;
        mhandler = handler;
    }

    /**
     * set the current state of the chat connection
     * @param state  an integer defining the current connection state
     */
    private synchronized void setstate(int state) {
        if (d) log.d(tag, "setstate() " + mstate + " -> " + state);
        mstate = state;

        //通过handle返回给主活动连接状态
        mhandler.obtainmessage(controlparkingactivity.message_state_change, state, -1).sendtotarget();
    }

    /**
     * return the current connection state. */
    public synchronized int getstate() {
        return mstate;
    }

    /**
     * start the chat service. specifically start acceptthread to begin a
     * session in listening (server) mode. called by the activity onresume() */
    public synchronized void start() {
        if (d) log.d(tag, "start");

        // cancel any thread attempting to make a connection
        if (mconnectthread != null)
        {
            mconnectthread.cancel();
            mconnectthread = null;
        }

        // cancel any thread currently running a connection
        if (mconnectedthread != null) 
        {
            mconnectedthread.cancel(); 
            mconnectedthread = null;
        }

        setstate(state_listen);

        // start the thread to listen on a bluetoothserversocket
        if (msecureacceptthread == null) 
        {
            msecureacceptthread = new acceptthread(true);
            msecureacceptthread.start();
        }
        if (minsecureacceptthread == null) 
        {
            minsecureacceptthread = new acceptthread(false);
            minsecureacceptthread.start();
        }
    }

    /**
     * start the connectthread to initiate a connection to a remote device.
     * @param device  the bluetoothdevice to connect
     * @param secure socket security type - secure (true) , insecure (false)
     */
    public synchronized void connect(bluetoothdevice device, boolean secure) {
        if (d) log.d(tag, "connect to: " + device);

        // cancel any thread attempting to make a connection
        if (mstate == state_connecting) {
            if (mconnectthread != null) {mconnectthread.cancel(); mconnectthread = null;}
        }

        // cancel any thread currently running a connection
        if (mconnectedthread != null) {mconnectedthread.cancel(); mconnectedthread = null;}

        // start the thread to connect with the given device
        mconnectthread = new connectthread(device, secure);
        mconnectthread.start();
        setstate(state_connecting);
    }

    /**
     * start the connectedthread to begin managing a bluetooth connection
     * @param socket  the bluetoothsocket on which the connection was made
     * @param device  the bluetoothdevice that has been connected
     */
    public synchronized void connected(bluetoothsocket socket, bluetoothdevice
            device, final string sockettype) {
        if (d) log.d(tag, "connected, socket type:" + sockettype);

        // cancel the thread that completed the connection
        if (mconnectthread != null) {mconnectthread.cancel(); mconnectthread = null;}

        // cancel any thread currently running a connection
        if (mconnectedthread != null) {mconnectedthread.cancel(); mconnectedthread = null;}

        // cancel the accept thread because we only want to connect to one device
        if (msecureacceptthread != null) {
            msecureacceptthread.cancel();
            msecureacceptthread = null;
        }
        if (minsecureacceptthread != null) {
            minsecureacceptthread.cancel();
            minsecureacceptthread = null;
        }

        // start the thread to manage the connection and perform transmissions
        mconnectedthread = new connectedthread(socket, sockettype);
        mconnectedthread.start();

        // send the name of the connected device back to the ui activity
        message msg = mhandler.obtainmessage(controlparkingactivity.message_device_name);
        bundle bundle = new bundle();
        bundle.putstring(controlparkingactivity.device_name, device.getname());
        msg.setdata(bundle);
        mhandler.sendmessage(msg);

        setstate(state_connected);
    }

    /**
     * stop all threads
     */
    public synchronized void stop() {
        if (d) log.d(tag, "stop");

        if (mconnectthread != null) {
            mconnectthread.cancel();
            mconnectthread = null;
        }

        if (mconnectedthread != null) {
            mconnectedthread.cancel();
            mconnectedthread = null;
        }

        if (msecureacceptthread != null) {
            msecureacceptthread.cancel();
            msecureacceptthread = null;
        }

        if (minsecureacceptthread != null) {
            minsecureacceptthread.cancel();
            minsecureacceptthread = null;
        }
        setstate(state_none);
    }

    /**
     * write to the connectedthread in an unsynchronized manner
     * @param out the bytes to write
     * @see connectedthread#write(byte[])
     */
    public void write(byte[] out) {
        // create temporary object
        connectedthread r;
        // synchronize a copy of the connectedthread
        synchronized (this) {
            if (mstate != state_connected) return;
            r = mconnectedthread;
        }
        // perform the write unsynchronized
        r.write(out);
    }

    /**
     * indicate that the connection attempt failed and notify the ui activity.
     */
    private void connectionfailed() {
        // send a failure message back to the activity
        message msg = mhandler.obtainmessage(controlparkingactivity.message_toast);
        bundle bundle = new bundle();
        bundle.putstring(controlparkingactivity.toast, "unable to connect device");
        msg.setdata(bundle);
        mhandler.sendmessage(msg);

        // start the service over to restart listening mode
        bluetoothchatservice.this.start();
    }

    /**
     * indicate that the connection was lost and notify the ui activity.
     */
    private void connectionlost() {
        // send a failure message back to the activity
        message msg = mhandler.obtainmessage(controlparkingactivity.message_toast);
        bundle bundle = new bundle();
        bundle.putstring(controlparkingactivity.toast, "device connection was lost");
        msg.setdata(bundle);
        mhandler.sendmessage(msg);

        // start the service over to restart listening mode
        bluetoothchatservice.this.start();
    }

    /**
     * this thread runs while listening for incoming connections. it behaves
     * like a server-side client. it runs until a connection is accepted
     * (or until cancelled).
     */
    private class acceptthread extends thread {
        // the local server socket
        private final bluetoothserversocket mmserversocket;
        private string msockettype;

        public acceptthread(boolean secure) {
            bluetoothserversocket tmp = null;
            msockettype = secure ? "secure":"insecure";

            // create a new listening server socket
            try {
                if (secure) {
                    tmp = madapter.listenusingrfcommwithservicerecord(name_secure,
                        my_uuid_secure);
                } else {
                    tmp = madapter.listenusinginsecurerfcommwithservicerecord(
                            name_insecure, my_uuid_insecure);
                }
            } catch (ioexception e) {
                log.e(tag, "socket type: " + msockettype + "listen() failed", e);
            }
            mmserversocket = tmp;
        }

        public void run() {
            if (d) log.d(tag, "socket type: " + msockettype +
                    "begin macceptthread" + this);
            setname("acceptthread" + msockettype);

            bluetoothsocket socket = null;

            // listen to the server socket if we're not connected
            while (mstate != state_connected) {
                try {
                    // this is a blocking call and will only return on a
                    // successful connection or an exception
                    socket = mmserversocket.accept();
                } catch (ioexception e) {
                    log.e(tag, "socket type: " + msockettype + "accept() failed", e);
                    break;
                }

                // if a connection was accepted
                if (socket != null) {
                    synchronized (bluetoothchatservice.this) {
                        switch (mstate) {
                        case state_listen:
                        case state_connecting:
                            // situation normal. start the connected thread.
                            connected(socket, socket.getremotedevice(),
                                    msockettype);
                            break;
                        case state_none:
                        case state_connected:
                            // either not ready or already connected. terminate new socket.
                            try {
                                socket.close();
                            } catch (ioexception e) {
                                log.e(tag, "could not close unwanted socket", e);
                            }
                            break;
                        }
                    }
                }
            }
            if (d) log.i(tag, "end macceptthread, socket type: " + msockettype);

        }

        public void cancel() {
            if (d) 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);
            }
        }
    }


    /**
     * this thread runs while attempting to make an outgoing connection
     * with a device. it runs straight through; the connection either
     * succeeds or fails.
     */
    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";

            // get a bluetoothsocket for a connection with the
            // given bluetoothdevice
            try {
                if (secure) {
                    tmp = device.createrfcommsockettoservicerecord(
                            my_uuid_secure);
                } else {
                    tmp = device.createinsecurerfcommsockettoservicerecord(
                            my_uuid_insecure);
                }
            } catch (ioexception e) {
                log.e(tag, "socket type: " + msockettype + "create() failed", e);
            }
            mmsocket = tmp;
        }

        public void run() {
            log.i(tag, "begin mconnectthread sockettype:" + msockettype);
            setname("connectthread" + msockettype);

            // always cancel discovery because it will slow down a connection
            madapter.canceldiscovery();

            // 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();
            } catch (ioexception e) {
                // close the socket
                try {
                    mmsocket.close();
                } catch (ioexception e2) {
                    log.e(tag, "unable to close() " + msockettype +
                            " socket during connection failure", e2);
                }
                connectionfailed();
                return;
            }

            // reset the connectthread because we're done
            synchronized (bluetoothchatservice.this) {
                mconnectthread = null;
            }

            // start the connected thread
            connected(mmsocket, mmdevice, msockettype);
        }

        public void cancel() {
            try {
                mmsocket.close();
            } catch (ioexception e) {
                log.e(tag, "close() of connect " + msockettype + " socket failed", e);
            }
        }
    }

    /**
     * this thread runs during a connection with a remote device.
     * it handles all incoming and outgoing transmissions.
     */
    private class connectedthread extends thread {
        private final bluetoothsocket mmsocket;
        private final inputstream mminstream;
        private final outputstream mmoutstream;

        public connectedthread(bluetoothsocket socket, string sockettype) {
            log.d(tag, "create connectedthread: " + sockettype);
            mmsocket = socket;
            inputstream tmpin = null;
            outputstream tmpout = null;

            // get the bluetoothsocket input and output streams
            try {
                tmpin = socket.getinputstream();
                tmpout = socket.getoutputstream();
            } catch (ioexception e) {
                log.e(tag, "temp sockets not created", e);
            }

            mminstream = tmpin;
            mmoutstream = tmpout;
        }

        public void run() {
            log.i(tag, "begin mconnectedthread");
            byte[] buffer = new byte[1024];
            int bytes;

            // keep listening to the inputstream while connected
            while (true) {
                try {
                    // read from the inputstream
                    bytes = mminstream.read(buffer);

                    // send the obtained bytes to the ui activity
                    mhandler.obtainmessage(controlparkingactivity.message_read, bytes, -1, buffer).sendtotarget();
                } catch (ioexception e) {
                    log.e(tag, "disconnected", e);
                    connectionlost();
                    // start the service over to restart listening mode
                    bluetoothchatservice.this.start();
                    break;
                }
            }
        }

        /**
         * write to the connected outstream.
         * @param buffer  the bytes to write
         */
        public void write(byte[] buffer) {
            try {
                mmoutstream.write(buffer);

                // share the sent message back to the ui activity
                mhandler.obtainmessage(controlparkingactivity.message_write, -1, -1, buffer).sendtotarget();
            } catch (ioexception e) {
                log.e(tag, "exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmsocket.close();
            } catch (ioexception e) {
                log.e(tag, "close() of connect socket failed", e);
            }
        }
    }

}