Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android--藍牙操作(藍牙的打開與關閉,可見性的打開與關閉)

Android--藍牙操作(藍牙的打開與關閉,可見性的打開與關閉)

編輯:關於Android編程

BluetoothAdapter 用法

藍牙運行原理:通過BluetoothAdapter 藍牙適配器處理任務,如果藍牙被啟動之後,系統會自動去搜索其它設備,如果匹配到附近的設備就發送一個廣播,BroadcastRecevier的onReceive被調用一次,我們只需要在onReceive中處理自己的操作即可。

藍牙是一種支持設備短距離傳輸數據的無線技術。android在2.0以後提供了這方面的支持。從查找藍牙設備到能夠相互通信要經過幾個基本步驟(本機做為服務器):

根據需要設置自己的權限:

<!--設備之間申請連接,交流等-->

<!--允許程序去搜索和配對藍牙設備。-->

<!--允許設備不經過用戶操作自動配對-->

<!--動態掃描的權限,android6.0需要設置此權限-->

打開藍牙的方法

       bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//        if (bluetoothAdapter == null) {
//            Toast.makeText(context,"對不起,您的設備不支持藍牙,即將退出", Toast.LENGTH_SHORT).show();
//            finish();
//        } else if(!bluetoothAdapter.isEnabled()) {//藍牙未開啟
//            Intent intent = newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//           startActivityForResult(intent, REQUEST_BLUETOOTH_OPEN);
//        }


 

設置藍牙可見性的方法

1.通過Intent啟動

    private void ensureBluetoothDiscoverable() {
        if(bluetoothAdapter.getScanMode() !=
                BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3);
            startActivity(intent);
        }
    }

 

2.通過系統setting強制開啟


public void setDiscoverableTimeout(int timeout) { BluetoothAdapter adapter=BluetoothAdapter.getDefaultAdapter(); try { Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class); setDiscoverableTimeout.setAccessible(true); Method setScanMode =BluetoothAdapter.class.getMethod("setScanMode", int.class,int.class); setScanMode.setAccessible(true); setDiscoverableTimeout.invoke(adapter, timeout); setScanMode.invoke(adapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,timeout); } catch (Exception e) { e.printStackTrace(); } }

第一種方法,讓用戶看到自己開啟了藍牙的可見性,第二種直接從後台開啟藍牙可見,但會一直可見下去,直到藍牙關閉。我在小米miui + android6.0使用了第一種方法開啟了藍牙可見性,但並沒有想象中的到時間自動關閉,因為這時的小米已經去掉了藍牙可見性的計時關閉,只會一直開啟下去,所以我找了好久,才找到下面的方法關閉了藍牙可見性。

 

