Bluetooth結構 java
一、JAVA層
frameworks/base/core/java/android/bluetooth/
android
包含了bluetooth的JAVA類。
安全
二、JNI層
服務器
frameworks/base/core/jni/android_bluetooth_開頭的文件 app
定義了bluez經過JNI到上層的接口。
socket
frameworks/base/core/jni/android_server_bluetoothservice.cpp
tcp
調用硬件適配層的接口system/bluetooth/bluedroid/bluetooth.c
ide
三、bluez庫
工具
external/bluez/ 測試
這是bluez用戶空間的庫,開源的bluetooth代碼,包括不少協議,生成libbluetooth.so。
四、硬件適配層
system/bluetooth/bluedroid/bluetooth.c
包含了對硬件操做的接口
system/bluetooth/data/*
一些配置文件,複製到/etc/bluetooth/。
還有其餘一些測試代碼和工具。
1、簡略介紹Bluetooth開發使用到的類
一、BluetoothAdapter,藍牙適配器,可判斷藍牙設備是否可用等功能。
經常使用方法列舉以下:
cancelDiscovery() ,取消搜索過程,在進行藍牙設備搜索時,若是調用該方法會中止搜索。(搜索過程會持續12秒)
disable()關閉藍牙,也就是咱們常說的禁用藍牙。
enable()打開藍牙,這個方法打開藍牙但不會彈出提示,正常流程操做下,咱們會讓系統提示用戶是否打開藍牙設備。以下兩行代碼可輕鬆搞定。
Intent enabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler,reCode);//同startActivity(enabler);(在主Activity啓動一個二級Activity,reCode通常等於3,必定記得要在AndroidManifest.xml裏面添加藍牙權限)
getAddress()獲取本地藍牙地址
getDefaultAdapter()獲取默認BluetoothAdapter,實際上,也只有這一種方法獲取BluetoothAdapter
getName()獲取本地藍牙名稱
getRemoteDevice(String address)根據藍牙地址獲取遠程藍牙設備
getState()獲取本地藍牙適配器當前狀態(感受可能調試的時候更須要)
isDiscovering()判斷當前是否正在查找設備,是返回true
isEnabled()判斷藍牙是否打開,已打開返回true,不然,返回false
listenUsingRfcommWithServiceRecord(String name,UUID uuid)根據名稱,UUID建立並返回
BluetoothServerSocket,這是建立BluetoothSocket服務器端的第一步
startDiscovery()開始搜索,這是搜索的第一步
2.BluetoothDevice看名字就知道,這個類描述了一個藍牙設備
createRfcommSocketToServiceRecord(UUIDuuid)根據UUID建立並返回一個BluetoothSocket
這個方法也是咱們獲取BluetoothDevice的目的——建立BluetoothSocket
這個類其餘的方法,如getAddress(),getName(),同BluetoothAdapter
這個類有幾個隱藏方法,涉及到藍牙的自動配對,setPin,createBond,cancelPairingUserInput,等方法(須要經過java的反射,調用這幾個隱藏方法)
3.BluetoothServerSocket若是去除了Bluetooth相信你們必定再熟悉不過了,既然是Socket,方法就應該都差很少,
這個類一種只有三個方法
兩個重載的accept(),accept(inttimeout)二者的區別在於後面的方法指定了過期時間,須要注意的是,執行這兩個方法的時候,直到接收到了客戶端的請求(或是過時以後),都會阻塞線程,應該放在新線程裏運行!
還有一點須要注意的是,這兩個方法都返回一個BluetoothSocket,最後的鏈接也是服務器端與客戶端的兩個BluetoothSocket的鏈接
close()關閉!
4.BluetoothSocket,跟BluetoothServerSocket相對,是客戶端
一共5個方法,不出意外,都會用到
close(),關閉
connect()鏈接
getInptuStream()獲取輸入流
getOutputStream()獲取輸出流
getRemoteDevice()獲取遠程設備,這裏指的是獲取bluetoothSocket指定鏈接的那個遠程藍牙設備
2、藍牙設備的發現、查找。
1.基於安全性考慮,設置開啓可被搜索後,Android系統會默認給出120秒的時間,其餘設備能在這120秒內搜索到它。 BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
_bluetooth.startDiscovery();
3.關閉藍牙設備
BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
_bluetooth.disable();
4.建立藍牙客戶端
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID號));
socket.connect();
4.建立藍牙服務端
BluetoothServerSocket _serverSocket = _bluetooth.listenUsingRfcommWithServiceRecord(服務端名稱,UUID.fromeString(UUID號));
BluetoothSocket socket = _serverSocket.accept();
InputStream inputStream = socket.getInputStream();
3、相關代碼實現
注:tcp_ip模塊須要在系統setting模塊中,完成藍牙的配對,只有配對成功的,才能進行socket通訊(具體如何配對和如何自動配對,將在bluetoot3或者4中進行講解)
AndridManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.thecaseforbluetooth" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".BluetoothActivity" android:label="@string/title_activity_bluetooth" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnSearch" android:text="查找設備" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnExit" android:text="退出應用" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnDis" android:text="設置可被發現" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnserver" android:text="啓動服務端" /> <ToggleButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tbtnSwitch" android:text="開/關 藍牙設備" /> <ListView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/lvDevices" /> </LinearLayout>BluetoothActivity.java
package com.example.thecaseforbluetooth; import java.util.ArrayList; import java.util.Set; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import android.widget.ToggleButton; public class BluetoothActivity extends Activity { public Button searchBtn;//搜索藍牙設備 public Button exitBtn;//退出應用 public Button discoverBtn;//設置可被發現 public ToggleButton openBtn;//開關藍牙設備 public Button serverbtn; public ListView listView;//藍牙設備清單 public ArrayAdapter<String> adapter; public ArrayList<String> list =new ArrayList<String>(); private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); Set<BluetoothDevice> bondDevices ; public Context context ; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); searchBtn = (Button)findViewById(R.id.btnSearch); exitBtn = (Button)findViewById(R.id.btnExit); discoverBtn = (Button)findViewById(R.id.btnDis); openBtn = (ToggleButton)findViewById(R.id.tbtnSwitch); serverbtn = (Button)findViewById(R.id.btnserver); listView = (ListView)findViewById(R.id.lvDevices); context = getApplicationContext(); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,list); listView.setAdapter(adapter); openBtn.setChecked(false); //註冊廣播接收信號 IntentFilter intent = new IntentFilter(); intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver來取得搜索結果 intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); //每當掃描模式變化的時候,應用程序能夠爲經過ACTION_SCAN_MODE_CHANGED值來監聽全局的消息通知。好比,當設備中止被搜尋之後,該消息能夠被系統通知給應用程序。 intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); //每當藍牙模塊被打開或者關閉,應用程序能夠爲經過ACTION_STATE_CHANGED值來監聽全局的消息通知。 registerReceiver(searchReceiver, intent); //顯示已配對設備以及搜索未配對設備 searchBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(bluetoothAdapter.isDiscovering()){ bluetoothAdapter.cancelDiscovery(); } list.clear(); bondDevices = bluetoothAdapter.getBondedDevices(); for(BluetoothDevice device : bondDevices) { String str = " 已配對完成 " + device.getName() +" " + device.getAddress(); list.add(str); adapter.notifyDataSetChanged(); } bluetoothAdapter.startDiscovery(); } }); //退出應用 exitBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub BluetoothActivity.this.finish(); } }); //設置藍牙設備可發現 discoverBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent discoverIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverIntent); } }); //開關藍牙設備 openBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(openBtn.isChecked() == true){ bluetoothAdapter.disable(); } else if(openBtn.isChecked() == false){ bluetoothAdapter.enable(); } } }); //做爲服務端開啓 serverbtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub ServerThread serverThread = new ServerThread(bluetoothAdapter, context); Toast.makeText(context, "server 端啓動", 5000).show(); serverThread.start(); } }); listView.setOnItemClickListener(new ItemClickListener()); } @Override public void onStart() { super.onStart(); // If BT is not on, request that it be enabled. if(bluetoothAdapter == null){ Toast.makeText(context, "藍牙設備不可用", 5000).show(); } if (!bluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, 3); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private final BroadcastReceiver searchReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); BluetoothDevice device = null; if(BluetoothDevice.ACTION_FOUND.equals(action)){ device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() == BluetoothDevice.BOND_NONE) { Toast.makeText(context, device.getName()+"", 5000).show(); String str = " 未配對完成 " + device.getName() +" " + device.getAddress(); if (list.indexOf(str) == -1)// 防止重複添加 list.add(str); } adapter.notifyDataSetChanged(); } } }; public class ItemClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub if(bluetoothAdapter.isDiscovering()) bluetoothAdapter.cancelDiscovery(); String str = list.get(arg2); String address = str.substring(str.length() - 17); BluetoothDevice btDev = bluetoothAdapter.getRemoteDevice(address); ClientThread clientThread = new ClientThread(btDev, context); clientThread.start(); }} }Bluetoothprotocol.java
package com.example.thecaseforbluetooth; public interface Bluetoothprotocol { public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap"; public static final String PROTOCOL_SCHEME_RFCOMM = "btspp"; public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep"; public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex"; }ServerThread.java
package com.example.thecaseforbluetooth; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Message; import android.util.Log; import android.widget.Toast; public class ServerThread extends Thread { public BluetoothServerSocket mserverSocket; public BluetoothAdapter bluetoothAdapter; public BluetoothSocket socket; public Context context; public ServerThread(BluetoothAdapter bluetoothAdapter,Context context) { this.bluetoothAdapter = bluetoothAdapter; this.context = context; } public void run() { try { /* 建立一個藍牙服務器 * 參數分別:服務器名稱、UUID */ mserverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(Bluetoothprotocol.PROTOCOL_SCHEME_RFCOMM, UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); // /* 接受客戶端的鏈接請求 */ socket = mserverSocket.accept(); //下面代碼做者偷懶,讀寫另外起一個線程最好 //接收數據 byte[] buffer = new byte[1024]; int bytes; InputStream mmInStream = null; try { mmInStream = socket.getInputStream(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } System.out.println("zhoulc server"); while(true){ if( (bytes = mmInStream.read(buffer)) > 0 ) { byte[] buf_data = new byte[bytes]; for(int i=0; i<bytes; i++) { buf_data[i] = buffer[i]; } String s = new String(buf_data); System.out.println(s+"zhoulc server is in"); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }ClientThread.java
package com.example.thecaseforbluetooth; import java.io.IOException; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.widget.Toast; public class ClientThread extends Thread { public BluetoothSocket socket; public BluetoothDevice device; public Context context; public ClientThread(BluetoothDevice device,Context context){ this.device = device; this.context = context; } public void run() { try { //建立一個Socket鏈接:只須要服務器在註冊時的UUID號 socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); //鏈接 socket.connect(); //下面代碼做者偷懶,讀寫另外起一個線程最好 //發送數據 if (socket == null) { Toast.makeText(context, "連接失敗", 5000).show(); return; } System.out.println("zhoulc client"); while(true){ try { System.out.println("zhoulc client is in"); String msg = "hello everybody I am client"; OutputStream os = socket.getOutputStream(); os.write(msg.getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } } }