1. 程式人生 > >Android 普通藍芽學習筆記

Android 普通藍芽學習筆記

Android 普通藍芽學習

雖然做開發有一段時間了,但是有關藍芽方面一直接觸的不多,正好目前有一個關於藍芽開發的需求,雖然是用到的BLE和普通藍芽有些區別,但是既然學習了就順便把普通藍芽也學習一下,也為了以後自己少走些彎路,先將這些學習筆記學習下來。官方文件

本例的原始碼已經上傳,檢視原始碼

需要的許可權

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

藍芽有關的所有的類如下:

android藍芽的類

普通藍芽用到的幾個關鍵的類:

  • BluetoothAdapter 藍芽介面卡

    Represents the local device Bluetooth adapter. The BluetoothAdapter lets you perform fundamental Bluetooth tasks, such as initiate device discovery,

    query a list of bonded (paired) devices, instantiate a BluetoothDevice using a known MAC address, and create a BluetoothServerSocket to listen for

    connection requests from other devices, and start a scan for Bluetooth LE devices.

    根據官方文件的說明,BluetoothAdapter可以執行基本的藍芽任務,比如啟動裝置發現,查詢已配對的藍芽列表,使用已知的地址例項化一個BluetoothDevice,建立一個BluetoothServerSocket

    監聽連結請求等。

  • BluetoothDevice 藍芽裝置

    Represents a remote Bluetooth device. A BluetoothDevice lets you create a connection with the respective device or query information about it,

    such as the name, address, class, and bonding state.

    代表一個遠端藍芽裝置。BluetoothDevice允許建立一個連線的裝置或查詢相關資訊,如名稱、地址、階級和配對的狀態。

  • BluetoothSocket

    The interface for Bluetooth Sockets is similar to that of TCP sockets: Socket and ServerSocket.

    顧名思義藍芽連線

  • BluetoothServerSocket

    The interface for Bluetooth Sockets is similar to that of TCP sockets: Socket and ServerSocket.

    藍芽服務連結,後兩者都是和TCP埠類似的一個socket

首先開啟藍芽開始搜尋等;

主要用到的幾個方法:

  • getDefaultAdapter() 獲取一個介面卡物件

  • getName() 獲取本地藍芽名稱

  • getAddress() 獲取本地藍芽的地址

  • enable() 開啟本地藍芽(低版本中不會提示使用者)

  • isEnabled() 判斷藍芽是否已經開啟

  • disable() 關閉本地藍芽

  • startDiscovery() 開始搜尋(發現)

  • cancelDiscovery() 取消裝置搜尋(發現)

  • isDiscovering() 返回當前是否是在搜尋裝置

  • listenUsingRfcommWithServiceRecord(String name, UUID uuid) 建立一個安全的BluetoothServerSocket

開啟藍芽

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //開啟藍芽 方法一
        if (!bluetoothAdapter.isEnabled()) {
            bluetoothAdapter.enable();
        }

        //方法二 推薦
        Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enabler, REQUEST_ENABLE);

開始搜尋裝置

呼叫startDiscovery()開始搜尋裝置,但是僅僅呼叫此方法是沒有任何作用的,startDiscovery()是非同步呼叫,立即返回,需要註冊一個廣播接收者

來接受搜尋的結果。整個搜尋過程持續12秒。


//註冊
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, intentFilter);

//廣播接收者
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);
                Log.d("MainActivity", "搜尋到裝置");
                //在列表中顯示搜尋出的裝置
                adapter.add("name : " + device.getName() + "\n address : " + device.getAddress());
                bluetoothDevices.add(device);
            }
            //搜尋完成
            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
                    .equals(action)) {
                Log.d("MainActivity", "搜尋結束");
            } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
                Log.d("MainActivity", "開始搜尋");
            }
        }
    };

連線裝置

建立連線,Android sdk支援的藍芽連線是通過BluetoothSocket建立連線,伺服器端(BluetoothServerSocket)和客戶端(BluetoothSocket)需指定同樣的UUID,才能建立連線,因為建立連線的方法會阻塞執行緒,所以伺服器端和客戶端都應啟動新執行緒連線。

UUID的格式如下:

String uuid = "a60f35f0-b93a-11de-8a39-08002009c666";

建立伺服器端程式碼如下:

首先建立伺服器,獲取BluetoothServerSocket物件,通過BluetoothAdapterlistenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)方法和listenUsingRfcommWithServiceRecord(String name, UUID uuid)方法,其中前者是不安全的連結,後者是安全的連結。

然後使用BluetoothServerSocket.accept()方法接受客戶端連線,當連線成功返回一個BluetoothSocket物件。

    private class ServiceThread extends Thread {
        @Override
        public void run() {

            BluetoothServerSocket serverSocket = null;
            try {
                serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("my_test_lianjie", UUID.fromString(uuid));
                Log.d("ServiceThread", "建立伺服器成功");
            } catch (IOException e) {
                e.printStackTrace();
                Log.d("ServiceThread", "建立伺服器失敗");
            }

            try {
                socket = serverSocket.accept();
                Log.d("ServiceThread", "客戶端連線成功");
                new ReadThread().start();
            } catch (IOException e) {
                e.printStackTrace();
                Log.d("ServiceThread", "客戶端連線失敗");
            }
        }
    }

建立客戶端連結程式碼如下:

這裡需要注意的是要對首先檢測裝置是否進行了配對,只有首先進行配對才能進行連線。藍芽配對是通過反射的方法呼叫BluetoothDevice.creMethod()方法。

建立連線首先獲取BluetoothSocket物件,呼叫BluetoothDevicecreateInsecureRfcommSocketToServiceRecord(UUID uuid)或者createRfcommSocketToServiceRecord(UUID uuid)方法,其中前者是不安全的連結,後者是安全的連結。

然後呼叫BluetoothSocket.connect()方法進行連線。

    private class ConnectThread extends Thread {

        BluetoothDevice device;

        public ConnectThread(BluetoothDevice device) {
            this.device = device;
        }

        @Override
        public void run() {

            try {
                socket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
            } catch (IOException e) {
                e.printStackTrace();
            }


            if (device.getBondState() == BluetoothDevice.BOND_BONDED) { //已配對裝置 直接進行連結
                connectSocket();
            } else if (device.getBondState() == BluetoothDevice.BOND_NONE) { //未配對裝置 先配對再連結
                Method creMethod = null;
                try {
                    creMethod = BluetoothDevice.class.getMethod("createBond");
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
                Log.e("TAG", "開始配對");
                try {
                    creMethod.invoke(device);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    Log.e("TAG", "配對失敗");
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

        private void connectSocket() {
            try {
                socket.connect();
                Log.e("TAG", "連線成功");
                new ReadThread().start();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("TAG", "連線失敗");
            }
        }

        public void cancel() {
            try {
                socket.close();
                socket = null;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }

注意

客戶端建立連線的方式有很多種,這裡使用的是先獲得一個socket然後再檢查是否需要進行配對,再建立連線。

還可以通過反射的方法,通過埠進行連線。

進行通訊

藍芽通訊是通過流的方式進行的:

OutputStream outS = socket.getOutputStream();

InputStream inS = socket.getInputStream();

傳送的方法如:

                OutputStream os = null;
                try {
                    os = socket.getOutputStream();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    os.write("你好".getBytes());
                    Log.d("MainActivity", "傳送成功");
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d("MainActivity", "傳送失敗");
                }

接受的方法如:

    private class ReadThread extends Thread {
        @Override
        public void run() {
            byte[] buffer = new byte[1024];
            int bytes;
            InputStream mmInStream = null;

            try {
                mmInStream = socket.getInputStream();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            while (true) {
                try {
                    // Read from the InputStream
                    if ((bytes = mmInStream.read(buffer)) > 0) {
                        byte[] buf_data = new byte[bytes];
                        for (int i = 0; i < bytes; i++) {
                            buf_data[i] = buffer[i];
                        }
                        String s = new String(buf_data);
                        Log.d("ReadThread", s);
                    }
                } catch (IOException e) {
                    try {
                        mmInStream.close();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                    break;
                }
            }
        }
    }

至此,普通藍芽的基本發現、連線、通訊功能就完成了,當然還有許多需要完善的地方。

寫的可能有些混亂,不足之處,還請指正,不喜忽噴。

相關推薦

Android 普通學習筆記

Android 普通藍芽學習 雖然做開發有一段時間了,但是有關藍芽方面一直接觸的不多,正好目前有一個關於藍芽開發的需求,雖然是用到的BLE和普通藍芽有些區別,但是既然學習了就順便把普通藍芽也學習一下,也為了以後自己少走些彎路,先將這些學習筆記學習下來。官方文件

學習筆記之例項廣播資料的解析

轉載自:https://blog.csdn.net/sinat_23338865/article/details/52170581 BLE 裝置工作的第一步就是向外廣播資料。廣播資料中帶有裝置相關的資訊。 本文主要說一下 BLE 的廣播中的資料的規範以及廣播包的解析,這是我們專案中的廣播資料

nrf51822學習筆記之例項分析PPI和SHORT

首先開啟PPI程式看到如下  刪除串列埠初始化部分方便檢視: 一、初始化定時器的方式 TIMER可以處於兩種模式: 1定時模式(Timer mode) 2計數模式(Counter mode)

Android BLE 學習總結(一):手機作為周邊BluetoothGattServer的實現

低功耗藍芽的基本概念: 在BLE協議中,有兩個角色,周邊(Periphery)和中央(Central)。周邊是資料的提供者,中央是資料的使用和處理者。在Android SDK裡面,Android4.3以後手機可以作為中央使用;Android5.0以後手機才可以

學習筆記之建立連線的過程

傳送廣播資料包的叫廣播發起者(advertisers),在廣播通道接收廣播資料包但沒意向連線廣播發起裝置的叫掃描者( scanners), 需要連線到另一個裝置的裝置叫做 initiators,它監聽可連線的廣播資料包。如果advertiser正在使用一個可連線的廣播事件

Android APK安裝過程學習筆記

屏蔽 組成 學習 二進制 替換 壓縮包 基於 壓縮 方式 1.什麽是APK   APK,即Android Package,Android安裝包。不同平臺的安裝文件格式都不同,類似於Windows的安裝包是二進制的exe格式,Mac的安裝包是dmg格式。APK可以再Andro

Android異步載入學習筆記之四:利用緩存優化網絡載入圖片及ListView載入優化

角度 thread 下午 出發 easy code cat height back 假設不做不論什麽處理。直接用網絡載入圖片在網速快的情況下可能沒什麽不好的感覺。可是假設使用移動流量或是網絡不好的時候。問題就來了,要麽用戶會抱怨流量使用太多。要麽抱怨圖

Android Bluetooth 強度Rssi

轉自 https://blog.csdn.net/lhc1105/article/details/54585632 轉自 https://blog.csdn.net/jasonwang18/article/details/73131020 轉自 http://www.cnblogs.co

Android獲取地址(非mac地址)

方法: public static String getBlueToothAddress(Context context){ return android.provider.Settings.Secure.getString(context.getContentResol

Android BLE 快速開發框架。

FastBle 專案地址:Jasonchenlijian/FastBle  簡介:Android BLE 藍芽快速開發框架。 更多:作者   提 Bug    標籤: 藍芽- Thanks to th

Android手機總結之傳統

出處:Android手機藍芽總結之傳統藍芽   最近,公司有一個專案時關於手機藍芽和硬體藍芽相互通訊的需求。基於之前很久沒有學習硬體的知識,這次記錄下來,以備下次需要時使用。 首先,需要搞清楚一些基本的概要,藍芽3.0以前的是傳統藍芽,4.0以後的是低功耗藍芽,Android藍

Android BLE4.0開發—Android手機與BLE終端通訊

轉載自: https://blog.csdn.net/fu908323236/article/details/76208997 這篇部落格主要講解AndroidBLE藍芽4.0的基本概念,以及基礎用法。  BLE 即 Bluetooth Low Energy,藍芽低功耗技術,是藍芽

Android群英傳》學習筆記Android體系與系統架構

一、Android系統架構 1.Linux核心層 Android核心系統服務依賴於Linux2.6核心,如安全性、記憶體管理、程序管理、網路協議棧和驅動模型。Linux核心也是作為硬體與軟體棧的抽象層

Android群英傳》學習筆記Android控制元件架構與自定義控制元件詳解

一、Android控制元件架構: 控制元件大致分為兩類:ViewGroup控制元件與View控制元件。View是繪製在螢幕上的使用者能與之互動的一個物件。而ViewGroup則是一個用於存放其他Vi

Android群英傳》學習筆記之Activity與Activity呼叫棧分析

一、Activity 1、Activity形態: Active/Running 處於棧頂,可互動。 Paused 被遮擋但未被完全覆蓋,失去焦點,不可互動。 Stopped 被完全覆蓋,但保持了所有狀

學習 (8)配對raspberryPi和SensorTag CC2650

這裡我們利用gatttool來配對。 [email protected]:~ $ gatttool --help Usage: gatttool [OPTION...] Application Options: -i, --adapter=

學習(五)-- 低功耗(BLE)主機:屬性、服務

 在BLE中服務、屬性、特性、行為很難理解。講得極其抽象,讓我疑惑的是它是一種邏輯上面的概念還是資料結構上的概念? 服務是一種或多種特性的組合,特性則由一種或多種屬性組成 BLE的對於服務上的概念上居然是來源於“面向物件程式設計(OOP)”: 類 物件 屬

學習(四)-- 低功耗(BLE)鏈路層資料包

octet : 八位位元組  鏈路層定義了兩個裝置如何利用無線電傳輸資訊。它包含了報文、廣播資料通道的詳細定義,也規定了發現其他裝置的流程、廣播的資料、連線的建立、連線的管理以及連線中的資料傳輸。  下圖是報文的基本結構,適用於所有的報文,無論其用途是什麼。報文一開始是一小段訓練

學習(二)

通訊距離 路徑損耗是指發射機天線到接收機天線的能量消耗,路徑損耗與距離的關係: p a

學習--關係

簡寫 GAP : Generic Access Profile GATT : Generic Attribute Profile ATT : Attribute Protocol HCI : Host-Controller Interface