關閉藍牙可見性

  private void closeBluetoothDiscoverable(){
        //嘗試關閉藍牙可見性
        try {
            Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
            setDiscoverableTimeout.setAccessible(true);
            Method setScanMode =BluetoothAdapter.class.getMethod("setScanMode", int.class,int.class);
            setScanMode.setAccessible(true);

            setDiscoverableTimeout.invoke(bluetoothAdapter, 1);
            setScanMode.invoke(bluetoothAdapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

BluetoothAdapter的常用方法

getAddress()獲取本地藍牙地址

getDefaultAdapter()獲取默認BluetoothAdapter,實際上,也只有這一種方法獲取BluetoothAdapter

getName()獲取本地藍牙名稱

getRemoteDevice(String address)根據藍牙地址獲取遠程藍牙設備

getState()獲取本地藍牙適配器當前狀態(感覺可能調試的時候更需要)

isDiscovering()判斷當前是否正在查找設備,是返回true

isEnabled()判斷藍牙是否打開,已打開返回true,否則,返回false

listenUsingRfcommWithServiceRecord(String name,UUID uuid)根據名稱,UUID創建並返回

BluetoothServerSocket,這是創建BluetoothSocket服務器端的第一步

startDiscovery()開始搜索,這是搜索的第一步

BluetoothAdapter裡的方法很多,常用的有以下幾個:

cancelDiscovery() 根據字面意思,是取消發現,也就是說當我們正在搜索設備的時候調用這個方法將不再繼續搜索

disable()關閉藍牙

enable()打開藍牙,這個方法打開藍牙不會彈出提示,更多的時候我們需要問下用戶是否打開,一下這兩行代碼同樣是打開藍牙,不過會提示用戶:

搜索藍牙設備

Android6.0藍牙搜索需要定位權限,具體博文請看Android6.0權限詳解, 藍牙搜索使用的權限申請方法如下:

 

    private void mayRequestLocation(){
        Log.d(TAG, "mayRequestLocation: androidSDK--" + Build.VERSION.SDK_INT);
        if(Build.VERSION.SDK_INT >= 23){
            //6.0以上設備
            int checkCallPhonePermission = checkSelfPermission(Manifest.permission.
                    ACCESS_COARSE_LOCATION);
            if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "mayRequestLocation: 請求粗略定位的權限");
                requestPermissions(new String[]{Manifest.permission.
                        ACCESS_COARSE_LOCATION}, REQUEST_PERMISSION_LOCATION);
                return;
            }
        }

 

藍牙搜索具體方法:

 

//查找配對過的設備
                        mayRequestLocation();
                        Set pairedDevices = bluetoothAdapter.getBondedDevices();
                        if (pairedDevices.size() > 0) {
                            for (BluetoothDevice device : pairedDevices) {
                                Log.d(TAG, "已配對設備:" + device.getName() + " address: " + device.getAddress());
                            }
                        } else {
                            Log.d(TAG, "onClick: 沒有找到配對的設備");
                        }

                        //嘗試搜索設備
                        BroadcastReceiver receiver = new BroadcastReceiver() {
                            @Override
                            public void onReceive(Context context, Intent intent) {
                                String action = intent.getAction();
                                switch (action) {
                                    case BluetoothAdapter.ACTION_DISCOVERY_FINISHED: {
                                        Log.d(TAG, "onReceive: 結束查找設備");
                                        break;
                                    }
                                    case BluetoothAdapter.ACTION_DISCOVERY_STARTED: {
                                        Log.d(TAG, "onReceive: 開始查找設備");
                                        break;
                                    }
                                    case BluetoothDevice.ACTION_FOUND: {
                                          /* 從intent中取得搜索結果數據 */
                                        Log.d(TAG, "onReceive: 查找到設備");
                                        BluetoothDevice device = intent
                                                .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                                        Log.d(TAG, "設備:" + device.getName() + " address: " + device.getAddress());
                                        break;
                                    }
                                }

                            }
                        };
                        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
                        registerReceiver(receiver, filter);
                        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
                        registerReceiver(receiver, filter);
                        filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
                        registerReceiver(receiver, filter);
                        if (bluetoothAdapter.isDiscovering()) {//正在查找
                            Log.d(TAG, "onClick: 正在查找設備");
                        } else {
                            bluetoothAdapter.startDiscovery();
                        }


兩個藍牙設備的連接

import java.io.IOException;

/**
 * 客戶端,用於連接服務端
 */
class ClientThread extends Thread {

    /**
     * 在創建客戶端的時候,創建bluetoothSocket
     */
    public ClientThread() {
        try {
            bluetoothSocket =bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
        } catch (IOException e) {
            Log.e(TAG, "ClientThread:", e);
            e.printStackTrace();
        }
    }

    /**
     * 在線程內創建子線程,進行連接,我覺的這是由於多線程思想決定的
     * 在一個主線程中開辟子線程實現操作,從而可以實現並發,不會導致
     * 主線程的阻塞,導致IOException
     */
    @Override
    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(bluetoothSocket == null){
                    return;
                }else{
                    try {
                       bluetoothSocket.connect();
                        /**
                         * 連接成功後,將連接完成的socket傳入已連接線程
                         */
                        connectedThread = new ConnectedThread(bluetoothSocket);
                        connectedThread.start();
                    } catch (IOException e) {
                        Log.e(TAG, "run: ", e);
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

/**
 * 服務器線程,用於接受來自客戶端的訪問
 */
private class ServerThread extends Thread {
    /**
     * 藍牙通信,兩者需要使用同一個UUID
     */
    public ServerThread() {
        Log.d(TAG, "ServerThread: 構件服務端");
        try {
            bluetoothServerSocket =BluetoothAdapter.getDefaultAdapter().
                   listenUsingRfcommWithServiceRecord("test", uuid);
        } catch (IOException e) {
            Log.e(TAG, "ServerThread: construct", e);
            e.printStackTrace();
        }
    }

    /**
     * 服務端等待連接線程,從等級上講,比客戶端的連接線程高一個級別,應該是由於服務器端
     * 只需要等待一個連接請求,但並不考慮多線程,因為請求發出必有先後,而客戶端卻需要考
     * 慮線程,所以低了一個級別
     */
    @Override
    public void run() {
        while (bluetoothServerSocket != null) {
            try {
                Log.e(TAG, "run:serverThread  等待連接");
                bluetoothSocket1 =bluetoothServerSocket.accept();
                Message message = new Message();
                message.what = MSG_WAIT_CONNECT;
                handler.sendMessage(message);
            } catch (IOException e) {
                Log.e(TAG, "run:ServerThread", e);
                e.printStackTrace();
            }
            if (bluetoothSocket1 != null) {
                Log.d(TAG, "run: connectsuccess");
                connectedThread = new ConnectedThread(bluetoothSocket1);
                connectedThread.start();
                Message message = new Message();
                message.what = MSG_CONNECT_SUCCESS;
                handler.sendMessage(message);
            }
        }
    }
}

/**
 * 已連接的線程,用於通信
 */
private class ConnectedThread extends Thread{
    private BluetoothSocket bluetoothSocket;
    private OutputStream outputStream;
    private InputStream inputStream;
    byte [] bytes = new byte[1024];

    /**
     * 獲取輸入輸出流
     * @param bluetoothSocket
     */
    public ConnectedThread(BluetoothSocket bluetoothSocket) {
        this.bluetoothSocket = bluetoothSocket;
        try {
            outputStream = this.bluetoothSocket.getOutputStream();
            inputStream = this.bluetoothSocket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 讀取線程,一直工作
     */
    @Override
    public void run() {
        int i = 0;
        if(inputStream == null)
            return;
        do {
            try {
                i = inputStream.read(bytes);
                Message message = new Message();
                message.what = MSG_READ_STRING;
                String string = new String(bytes);
                message.obj = string;
                handler.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }while (i != 0);
    }

    /**
     * 寫不需要線程,值得一提的是讀取和寫入都是用bytes串的形式傳輸的
     * @param string
     */
    public void write(String string){
        byte [] bytes;
        bytes = string.getBytes();
        try {
            outputStream.write(bytes);
            MessageForChat msg = new MessageForChat(true, string);
            messageList.add(msg);
            adapter.notifyDataSetChanged();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
    以下是做的一個藍牙聊天的Demo 頂上的文字區域用來顯示正在連接的藍牙設備的名字和地址,而聊天窗口模仿微信聊天窗口,如下圖: \   \     Demo的git地址是:https://github.com/No1clay/Android.git(裡邊的WeChat示例)
 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved