Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中經典藍牙開發步驟 (流程)

Android中經典藍牙開發步驟 (流程)

編輯:關於Android編程

藍牙在我們做智能手表中,必須使用到的。即使不同的需求開發,但也可以抽取出下面的步驟。

下面的流程,如果已經完成了這一步,就可以去到下一步。比如說,已經打開了藍牙,那麼藍牙肯定是可用的。這才真的沒必要檢測藍牙是否可用了。

如果已經打開了,當然也沒有必要再次執行打開的代碼啦!是吧!又比如說,已經配對了藍牙,就沒必要再配對了。在連接之前進行檢查一下就可以了嘛!

權限:

1、檢查是否支持藍牙設備:

我們通過BluetoothAdapter這個類去獲取適配器,如果沒有則不支持藍牙通信,也就是該設備沒有藍牙模塊。

不管是我們自己的設備一定有藍牙還是別人的設備知道一定有。大家都要養成習慣,在使用之前檢查一下是否支持藍牙。

    /**
     * 參數 無
     * 返回值 true 表示可以用嘛,否則不可以
     * 異常 無
     * 描述:這個方法用於檢查藍牙是否可用
     */
    public boolean checkBtIsValueble() {

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            return false;
        } else {
            return true;
        }

    }

根據返回值,如果不支持是吧,那只好提示用戶不支持藍牙。如果支持藍牙,則進行下一步:

2、判斷藍牙可不可用(有沒有打開?3:打開藍牙)

判斷藍牙有沒有打開的話,可以通過適配器的isEnable()方法來判斷。

打開藍牙的方法有兩種,一種是靜默打開(個別系統不同,可能也要用戶授權),另外一種則需要讓用戶授權,可以檢測到打開的狀態。

  • 第一種打開方式,通過意圖的形式來打開,這種形式不需要聲明權限,但是要經過用戶的授權,請看碼:
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

    接著呢?看到 ForResult當然是去接收結果啦,是吧!

    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            //判斷是不是啟動藍牙的結果
            if (requestCode == REQUEST_ENABLE_BT) {
                if (resultCode == Activity.RESULT_OK) {
                    //成功
                    Toast.makeText(this, "藍牙開啟成功...", Toast.LENGTH_SHORT).show();
                    isOpenBlueToolth = true;
                } else {
                    //失敗
                    Toast.makeText(this, "藍牙開啟失敗...", Toast.LENGTH_SHORT).show();
                    isOpenBlueToolth = false;
                }
            }
        }

    RESULT_OK則表示成功,RESULT_CANCELED則表示取消了

    或者你也可以監聽廣播(但要記得注銷廣播),創建一個廣播接收者,設置過濾為:ACTION_STATE_CHANGED

    本質:藍牙的狀態發生改變這後,系統就會發出廣播的,具體的含義如下:

    EXTRA_STATE:直接翻譯是額外狀態

    EXTRA_PREVIOUS_STATE: 這個是這前的狀態

    這上面兩個狀態的值是下面的其中一個:

    STATE_TURNING_ON:正在玩命打開中...

    STATE_ON:已經開啟了

    STATE_TURNING_OFF:使勁關閉中...

    STATE_OFF:已經關閉了

第二種很簡單,小手一抖,一行代碼的事。但是要添加權限。為靜默打開形式,對於某些系統來說,是無效的。還是需要用戶的授權
 if (!defaultAdapter.isEnabled()) {
            defaultAdapter.enable();
        }

好,就這樣子,就打開了,核心代碼就一行。enable()就可以了。不要忘記權限

PS:關閉藍牙為disable();

3、根據不同的角色,明確需求

這裡面的角色,只有兩種嘛,要麼是客戶端,要麼是服務端。其實藍牙是BluetoothSocket,我們小時候學java的時候就學過網絡編程,也有Scoket,是吧!

首先是先有服務端,阻塞式地等客戶端連接進來。

這裡也一樣,要分清楚是服務端還是客戶端,這是第一點。另外就是要記得,關於網絡訪問,數據傳輸這些是耗時操作。要注意線程哈!

3.1客戶端

如果是客戶端,那我們的目標是什麼?當然是連接到服務端去,是吧!首先呢,我們要找到服務端。這時要進行藍牙掃描啦!

怎麼掃描周圍的服務端呢?看碼:

//掃描藍牙
isDiscovering = defaultAdapter.startDiscovery();

//注冊一個廣播接收者來獲取到掃描的藍牙設備
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);

廣播接收者的代碼如下:

private final 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(TAG, "掃描到了 --- > name : " + device.getName() + "-----> address:" + device.getAddress() + isDiscovering);
                mAdapter.add(device.getAddress());
                mAdapter.notifyDataSetChanged();

            }
        }
    };

解釋一下吧:我們通過開啟掃描,然後就進行對周圍的設備進行掃描啦,記得好像是掃描12秒的。不太清楚了,想查個究竟的可以上網問,或者自己用秒表測試一下哈,嘻嘻!

每掃描到一個設備的話,就會收到一次廣播啦。這裡要一定要注意哈,設備的名字可能是空的,但地址一定是有的。所以在使用設備名字時,一定要記得判空哪

就這樣子,我們靜悄悄地就可以發現周圍的設備了,或許你又有疑問了,為什麼手機誰連誰都可以呢?這到底是為什麼呢?因為他們同時實現了客戶端和服務端的功能。實際開發中也可以根據需求這樣做。

有了設備之後,我們可以獲取到設別的物理地址。接下來就是要進行配對了。這裡要說一下的時, 配對和連接是兩個不同的概念哦!

你可以理解為,配對是為了驗證身份,而連接則是創建傳送數據的通道

在配對之前,要獲取到遠程的設備(服務端),怎麼獲取呢,看下面的代碼吧:

 if (mBluetoothAdapter == null) {
                mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                updateMsg("去獲取適配器...");
            }
            updateMsg("去獲取遠程設備...");
            mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);

            try {
                updateMsg("去獲取...BluetoothSocket...");
                socket = mBluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(UUID_STR));
            } catch (IOException e) {

                updateMsg("錯誤:socket獲取失敗..." + e.toString());
            }

這裡面要理解的是通過物理地址來獲取到遠程的設備,然後需要UUID作為了一個標識。類比我們小時候學的Socket,這裡的mac地址呢,就類似於Ip地址,而UUID則類似於端口號。這樣相信聰明的你一定理解了是吧!

怎麼進行配對和判斷有沒有配對呢?

先來判斷是否有配對吧:

在配對之前呢,我們要習慣先取消掉發現設備(Discovery()):cancelDiscovery();

updateMsg("取消藍牙查找(搜索)...");
            mBluetoothAdapter.cancelDiscovery();

            // 連接建立之前的先配對
            try {
                if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {
                    Method creMethod = BluetoothDevice.class.getMethod("createBond");

                    updateMsg("正開始進行配對藍牙...");

                    creMethod.invoke(mBluetoothDevice);
                } else {
                    updateMsg("已經配對");
                }

            } catch (Exception e) {
                updateMsg("無法進行配對..." + e.toString());
            }

如果上面沒有什麼問題的主知,那麼就可以連接了,是吧!哈哈,此處應有掌聲哈!

話不多說,程序員更多的是用代碼來表達自己的想法:

 //連接操作
            try {
                socket.connect();
                updateMsg("連接狀態..." + socket.isConnected());


            } catch (IOException e) {

                updateMsg("連接失敗" + e.toString());

                try {
                    if (socket != null) {
                        socket.close();
                        socket = null;
                    }
                } catch (IOException e2) {
                    updateMsg("關閉socket失敗" + e2.toString());
                }

            }

這樣子,連接了。這和Socket是一樣的道理嘛!

到這裡的話,客戶端的准備工作就搞定了。但是這些操作要在子線程中完成,知道嗎?

接下來,當然是發數據和接收數據,可以通過getInputStream(),來獲取輸入流,用getOutputStream來獲取輸入流。

使用完成之後要記得關閉流,對於異常可以統一處理,使用代號也行,按自己的習慣或者公司的開發標准。

到這裡就不說發送數據了,你愛咋咋地!下面就說說服務端吧!

3.2服務端的業務邏輯

藍牙和Socket不同的是mac地址不是和ip地址那樣預先知道的。所以服務端要被客戶端掃描到。一般情況下,是不可見的。那麼這個時候,客戶端對服務端進行掃描時,就需要讓服務端可見啦!

 Intent btIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
 //設置藍牙的可見時間
 btIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600);
 startActivity(btIntent);
 Toast.makeText(WearMainActivity.this, "正打開藍牙可見..", Toast.LENGTH_SHORT).show();

這裡參數哈,我靠,一看3600是吧,那我就不客氣了,來個10000怎麼樣呢?其實,最多只能是3600秒。默認貌似是120秒吧,我忘記了,老了!

作為服務端,它應該和ServiceSocket一樣,去等待著客戶端連接進來。一般在子線程中開一個死循環去等待。由於app在多數情況下是一對一的。accept方法是阻塞的。所以呢,可以不死循環去accept()客戶端進來。

當然,這裡要根據需求來定啦。不能這麼死板。多數情況下,我們會使用可控制的循環去等待客戶端進來。下面例子直接等待一個連接進來就完事了哈:

  try {
        socket = mmServerSocket.accept();
       } catch (IOException e) {
        updateViewSafely("accept失敗.." + e.toString());
       }

如果有客戶端進來的話,那麼就可以獲取到了socket。那麼還是一樣的方法,通過socket來獲取到輸入輸出流。

InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();

接下來想干嘛干嘛去,要注意對異常的處理,關流等操作。一般來說,操作這些數據的在子線程,如果要更新UI,不要搞錯線程。通常用Handler來處理消息

4.0末言

到這裡貌似寫完了哈,不詳細的地方自己想去,也可以問我,反正我也不會告訴你的。有錯的地方嘛,可以到社區當眾指出!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved