【轉】Android:Bluetooth 的打開和關閉--不錯


原文網址:http://www.ifeegoo.com/android-turn-on-and-turn-off-bluetooth.html

摘要:Android 中打開和關閉 Bluetooth 的代碼雖然並不困難,但是我們還是需要注意一些細節和異常情況,這樣我們才能更好的優化我們的與 Bluetooth 相關的應用。

Runtime Environment
OS: Windows 8.1
IDE: ADT Bundle v22.6.2
Device:
Nexus 5 / Android 4.4.4
MI 2SC / MIUI-4.7.11 (Android 4.1.1 JRO03L)
Android 中打開和關閉 Bluetooth 的代碼雖然並不困難,但是我們還是需要注意一些細節和異常情況,這樣我們才能更好的優化我們的與 Bluetooth 相關的應用。

在研究打開和關閉 Bluetooth 之前,我們應該了解 Android 版本和 Bluetooth 版本之間的關系,請參考本博客文章 《Android 版本與 Bluetooth 版本之間的關系》

Android 在 Android 2.0 Eclair / API Level 5 中就已經有開放的操作 Bluetooth 的 API 了,在此版本已經有以下公開類:

1 /**
2 * 本地 Bluetooth 適配器,執行基本的 Bluetooth 任務,例如:初始設備掃描、查詢已經綁定
3 * (或已經配對)的設備、通過已知的 MAC 地址來實例化 BluetoothDevice 對象、創建
4 * BluetoothServerSocket 來監聽其它設備的連接請求等。
5 */
6 BluetoothAdapter.java
7  
8 /**
9  * 描述設備的一般特性和能力。例如,它會指定一般設備類型,例如:手機、電腦、耳機等,還
10  * 有是否支持音頻或電話等服務。但是不能可靠的描述諸如設備支持哪些 Profile 或者 Service。
11  */
12 BluetoothClass.java
13  
14 /**
15  * 表示一個遠程的 Bluetooth 設備。它能讓你與各個設備創建連接或者查詢信息。
16  * 例如:名字、地址、類和綁定狀態等。
17  */
18 BluetoothDevice.java
19  
20 /**
21  * Bluetooth socket 和 TCP socket 有些類似。最普通的 Bluetooth socket 類型是 RFCOMM,
22  * 這是 Android API 支持的類型。RFCOMM 是一個方向性的連接。通過 Bluetooth 傳輸流。
23  * 同樣也稱作 SPP (Serial Port Profile)。
24  */
25 BluetoothServerSocket.java
26 BluetoothSocket.java
Android 中打開 Bluetooth:有以下三種方法:
1.強制打開
2.調用系統彈出框提示用戶打開
3.跳轉到系統設置中讓用戶自己打開

1.強制打開 Bluetooth 的代碼:

1 BluetoothAdapter.getDefaultAdapter() 需要注冊權限:
2 <uses-permission android:name="android.permission.BLUETOOTH" />
3  
4 BluetoothAdapter.enable() 需要注冊權限:
5 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
1 /**
2  * Bluetooth 管理類
3  *
4  * @author ifeegoo www.ifeegoo.com
5  *
6  */
7 public class BluetoothManager
8 {
9  
10     /**
11      * 當前 Android 設備是否支持 Bluetooth
12      *
13      * @return true:支持 Bluetooth false:不支持 Bluetooth
14      */
15     public static boolean isBluetoothSupported()
16     {
17         return BluetoothAdapter.getDefaultAdapter() != null ? true : false;
18     }
19  
20     /**
21      * 當前 Android 設備的 bluetooth 是否已經開啟
22      *
23      * @return true:Bluetooth 已經開啟 false:Bluetooth 未開啟
24      */
25     public static boolean isBluetoothEnabled()
26     {
27         BluetoothAdapter bluetoothAdapter = BluetoothAdapter
28                 .getDefaultAdapter();
29  
30         if (bluetoothAdapter != null)
31         {
32             return bluetoothAdapter.isEnabled();
33         }
34  
35         return false;
36     }
37  
38     /**
39      * 強制開啟當前 Android 設備的 Bluetooth
40      *
41      * @return true:強制打開 Bluetooth 成功 false:強制打開 Bluetooth 失敗
42      */
43     public static boolean turnOnBluetooth()
44     {
45         BluetoothAdapter bluetoothAdapter = BluetoothAdapter
46                 .getDefaultAdapter();
47  
48         if (bluetoothAdapter != null)
49         {
50             return bluetoothAdapter.enable();
51         }
52  
53         return false;
54     }
55 }
以上強制打開 Bluetooth 是調用了 BluetoothAdapter.enable() 方法。首先需要獲取 BluetoothAdapter 對象,如果這個對象為 null 的話,說明當前設備不支持 Bluetooth 功能。還有以下幾點需要注意:
1° 在 Nexus 5 Android 4.4.4 原生系統中,在沒有任何其它管理 Bluetooth 權限的應用情況下,調用強制打開 Bluetooth 的方法,沒有任何提示就直接打開 Bluetooth 了。
2° 在小米手機 MI 2SC / MIUI-4.7.11 (Android 4.1.1 JRO03L) 上系統自帶的 “安全中心” – “應用權限管理” – “開啟藍牙” 中,有三種設置:
允許:調用強制打開 Bluetooth 代碼,沒有任何提示,Bluetooth 被成功打開。
提示:會彈出提示框,提示安全警告 “ ***應用嘗試開啟藍牙”,可以選擇“拒絕”或“允許”,還有記住此次選擇(備注:如果不記住的話,下次還會彈出同樣的提示框,除非你自己去修改了應用開啟藍牙的權限)。
拒絕:調用強制打開 Bluetooth 代碼,沒有任何提示,Bluetooth 強制打開失敗。
備注:各種手機自帶的權限管理功能或者第三方權限管理應用略有不同。
3° 對於 BluetoothAdapter.enable() 這個方法,API 中有以下說明 (備注:初始 API 中,如 Android 2.0 Eclair / API Level 5 中並沒有這段提示)
Bluetooth should never be enabled without direct user consent. If you want to turn on Bluetooth in order to create a wireless connection, you should use the ACTION_REQUEST_ENABLE Intent, which will raise a dialog that requests user permission to turn on Bluetooth. The enable() method is provided only for applications that include a user interface for changing system settings, such as a “power manager” app.
沒有直接的用戶的允許絕不要開啟 Bluetooth。如果你想要打開 Bluetooth 創建一個無線連接,你應當使用 ACTION_REQUEST_ENABLE Intent,這樣會彈出一個提示框提示用戶是否開啟 Bluetooth,enable() 方法僅提供給有 UI 、更改系統設置的應用來使用,例如“電源管理”應用。
從以上官方 API 提示可以看出:不建議你調用此方法來打開 Bluetooth,至少是在沒有任何用戶提醒的前提下!

mi-2sc-security-center-authorization-management-application-permission-management-turn-on-bluetooth-selection

mi-2sc-one-application-try-to-turn-on-bluetooth

2.調用系統彈出框提示用戶打開:

1 this.startActivityForResult(requestBluetoothOn, REQUEST_CODE_BLUETOOTH_ON) 需要注冊權限:
2 <uses-permission android:name="android.permission.BLUETOOTH" />
1 public class MainActivity extends Activity
2 {
3     /**
4      * 自定義的打開 Bluetooth 的請求碼,與 onActivityResult 中返回的 requestCode 匹配。
5      */
6     private static final int REQUEST_CODE_BLUETOOTH_ON = 1313;
7  
8     /**
9      * Bluetooth 設備可見時間,單位:秒。
10      */
11     private static final int BLUETOOTH_DISCOVERABLE_DURATION = 250;
12  
13     @Override
14     protected void onCreate(Bundle savedInstanceState)
15     {
16         super.onCreate(savedInstanceState);
17         this.setContentView(R.layout.activity_main);
18  
19         if ((BluetoothManager.isBluetoothSupported())
20                 && (!BluetoothManager.isBluetoothEnabled()))
21         {
22             this.turnOnBluetooth();
23         }
24     }
25  
26     /**
27      * 彈出系統彈框提示用戶打開 Bluetooth
28      */
29     private void turnOnBluetooth()
30     {
31         // 請求打開 Bluetooth
32         Intent requestBluetoothOn = new Intent(
33                 BluetoothAdapter.ACTION_REQUEST_ENABLE);
34  
35         // 設置 Bluetooth 設備可以被其它 Bluetooth 設備掃描到
36         requestBluetoothOn
37                 .setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
38  
39         // 設置 Bluetooth 設備可見時間
40         requestBluetoothOn.putExtra(
41                 BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
42                 BLUETOOTH_DISCOVERABLE_DURATION);
43  
44         // 請求開啟 Bluetooth
45         this.startActivityForResult(requestBluetoothOn,
46                 REQUEST_CODE_BLUETOOTH_ON);
47     }
48  
49     @Override
50     protected void onActivityResult(int requestCode, int resultCode, Intent data)
51     {
52         // requestCode 與請求開啟 Bluetooth 傳入的 requestCode 相對應
53         if (requestCode == REQUEST_CODE_BLUETOOTH_ON)
54         {
55             switch (resultCode)
56             {
57             // 點擊確認按鈕
58                 case Activity.RESULT_OK:
59                 {
60                     // TODO 用戶選擇開啟 Bluetooth,Bluetooth 會被開啟
61                 }
62                 break;
63  
64                 // 點擊取消按鈕或點擊返回鍵
65                 case Activity.RESULT_CANCELED:
66                 {
67                     // TODO 用戶拒絕打開 Bluetooth, Bluetooth 不會被開啟
68                 }
69                 break;
70                 default:
71                 break;
72             }
73         }
74     }
75 }
對於以上彈出系統彈框提示用戶打開 Bluetooth 的代碼,有以下幾點需要注意:
1° 這種調用系統的彈出框提示用戶打開 Bluetooth 的方式,一般不會受到系統或者第三方權限管理應用的阻止。只有當你不提示用戶的情況下,可以理解為“偷偷摸摸”的打開 Bluetooth ,這個是被認為侵犯用戶的知情權,系統或者第三方權限管理應用可能加以阻止:直接禁止不提示用戶的情況下打開 Bluetooth,或者提示用戶,又或者是讓用戶自己選擇哪些應用可以強制開啟 Bluetooth。而在 Nexus 5 / Android 4.4.4 原生系統強制打開 Bluetooth 是沒有任何提示,並且可以成功打開。
2° 彈出系統的提示框提醒用戶打開 Bluetooth 的主要代碼:
this.startActivityForResult(requestBluetoothOn,REQUEST_CODE_BLUETOOTH_ON);
注意:這個方法是需要 Activity 的對象來調用的!並且需要在 Activity 中重寫 onActivityResult 方法來獲取用戶操作彈出提示框的結果!
3° 這種彈出的系統彈框,根據系統的不同,UI 會有所不同,下圖左邊是 Nexus 5 Android 4.4.4 系統手機顯示效果,右邊是小米手機 MI 2SC / MIUI-4.7.11 (Android 4.1.1 JRO03L) 系統顯示的效果:
nexus-5-android-4.4.4-and-mi-2sc-miui-4.7.11-android-4.1.1-jro03l-request-to-turn-on-bluetooth4° 如果你只設置了 Bluetooth 設備的可見時間,而不去調用 setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE) 方法的話,Bluetooth 依然是不可見的。你設置的 Bluetooth 的可見時間是不生效的,當前 Android 系統的 Bluetooth 不可見!
5° 設置 Bluetooth 設備的可見時間的時候,在 Android 4.4.2 官方 API 中的說明如下:
The current default is 120 seconds, and requests over 300 seconds will be capped. These values could change.
當前默認值是 120s ,300s 是上限。這些值可能會變。
目前測試出來的有以下結論:
— 可設置的可見時間為 [1,3600] s ,也就是最小1秒鍾,最大1個小時。
— 設置的可見時間為 0 時,表示打開 Bluetooth 之后一直可見,設置小於0或者大於3600 時,系統會默認為 120s。
6° 如果你設備的 Bluetooth 已經打開,而且你不設置設備的可見時間的話,調用以上開啟 Bluetooth 的方法,是不會有任何提示的。當然,如果 Bluetooth 已經開啟,也可以通過這個方法來修改 Bluetooth 的可見性。

3.跳轉到系統設置中讓用戶自己打開:

1 // 跳轉到系統 Bluetooth 設置
2 this.startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
考慮到涉及用戶隱私和用戶體驗,推薦以下方式開啟 Bluetooth :
1° 采用強制開啟 Bluetooth 的方式打開 Bluetooth ,但是調用強制開啟 Bluetooth 代碼之前,我們自己在應用中提示用戶,我們的應用需要開啟 Bluetooth ,讓用戶自己選擇是否開啟 Bluetooth 。自己在應用中提示用戶我們需要開啟 Bluetooth 相對於彈出系統的提示框提示用戶當前應用需要開啟 Bluetooth 的優勢在於我們可以控制提示的內容和提示的方式以及 UI。
2° 假若用戶選擇了開啟 Bluetooth,但是強制開啟 Bluetooth 失敗,比如系統自帶的權限管理禁止你的應用開啟 Bluetooth ,我們不去提示用戶說當前系統禁止了應用開啟 Bluetooth,讓用戶自己去解除禁止。這樣顯然用戶體驗很差。這種情況下,我們再去調用彈出系統提示框提醒用戶打開 Bluetooth 即可。這種方式一般系統或者第三方應用不會禁止。
3° 如果彈出系統提示框提醒用戶打開 Bluetooth 有問題的話,最后采用提示用戶自己去系統 Bluetooth 設置中打開 Bluetooth,跳轉到系統的 Bluetooth 設置界面。
Android 中關閉 Bluetooth:有以下倆種方法:
1.強制關閉
2.跳轉到系統設置中讓用戶自己關閉

1.強制關閉:

1 BluetoothAdapter.getDefaultAdapter() 需要注冊權限:
2 <uses-permission android:name="android.permission.BLUETOOTH" />
3  
4 BluetoothAdapter.disable() 需要注冊權限:
5 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
1 /**
2  * Bluetooth 管理類
3  *
4  * @author ifeegoo www.ifeegoo.com
5  *
6  */
7 public class BluetoothManager
8 {
9     /**
10      * 當前 Android 設備是否支持 Bluetooth
11      *
12      * @return true:支持 Bluetooth false:不支持 Bluetooth
13      */
14     public static boolean isBluetoothSupported()
15     {
16         return BluetoothAdapter.getDefaultAdapter() != null ? true : false;
17     }
18  
19     /**
20      * 當前 Android 設備的 bluetooth 是否已經開啟
21      *
22      * @return true:Bluetooth 已經開啟 false:Bluetooth 未開啟
23      */
24     public static boolean isBluetoothEnabled()
25     {
26         BluetoothAdapter bluetoothAdapter = BluetoothAdapter
27                 .getDefaultAdapter();
28  
29         if (bluetoothAdapter != null)
30         {
31             return bluetoothAdapter.isEnabled();
32         }
33  
34         return false;
35     }
36  
37     /**
38      * 強制開啟當前 Android 設備的 Bluetooth
39      *
40      * @return true:強制打開 Bluetooth 成功 false:強制打開 Bluetooth 失敗
41      */
42     public static boolean turnOnBluetooth()
43     {
44         BluetoothAdapter bluetoothAdapter = BluetoothAdapter
45                 .getDefaultAdapter();
46  
47         if (bluetoothAdapter != null)
48         {
49             return bluetoothAdapter.enable();
50         }
51  
52         return false;
53     }
54      
55     /**
56      * 強制關閉當前 Android 設備的 Bluetooth
57      *
58      * @return  true:強制關閉 Bluetooth 成功 false:強制關閉 Bluetooth 失敗
59      */
60     public static boolean turnOffBluetooth()
61     {
62         BluetoothAdapter bluetoothAdapter = BluetoothAdapter
63                 .getDefaultAdapter();
64  
65         if (bluetoothAdapter != null)
66         {
67             return bluetoothAdapter.disable();
68         }
69  
70         return false;
71     }
72 }
以上強制關閉 Bluetooth 是調用了 BluetoothAdapter.disable() 方法。首先需要獲取 BluetoothAdapter 對象,如果這個對象為 null 的話,說明當前設備不支持 Bluetooth 功能。還有以下幾點需要注意:
1° 目前發現常見的系統或者第三方權限管理應用好像對關閉 Bluetooth 並不做限制。
2° 如果系統或者第三方權限管理應用限制你的應用關閉 Bluetooth 的話,請參考強制開啟 Bluetooth 要注意的點 1° 和 2°。
3° 對於 BluetoothAdapter.disable() 這個方法,API 中有以下說明 (備注:初始 API 中,如 Android 2.0 Eclair / API Level 5 中並沒有這段提示)
Bluetooth should never be disabled without direct user consent. The disable() method is provided only for applications that include a user interface for changing system settings, such as a “power manager” app.
沒有直接的用戶的允許絕不要關閉 Bluetooth。disable() 方法僅提供給有 UI 、更改系統設置的應用來使用,例如“電源管理”應用。
從以上官方 API 提示可以看出:不建議你調用此方法來關閉 Bluetooth,至少是在沒有任何用戶提醒的前提下!

2.跳轉到系統設置中讓用戶自己關閉:

1 // 跳轉到系統 Bluetooth 設置
2 this.startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
考慮到涉及用戶隱私和用戶體驗,推薦以下方式關閉 Bluetooth :
1° 采用強制關閉 Bluetooth 的方式關閉 Bluetooth ,但是調用強制關閉 Bluetooth 代碼之前,我們自己在應用中提示用戶,我們的應用需要關閉 Bluetooth ,讓用戶自己選擇是否關閉 Bluetooth 。自己在應用中提示用戶我們需要關閉 Bluetooth ,暫時沒有發現 Android 有提供了彈出系統提示框提示用戶關閉 Bluetooth 的 API。
2° 假若用戶選擇了關閉 Bluetooth,但是強制關閉 Bluetooth 失敗,比如系統自帶的權限管理禁止你的應用關閉 Bluetooth ,我們不去提示用戶說當前系統禁止了應用關閉 Bluetooth,讓用戶自己去解除禁止。這樣顯然用戶體驗很差。這種情況下,我們提示用戶“由於某些原因導致應用關閉 Bluetooth 失敗,請到系統設置中自己關閉 Bluetooth”,然后跳轉到系統 Bluetooth 設置中。
本博客所有文章 如無特別注明均為原創。復制或轉載請 以超鏈接形式注明轉自 ifeegoo,原文地址《 Android:Bluetooth 的打開和關閉


免責聲明!

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



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