1. 程式人生 > >android 傳統藍芽開發 (附示例原始碼)

android 傳統藍芽開發 (附示例原始碼)

前:本文為QiaoJim原創,轉載請附原文連結,謝謝合作!

----------------------------------------------------------------------------------

最近學習了android傳統藍芽,自己整理了一下思路,然後寫了一個BluetoothStudy小測試程式,來運用所理解的android傳統藍芽開發技術,寫下

一些心得和思路,供其他android熱愛者參考,也方便日後回顧。

部落格如有錯誤之處,歡迎留言之處,十分感謝。部落格最後會附上原始碼,可下載借鑑。

一、整體思路和對應相關方法

1、獲得BluetoothAdapter:

BluetoothAdapter.getDefaultAdapter();

2、開啟藍芽:詢問使用者開啟(推薦)或直接bluetoothAdapter.enable();

3、查詢已繫結裝置,發現新裝置:bluetoothAdapter.getBondedDevices();bluetoothAdapter.startDiscovery();

4.1、服務端,一直監聽請求,當該端主動發出請求時,關閉該端的監聽,角色轉為客戶端:

bluetoothDevice.createRfcommSocketToServiceRecord(UUID);

4.2、客戶端,點選目標裝置,配對連線:

bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID);

5、通過BluetoothSocket通訊:IO流讀寫

二、開發詳解

1、宣告許可權,注意可能需要的執行時許可權

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

android 6.0以上裝置發現新藍芽時,需加入執行時許可權,否則無法監聽ACTION_FOUND廣播

        if (Build.VERSION.SDK_INT >= 6.0) {
            ActivityCompat.requestPermissions(getActivity(), 
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                             Params.MY_PERMISSION_REQUEST_CONSTANT);
        }

        public void onRequestPermissionsResult(int requestCode, String permissions[],
                                               int[] grantResults) {
           switch (requestCode) {
              case Params.MY_PERMISSION_REQUEST_CONSTANT: {
                  if (grantResults.length > 0 
                          && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                       // 執行時許可權已授權
                   }
                  return;
               }
           }
        }


2、開啟藍芽,推薦用對話方塊形式讓使用者開啟

       bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

       // 藍芽未開啟,詢問開啟
       if (!bluetoothAdapter.isEnabled()) {
            Intent turnOnBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(turnOnBtIntent, Params.REQUEST_ENABLE_BT);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case Params.REQUEST_ENABLE_BT: {
                    //使用者開啟藍芽
                    if (resultCode == RESULT_OK) {
                        //顯示已繫結藍芽裝置
                        showBondDevice();
                    }
                    break;
                }
                case Params.REQUEST_ENABLE_VISIBILITY: {
                    //設定該藍芽裝置可被其他裝置發現,600是設定的裝置可發現時間(部落格最後有簡單說明)
                    if (resultCode == 600) {
                        toast("藍芽已設定可見");
                    } else if (resultCode == RESULT_CANCELED) {
                        toast("藍芽設定可見失敗,請重試");
                    }
                    break;
                }
            }
        }
3、通過BluetoothAdapter獲取已繫結的藍芽裝置
        private void showBondDevice() {
            deviceList.clear();
            // 所有已繫結裝置,一個Set集合
            Set<BluetoothDevice> tmp = bluetoothAdapter.getBondedDevices();
            for (BluetoothDevice d : tmp) {
                deviceList.add(d);
            }
            //更新列表
            listAdapter.notifyDataSetChanged();
        }

4、發現藍芽裝置,發現一個裝置,會發送一條ACTION_FOUND廣播,註冊廣播接收器,可獲得對應藍芽裝置資訊

        bluetoothAdapter.startDiscovery();

        intentFilter = new IntentFilter();
        btReceiver = new MyBtReceiver();
        //監聽 搜尋開始,搜尋結束,發現新裝置 3條廣播
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
        getActivity().registerReceiver(btReceiver, intentFilter);

        //廣播接收器
        private class MyBtReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
                    toast("開始搜尋 ...");
                } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                    toast("搜尋結束");
                } else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    //獲得發現的裝置
                    BluetoothDevice device = 
                        intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                        deviceList.add(device);
                        listAdapter.notifyDataSetChanged();
                    }
                }
            }
        }


5、裝置連線,伺服器端開啟執行緒一直等待連線,客戶端點選某個目標裝置,關閉伺服器執行緒監聽,並開啟執行緒,發出連線請求。 

注意:客戶端連線前,一定cancelDiscovery()

        // 藍芽已開啟
        if (bluetoothAdapter.isEnabled()) {
            showBondDevice();
            // 預設開啟服務執行緒監聽
            if (serverThread != null) {
                serverThread.cancel();
            }
            serverThread = new ServerThread(bluetoothAdapter, uiHandler);
            new Thread(serverThread).start();
        }

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, 
                                    int position, long id) {
                // 關閉伺服器監聽
                if (serverThread != null) {
                    serverThread.cancel();
                    serverThread=null;
                }
                BluetoothDevice device = deviceList.get(position);
                // 開啟客戶端執行緒,連線點選的遠端裝置
                clientThread = new ClientThread(bluetoothAdapter, device, uiHandler);
                new Thread(clientThread).start();

                // 通知 ui 連線的伺服器端裝置
                Message message = new Message();
                message.what = Params.MSG_CONNECT_TO_SERVER;
                message.obj = device;
                uiHandler.sendMessage(message);
            }
        });

6、建立BluetoothSocket連線以後,使用IO流資料傳輸,伺服器和客戶端讀寫資料類似,貼一部分程式碼供參考

        public void writeData(String dataSend) {
            if (serverThread != null) {
                serverThread.write(dataSend);
            } else if (clientThread != null) {
                clientThread.write(dataSend);
            }
        }
        //寫資料
        public void write(String data){
            try {
                out.write(data.getBytes("utf-8"));            
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        new Thread(new Runnable() {
                @Override
                public void run() {
                    byte[] buffer = new byte[1024];
                    int len;
                    String content;
                    try {
                        //讀資料
                        while ((len=in.read(buffer)) != -1) {
                            content=new String(buffer, 0, len);
                            Message message = new Message();
                            message.what = Params.MSG_CLIENT_REV_NEW;
                            message.obj = content;
                            //更新 ui
                            uiHandler.sendMessage(message);
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
7、其他說明

(1)新裝置繫結,bluetoothDevice.createBond()

(2)設定裝置可被發現的時間:

Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
enableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);  
startActivityForResult(enableIntent, Params.REQUEST_ENABLE_VISIBILITY); 

(3)伺服器獲得遠端裝置,bluetoothSocket.getRemoteDevice() 

(4)通過MAC獲得藍芽裝置,bluetoothAdapter.getRemoteDevice(String address) 

(5)關閉藍芽,bluetoothAdapter.disable()

三、原始碼示例下載

感謝閱讀,如有錯誤,請留言。如果覺得博文不錯,請點贊支援。 

四、效果圖