第一步:聲明Bluetooth Permissions
<!-- 設置藍牙訪問權限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
第二步:獲取BluetoothAdapter,判斷該設備是否支持藍牙
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth // 說明該設備不支持藍牙 }
第三步:檢查當前的藍牙是否開啟
if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); // 不做提示,強行打開 // mAdapter.enable(); }
如果是第一種方式:會出現提示彈窗
A dialog will appear requesting user permission to enable Bluetooth, as shown in Figure 1. If the user responds "Yes," the system will begin to enable Bluetooth and focus will return to your application once the process completes (or fails).
If enabling Bluetooth succeeds, your Activity will receive the RESULT_OK
result code in the onActivityResult()
callback. If Bluetooth was not enabled due to an error (or the user responded "No") then the result code will be RESULT_CANCELED
.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_ENABLE_BT) { if (resultCode == RESULT_OK) { // 藍牙已經開啟 Log.d("h_bl", "藍牙已經開啟完畢"); String bluetoothName = bluetoothAdapter.getName(); // 獲取本地藍牙名稱 String bluetoothAddress = bluetoothAdapter.getAddress(); // 獲取本地藍牙地址 tv_bluetoothName.append(bluetoothName); tv_bluetoothAddress.append(bluetoothAddress); } else { Log.d("h_bl", "藍牙開啟失敗"); } } super.onActivityResult(requestCode, resultCode, data); }
其中,
private int REQUEST_ENABLE_BT = 1; // 藍牙打開的請求碼
Optionally, your application can also listen for the ACTION_STATE_CHANGED
broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed. This broadcast contains the extra fields EXTRA_STATE
and EXTRA_PREVIOUS_STATE
, containing the new and old Bluetooth states, respectively. Possible values for these extra fields areSTATE_TURNING_ON
, STATE_ON
, STATE_TURNING_OFF
, and STATE_OFF
. Listening for this broadcast can be useful to detect changes made to the Bluetooth state while your app is running.
可選的,你的應用可以監聽ACTION_STATE_CHANGED廣播intent,當系統藍牙狀態改變將會發起這個廣播,這個廣播包含了EXTRA_STATE和EXTRA_PREVIOUS_STATE額外的字段,包含了新的和舊的藍牙狀態分別的,可能 有STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF和STATE_OFF可能的值,監聽廣播能夠 對於檢測藍牙狀態改變是有用的。 --- 用來判斷藍牙是否開啟完畢
第3.1步:檢查當前的藍牙是否開啟完畢
// 藍牙狀態改變的廣播 private final BroadcastReceiver bluetoothState = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String stateExtra = BluetoothAdapter.EXTRA_STATE; int state = intent.getIntExtra(stateExtra, -1); switch (state) { case BluetoothAdapter.STATE_TURNING_ON: // 藍牙打開中 break; case BluetoothAdapter.STATE_ON: // 藍牙打開完成 break; case BluetoothAdapter.STATE_TURNING_OFF: // 藍牙關閉中 break; case BluetoothAdapter.STATE_OFF: // 藍牙關閉完成 break; } } }; // 藍牙狀態改變的廣播 IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(bluetoothState,new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); // 藍牙狀態改變的廣播
Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability, below.
提示:啟用程序會自動啟用藍牙。如果你打算開啟設備的可見性,可以跳過上面的2步。閱讀關於啟用可發現,下面。 --- 設置藍牙的可見性,就把Intent添加值,看第五步
第四步:尋找其他設備
Using the BluetoothAdapter
, you can find remote Bluetooth devices either through device discovery or by querying the list of paired (bonded) devices.
Device discovery is a scanning procedure that searches the local area for Bluetooth enabled devices and then requesting some information about each one (this is sometimes referred to as "discovering," "inquiring" or "scanning"). However, a Bluetooth device within the local area will respond to a discovery request only if it is currently enabled to be discoverable. If a device is discoverable, it will respond to the discovery request by sharing some information, such as the device name, class, and its unique MAC address. Using this information, the device performing discovery can then choose to initiate a connection to the discovered device.
Once a connection is made with a remote device for the first time, a pairing request is automatically presented to the user. When a device is paired, the basic information about that device (such as the device name, class, and MAC address) is saved and can be read using the Bluetooth APIs. Using the known MAC address for a remote device, a connection can be initiated with it at any time without performing discovery (assuming the device is within range).
Remember there is a difference between being paired and being connected. To be paired means that two devices are aware of each other's existence, have a shared link-key that can be used for authentication, and are capable of establishing an encrypted connection with each other. To be connected means that the devices currently share an RFCOMM channel and are able to transmit data with each other. The current Android Bluetooth API's require devices to be paired before an RFCOMM connection can be established. (Pairing is automatically performed when you initiate an encrypted connection with the Bluetooth APIs.)
The following sections describe how to find devices that have been paired, or discover new devices using device discovery.
Note: Android-powered devices are not discoverable by default. A user can make the device discoverable for a limited time through the system settings, or an application can request that the user enable discoverability without leaving the application. How to enable discoverability is discussed below.
使用BluetoothAdapter,你能夠打開可見性的設備(搜索到的藍牙設備)和已經配對的的設備列表。
設備發現是一個掃描程序,搜索本地區具有藍牙功能的設備,然后請求一些信息(這是有時被稱為“發現中”,“查詢中”或“掃描中”)。然而,只有局域網內的藍牙設備處於能夠被發現的狀態中,才能響應別的設備發送的發現請求。如果一個設備是可以被發現的,它會響應發現請求並共享一些信息,比如設備名稱、類別,並以唯一的MAC地址。使用此信息,該設備執行發現,然后選擇啟動一個初始化連接到設備。
當第一次去連接遠程設備的時候,會提交一個配對請求給用戶確認。當設備配對時,一些基本的信息會被保存,並可以通過APIs去讀取這些信息(such as the device name, class, and MAC address)。使用一個已知的MAC地址去連接設備的時候,無論該設備是否處於發現狀態,都可以去連接。(但設備是在范圍內)。
記住配對和連接之間的區別。已經配對的意味着兩個設備是互相認識對方的存在,已經有了一個用來認證的共享的key,然后可以建立一個加密的連接。而連接是說設備已經建立了RFCOMM通道,並可以交換數據。現在的Android Bluetooth APIs 需要在建立RFCOMM通道之前,需要先配對。(使用Bluetooth APIs初始化加密連接的時候,會自動匹配。)
下面的章節將介紹如何找到已配對的設備,或者使用設備發現發現新設備。
Note: Android設備默認是不可發現的。用戶可以通過系統設置使設備能在有限的時間內被發現,或 應用程序可以要求用戶在沒有離開該應用的時候使藍牙可見。
4.1 找到已經配對的設備
Before performing device discovery, its worth querying the set of paired devices to see if the desired device is already known. To do so, call getBondedDevices()
. This will return a Set of BluetoothDevice
s representing paired devices. For example, you can query all paired devices and then show the name of each device to the user, using an ArrayAdapter:
在執行“發現設備”之前,先獲取到已經配對設備的set是很有值得的。調用getBondedDevices()即可,會返回一組已配對的set。例如,你可以查詢已配對的設備,並利用ArrayAdapter去顯示它們的名字。
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } else { Toast.makeText(getApplicationContext(), "沒有找到已匹對的設備!", Toast.LENGTH_SHORT).show(); }
All that's needed from the BluetoothDevice
object in order to initiate a connection is the MAC address. In this example, it's saved as a part of an ArrayAdapter that's shown to the user. The MAC address can later be extracted in order to initiate the connection. You can learn more about creating a connection in the section about Connecting Devices.
通過BluetoothDevice的MAC地址去初始化連接,這里只是顯示給用戶看。MAC可以被提取,然后去初始化連接。你可以在 Connecting Devices章節學習到更多創建連接。
4.2 發現設備
調用startDiscovery()函數后,系統將掃描12秒,返回找到的藍牙設備。我們需用廣播來接收。
For each device, the system will broadcast the ACTION_FOUND
Intent. This Intent carries the extra fields EXTRA_DEVICE
and EXTRA_CLASS
, containing a BluetoothDevice
and a BluetoothClass
, respectively. For example, here's how you can register to handle the broadcast when devices are discovered:
每發現一個設備,系統就會發送ACTION_FOUND
Intent.的廣播,這個Intent攜帶額外的字段EXTRA_DEVICE
and EXTRA_CLASS,包含a
BluetoothDevice
and a BluetoothClass。
// Create a BroadcastReceiver for ACTION_FOUND private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
其中,需要調用
// 掃描藍牙設備 btAdapter.startDiscovery();
警告:Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery()
before attempting a connection。
Caution: Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources. Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery()
before attempting a connection. Also, if you already hold a connection with a device, then performing discovery can significantly reduce the bandwidth available for the connection, so you should not perform discovery while connected.
連接設備之前,要調用cancelDiscovery(),以便節約資源。並且不要執行連接的時候,去執行發現操作。
另外,需要取消廣播:
@Override protected void onDestroy() { unregisterReceiver(mReceiver); super.onDestroy(); }
第五步:設備的可發現時間設定,默認是120S。
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent);
The maximum duration an app can set is 3600 seconds, and a value of 0 means the device is always discoverable. Any value below 0 or above 3600 is automatically set to 120 secs)
一個應用程序可以設置最大持續時間為3600秒,填寫 0 的值表示設備總是發現。任何值低於0或高於3600自動設置為120秒。
會提示彈窗
Note: If Bluetooth has not been enabled on the device, then enabling device discoverability will automatically enable Bluetooth.
如果藍牙尚未啟用的設備,並使設備可發現將自動啟用藍牙。
The device will silently remain in discoverable mode for the allotted time. If you would like to be notified when the discoverable mode has changed, you can register a BroadcastReceiver for the ACTION_SCAN_MODE_CHANGED
Intent. This will contain the extra fields EXTRA_SCAN_MODE
andEXTRA_PREVIOUS_SCAN_MODE
, which tell you the new and old scan mode, respectively. Possible values for each areSCAN_MODE_CONNECTABLE_DISCOVERABLE
, SCAN_MODE_CONNECTABLE
, or SCAN_MODE_NONE
, which indicate that the device is either in discoverable mode, not in discoverable mode but still able to receive connections, or not in discoverable mode and unable to receive connections, respectively.
You do not need to enable device discoverability if you will be initiating the connection to a remote device. Enabling discoverability is only necessary when you want your application to host a server socket that will accept incoming connections, because the remote devices must be able to discover the device before it can initiate the connection.
可以接受“發現模式”的改變的廣播,會接收到ACTION_SCAN_MODE_CHANGED
Intent,包含額外的字段EXTRA_SCAN_MODE
andEXTRA_PREVIOUS_SCAN_MODE
,描述了新的和舊的掃描模式。其值可能是SCAN_MODE_CONNECTABLE_DISCOVERABLE
, SCAN_MODE_CONNECTABLE
, or SCAN_MODE_NONE。分別代表設備處於在發現模式;不可發現模式但仍能接收連接;不可發現模式和無法接收連接。
你不需要非得使設備可見,如果你初始化去連接到遠程設備的時候。當你作為主機 host a server socket,讓別的設備連接進來的時候,就必須是處於可見模式!因為遠程設備要發現主機,才可以初始化連接。