PC端實現藍牙開發


藍牙作為一種短距離無線通訊技術,越來越融合到我們的生活當中,軟件開發也是隨處可見。本文介紹的是PC端與其他藍牙設備建立通訊的一個案例。

  藍牙客戶端,即是請求連接的一端,搜索會發現可連接的藍牙設備名稱。

  藍牙服務端,提供服務的一端。往往生活中使用到的藍牙(比如手機是個雙重角色),又是客戶端又是服務端。

藍牙通信的原理

  藍牙技術規定每一對設備之間進行藍牙通訊時,必須一個為主角色,另一為從角色,才能進行通信,通信時,必須由主端進行查找,發起配對,建鏈成功后,雙方即可收發數據。藍牙主端設備發起呼叫,首先是查找,找出周圍處於可被查找的藍牙設備。主端設備找到從端藍牙設備后,與從端藍牙設備進行配對,此時需要輸入從端設備的PIN碼,也有設備不需要輸入PIN碼。

藍牙流程

藍牙客戶端Socket的與Sokcet流程是一樣的,只不過參數不同而已。如下:
1、創建客戶端藍牙Sokcet
2、創建連接
3、讀寫數據
4、關閉

因此又可以視為一個短連接。

一、jar包

首先,在PC端實現藍牙java並沒有提供官方jar包,本文使用的是一個第三方庫。需要手動導入到maven倉庫,

不會導倉庫的請參考https://www.cnblogs.com/zeussbook/p/9930679.htm

第三方jar包下載地址:https://sourceforge.net/projects/bluecove/files/BlueCove/2.1.0/bluecove-2.1.0.jar/download

二、代碼部分

2.1藍牙服務端

package com.shunyutong.test.bluetooth;

import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.StreamConnectionNotifier;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: lanhaifeng
 * @Date: 2020/5/4 0004 16:28
 * @Description: 藍牙服務端
 * @statement:
 */
public class BluetoothServer implements Runnable{

    //本機藍牙設備
    private LocalDevice local = null;
    // 流連接
    private StreamConnection streamConnection = null;

    // 輸入流
    private InputStream inputStream;
    private OutputStream outputStream;
    //接入通知
    private StreamConnectionNotifier notifier;
    //基於緩存的線程池
    private final static ExecutorService service = Executors.newCachedThreadPool();

    public String serverName;
    public String serverUUID;

    private OnServerListener mServerListener;

    /**
     * 服務監聽接口
     */
    public interface OnServerListener {
        void onConnected(InputStream inputStream, OutputStream outputStream);
        void onDisconnected();
        void onClose();
    }

    /**
     * 藍牙服務有參構造函數
     * @param serverUUID id
     * @param serverName 名稱
     */
    public BluetoothServer(String serverUUID, String serverName) {
        this.serverUUID = serverUUID;
        this.serverName = serverName;
    }

    /**
     * 啟動
     */
    public void start() {
        try {
            local = LocalDevice.getLocalDevice();
            if (!local.setDiscoverable(DiscoveryAgent.GIAC))
                System.out.println("請將藍牙設置為可被發現");
            //作為服務端,被請求
            String url = "btspp://localhost:" +  serverUUID+ ";name="+serverName;
            notifier = (StreamConnectionNotifier) Connector.open(url);

            service.submit(this);
        } catch (IOException e) {
            System.out.println(e.getMessage());;
        }
    }


    /**
     * 重寫run()
     */
    @Override
    public void run() {
        try {
            streamConnection = notifier.acceptAndOpen();                //阻塞的,等待設備連接
            inputStream = streamConnection.openInputStream();
            outputStream = streamConnection.openOutputStream();

            if (mServerListener != null) {
                mServerListener.onConnected(inputStream, outputStream);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }


    public OnServerListener getServerListener() {
        return mServerListener;
    }

    public void setServerListener(OnServerListener mServerListener) {
        this.mServerListener = mServerListener;
    }
}

 

2.2藍牙客戶端

package com.shunyutong.test.bluetooth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Set;
import javax.bluetooth.RemoteDevice;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
/**
 * @Auther: lanhaifeng
 * @Date: 2020/5/4 0004 15:37
 * @Description:藍牙客戶端類
 * @statement:
 */
public class BluetoothClient {
    private StreamConnection streamConnection;//流連接
    private OnDiscoverListener onDiscoverListener = null;//發現監聽
    private OnClientListener onClientListener = null;//客戶端監聽

    /**
     * 客戶端監聽
     */
    public interface OnClientListener {
        void onConnected(InputStream inputStream, OutputStream outputStream);
        void onConnectionFailed();
        void onDisconnected();
        void onClose();
    }

    /**
     * 發現監聽
     */
    public interface OnDiscoverListener {
        void onDiscover(RemoteDevice remoteDevice);
    }


    /**
     * 無參構造函數
     */
    public BluetoothClient() {
    }

    /**
     * 查找所有
     * @throws IOException
     * @throws InterruptedException
     */
    public void find() throws IOException, InterruptedException {
        //附近所有的藍牙設備,必須先執行 runDiscovery
        Set<RemoteDevice> devicesDiscovered = RemoteDeviceDiscovery.getDevices();
        Iterator<RemoteDevice> itr = devicesDiscovered.iterator();
        //連接
        while (itr.hasNext()) {
            RemoteDevice remoteDevice = itr.next();

            onDiscoverListener.onDiscover(remoteDevice);
        }
    }

    /**
     * 啟動連接
     * @param remoteDevice
     * @param serviceUUID
     * @throws IOException
     * @throws InterruptedException
     */
    public void startClient(RemoteDevice remoteDevice, String serviceUUID) throws IOException, InterruptedException {
        String url = RemoteDeviceDiscovery.searchService(remoteDevice, serviceUUID);

        streamConnection = (StreamConnection) Connector.open(url);
        if (this.onClientListener != null) {
            this.onClientListener.onConnected(streamConnection.openInputStream(), streamConnection.openOutputStream());
        }
    }

    public OnDiscoverListener getOnDiscoverListener() {
        return onDiscoverListener;
    }


    public void setOnDiscoverListener(OnDiscoverListener onDiscoverListener) {
        this.onDiscoverListener = onDiscoverListener;
    }


    public OnClientListener getClientListener() {
        return onClientListener;
    }


    public void setClientListener(OnClientListener onClientListener) {
        this.onClientListener = onClientListener;
    }


}

 

2.3設備查找類

package com.shunyutong.test.bluetooth;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;

import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
/**
 * @Auther: lanhaifeng
 * @Date: 2020/5/4 0004 16:07
 * @Description:設備查找類
 * @statement:
 */
public class RemoteDeviceDiscovery {

    public final static Set<RemoteDevice> devicesDiscovered = new HashSet<RemoteDevice>();

    public final static Vector<String> serviceFound = new Vector<String>();

    final static Object serviceSearchCompletedEvent = new Object();
    final static Object inquiryCompletedEvent = new Object();


    /**
     * 發現監聽
     */
    private static DiscoveryListener listener = new DiscoveryListener() {
        public void inquiryCompleted(int discType) {
            System.out.println("#" + "搜索完成");
            synchronized (inquiryCompletedEvent) {
                inquiryCompletedEvent.notifyAll();
            }
        }

        /**
         * 發現設備
         * @param remoteDevice
         * @param deviceClass
         */
        @Override
        public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
            devicesDiscovered.add(remoteDevice);

            try {
                System.out.println("#發現設備" + remoteDevice.getFriendlyName(false));
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        /**
         * 發現服務
         * @param transID id
         * @param servRecord 服務記錄
         */
        @Override
        public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
            for (int i = 0; i < servRecord.length; i++) {
                String url = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                if (url == null) {
                    continue;
                }
                serviceFound.add(url);
                DataElement serviceName = servRecord[i].getAttributeValue(0x0100);
                if (serviceName != null) {
                    System.out.println("service " + serviceName.getValue() + " found " + url);
                } else {
                    System.out.println("service found " + url);
                }
            }
            System.out.println("#" + "servicesDiscovered");
        }

        /**
         * 服務搜索已完成
         * @param arg0
         * @param arg1
         */
        @Override
        public void serviceSearchCompleted(int arg0, int arg1) {
            System.out.println("#" + "serviceSearchCompleted");
            synchronized(serviceSearchCompletedEvent){
                serviceSearchCompletedEvent.notifyAll();
            }
        }
    };


    /**
     * 查找設備
     * @throws IOException
     * @throws InterruptedException
     */
    private static void findDevices() throws IOException, InterruptedException {

        devicesDiscovered.clear();

        synchronized (inquiryCompletedEvent) {

            LocalDevice ld = LocalDevice.getLocalDevice();

            System.out.println("#本機藍牙名稱:" + ld.getFriendlyName());

            boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC,listener);

            if (started) {
                System.out.println("#" + "等待搜索完成...");
                inquiryCompletedEvent.wait();
                LocalDevice.getLocalDevice().getDiscoveryAgent().cancelInquiry(listener);
                System.out.println("#發現設備數量:" + devicesDiscovered.size());
            }
        }
    }

    /**
     * 獲取設備
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    public static Set<RemoteDevice> getDevices() throws IOException, InterruptedException {
        findDevices();
        return devicesDiscovered;
    }

    /**
     * 查找服務
     * @param btDevice
     * @param serviceUUID
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    public static String searchService(RemoteDevice btDevice, String serviceUUID) throws IOException, InterruptedException {
        UUID[] searchUuidSet = new UUID[] { new UUID(serviceUUID, false) };

        int[] attrIDs =  new int[] {
                0x0100 // Service name
        };

        synchronized(serviceSearchCompletedEvent) {
            System.out.println("search services on " + btDevice.getBluetoothAddress() + " " + btDevice.getFriendlyName(false));
            LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(attrIDs, searchUuidSet, btDevice, listener);
            serviceSearchCompletedEvent.wait();
        }

        if (serviceFound.size() > 0) {
            return serviceFound.elementAt(0);
        } else {
            return "";
        }
    }
}

 

2.4藍牙服務端使用

package com.shunyutong.test.bluetoothService;

import com.shunyutong.test.bluetooth.BluetoothServer;

import java.io.InputStream;
import java.io.OutputStream;

/**
 * @Auther: lanhaifeng
 * @Date: 2020/5/4 0004 16:47
 * @Description: 藍牙服務端通信業務
 * @statement:
 */
public class BluetoothServerService {

    public static void main(String[] argv) {
        final String serverName = "Bluetooth Server Test";
        final String serverUUID = "1000110100001000800000805F9B34FB";  //根據需要自定義

        BluetoothServer server = new BluetoothServer(serverUUID, serverName);
        server.setServerListener(new BluetoothServer.OnServerListener() {

            @Override
            public void onConnected(InputStream inputStream, OutputStream outputStream) {
                System.out.printf("Connected");
                //添加通信代碼
                System.out.println(server.serverName);
                System.out.println(server.serverUUID);

            }

            @Override
            public void onDisconnected() {

            }

            @Override
            public void onClose() {

            }

        });

        server.start();
    }
}

 

2.5藍牙客戶端使用

package com.shunyutong.test.bluetoothService;

import com.shunyutong.test.bluetooth.BluetoothClient;

import javax.bluetooth.RemoteDevice;
import javax.microedition.io.ConnectionNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;

/**
 * @Auther: lanhaifeng
 * @Date: 2020/5/4 0004 16:51
 * @Description: 藍牙客戶端業務類
 * @statement:
 */
public class BluetoothClientService {

    public static void main(String[] argv) {

        final String serverUUID = "1000110100001000800000805F9B34FB"; //需要與服務端相同

        BluetoothClient client = new BluetoothClient();

        Vector<RemoteDevice> remoteDevices = new Vector<>();

        client.setOnDiscoverListener(new BluetoothClient.OnDiscoverListener() {

            @Override
            public void onDiscover(RemoteDevice remoteDevice) {
                remoteDevices.add(remoteDevice);
            }

        });

        client.setClientListener(new BluetoothClient.OnClientListener() {

            @Override
            public void onConnected(InputStream inputStream, OutputStream outputStream) {
                System.out.printf("Connected");
                //添加通信代碼

            }

            @Override
            public void onConnectionFailed() {
                System.out.printf("Connection failed");
            }

            @Override
            public void onDisconnected() {

            }

            @Override
            public void onClose() {

            }

        });

        try {
            client.find();

            if (remoteDevices.size() > 0 ) {

                client.startClient(remoteDevices.firstElement(), serverUUID);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }catch (ConnectionNotFoundException e){
            System.out.println("當前藍牙不在線");
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

測試效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM