16、蓝牙技术

蓝牙简介

        蓝牙(Bluetooth)是一种短距离的无线通信技术标准。这个名子来源于10世纪丹麦国王Harald Blatand,英文名子是Harold Bluetooth。在无线行业协会组织人员的讨论后,有人认为用Blatand国王的名字命名这种无线技术是再好不过了,这是因为Blatand国王将挪威、瑞典和丹麦统一起来,这就如同这项技术将统一无线通信领域一样。至此,蓝牙的名字也就这样定了下来。

       蓝牙协议分为4层,即核心协议层、电缆替代协议层、电话控制协议层和采纳的其它协议层。这4种协议中最重要的是核心协议。蓝牙的核心协议包括基带、链路管理、逻辑链路控制和适应协议四部分。其中链路管理(LMP)负责蓝牙组件间连接的建立。逻辑链路控制与适应协议(L2CAP)位于基带协议层上,属于数据链路层,是一个为高层传输和应用层协议屏蔽基带协议的适配协议。

打开和关闭蓝牙设备

第1种打开蓝牙的方式

Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableIntent, 1);

必须设置权限

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

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

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()

adapter.enable();

adapter.disable();

搜索蓝牙设备

蓝牙数据传输

      通过蓝牙传输数据与Socket类似。在网络中使用Socket和ServerSocket控制客户端和服务端的数据读写。而蓝牙通讯也由客户端和服务端Socket来完成。蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket。这两个类都在android.bluetooth包中。

      无论是BluetoothSocket,还是BluetoothServerSocket,都需要一个UUID(全局唯一标识符,Universally Unique Identifier).格式如下:

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

UUID的格式被分成5段,其中中间3段的字符数相同,都是4,第1段是8个字符,最后一段是12个字符。所以UUID实际上是一个8-4-4-4-12的字符串。

UUID相当于Socket的端口,而蓝牙地址相当于Socket的IP。

蓝牙的UUID

      两个蓝牙设备进行连接时需要使用同一个UUID。但很多读者可能发现,有很多型号的手机(可能是非Android系统的手机)之间使用了不同的程序也可以使用蓝牙进行通讯。从表面上看,它们之间几乎不可能使用同一个UUID。 

       实际上,UUID和TCP的端口一样,也有一些默认的值。例如,将蓝牙模拟成串口的服务就使用了一个标准的UUID:

00001101-0000-1000-8000-00805F9B34FB。除此之外,还有很多标准的UUID,如下面就是两个标准的UUID。

信息同步服务:00001104-0000-1000-8000-00805F9B34FB
文件传输服务:00001106-0000-1000-8000-00805F9B34FB
 
DEMO:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent"
 4     android:layout_height="fill_parent"
 5     android:orientation="vertical" >
 6 
 7     <Button
 8         android:layout_width="fill_parent"
 9         android:layout_height="wrap_content"
10         android:onClick="onClick_Search"
11         android:text="搜索" />
12 
13     <ListView
14         android:id="@+id/lvDevices"
15         android:layout_width="fill_parent"
16         android:layout_height="wrap_content" />
17 
18 </LinearLayout>
  1 import java.io.InputStream;
  2 import java.io.OutputStream;
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Set;
  6 import java.util.UUID;
  7 
  8 import android.app.Activity;
  9 import android.bluetooth.BluetoothAdapter;
 10 import android.bluetooth.BluetoothDevice;
 11 import android.bluetooth.BluetoothServerSocket;
 12 import android.bluetooth.BluetoothSocket;
 13 import android.content.BroadcastReceiver;
 14 import android.content.Context;
 15 import android.content.Intent;
 16 import android.content.IntentFilter;
 17 import android.os.Bundle;
 18 import android.os.Handler;
 19 import android.os.Message;
 20 import android.view.View;
 21 import android.view.Window;
 22 import android.widget.AdapterView;
 23 import android.widget.AdapterView.OnItemClickListener;
 24 import android.widget.ArrayAdapter;
 25 import android.widget.ListView;
 26 import android.widget.Toast;
 27 
 28 /**
 29  * 单击列表项蓝牙设备,去连接另外一个蓝牙设备,并且进行配对,
 30  * 配对完后,将一个文本信息,传递过去。
 31  * @author dr
 32  *
 33  */
 34 public class Main extends Activity implements OnItemClickListener {
 35 
 36     private ListView lvDevices;   // 蓝牙列表
 37     private BluetoothAdapter bluetoothAdapter;  // 蓝牙适配器
 38     // 用于储存所有搜索到的蓝牙名称和地址。
 39     private List<String> bluetoothDevices = new ArrayList<String>();
 40     // 数组适配器,显示列表
 41     private ArrayAdapter<String> arrayAdapter;
 42     // 
 43     private final UUID MY_UUID = UUID
 44             .fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
 45     // 自定义
 46     private final String NAME = "Bluetooth_Socket";
 47     // 客户端。
 48     private BluetoothSocket clientSocket;
 49     private BluetoothDevice device;
 50     //  
 51     private AcceptThread acceptThread;
 52     // 输出流(从客户端往服务端进行输出)。
 53     private OutputStream os;
 54     
 55     private Handler handler = new Handler() {
 56         public void handleMessage(Message msg) {
 57             Toast.makeText(Main.this, String.valueOf(msg.obj),
 58                     Toast.LENGTH_LONG).show();
 59             super.handleMessage(msg);
 60         }
 61     };
 62 
 63     @Override
 64     public void onCreate(Bundle savedInstanceState) {
 65         super.onCreate(savedInstanceState);
 66 
 67         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
 68         setContentView(R.layout.main);
 69         
 70         lvDevices = (ListView) findViewById(R.id.lvDevices);
 71 
 72         // 得到 BluetoothAdapter对象。
 73         bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 74 
 75         // 得到已经配对的蓝牙,显示出来
 76         Set<BluetoothDevice> pairedDevices = bluetoothAdapter
 77                 .getBondedDevices();   
 78         if (pairedDevices.size() > 0) {  // 已经配完对的。
 79             for (BluetoothDevice device : pairedDevices) {
 80                 bluetoothDevices.add(device.getName() + ":"
 81                         + device.getAddress() + "
");
 82             }
 83         }
 84 
 85         // 将所有设备,显示在列表上。
 86         arrayAdapter = new ArrayAdapter<String>(this,
 87                 android.R.layout.simple_list_item_1, android.R.id.text1,
 88                 bluetoothDevices);
 89 
 90         lvDevices.setAdapter(arrayAdapter);
 91         lvDevices.setOnItemClickListener(this);
 92         
 93         // 每找到一个设备,发送一个广播。
 94         IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
 95         this.registerReceiver(receiver, filter);
 96 
 97         // 全部搜索完后,发送一个广播。
 98         filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
 99         this.registerReceiver(receiver, filter);
100         
101         // 实例化,并且启动。
102         acceptThread = new AcceptThread();
103         acceptThread.start();
104     }
105 
106     public void onClick_Search(View view) {
107         // 显示进度条,扫描状态。
108         setProgressBarIndeterminateVisibility(true);
109         setTitle("正在扫描...");
110         // 判断是否正在搜索。
111         if (bluetoothAdapter.isDiscovering()) {
112             bluetoothAdapter.cancelDiscovery();
113         }
114         bluetoothAdapter.startDiscovery();
115     }
116 
117     /** 广播接收器 */ 
118     private final BroadcastReceiver receiver = new BroadcastReceiver() {
119         @Override
120         public void onReceive(Context context, Intent intent) {
121             String action = intent.getAction();
122             // 当搜索到一个设备时
123             if (BluetoothDevice.ACTION_FOUND.equals(action)) {
124                 // 获得这个设备的信息。
125                 BluetoothDevice device = intent
126                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
127                 // 判断当前设备没有被绑定。
128                 if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
129                     bluetoothDevices.add(device.getName() + ":"
130                             + device.getAddress() + "
");
131                     arrayAdapter.notifyDataSetChanged();
132                 }
133             // 已经完成的情况。
134             } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
135                     .equals(action)) {
136                 // 关闭进度条。
137                 setProgressBarIndeterminateVisibility(false);
138                 setTitle("连接蓝牙设备");
139             }
140         }
141     };
142 
143     @Override    /** 客户端 */ 
144     public void onItemClick(AdapterView<?> parent, View view, int position,
145             long id) {
146         String s = arrayAdapter.getItem(position);
147         // 得到地址,相当于ip
148         String address = s.substring(s.indexOf(":") + 1).trim();
149 
150         try {
151             // 判断是否在搜索
152             if (bluetoothAdapter.isDiscovering()) {  
153                 bluetoothAdapter.cancelDiscovery();
154             }
155             try {
156                 if (device == null) {
157                     // 得到远程设备。
158                     device = bluetoothAdapter.getRemoteDevice(address);
159                 }
160                 if (clientSocket == null) {
161                     // 得到UUID
162                     clientSocket = device
163                             .createRfcommSocketToServiceRecord(MY_UUID);
164                     // 开始连接。
165                     clientSocket.connect();
166                     // 获得输出流。
167                     os = clientSocket.getOutputStream();
168                 }
169             } catch (Exception e) {
170                 // TODO: handle exception
171             }
172             if (os != null) {
173                 os.write("发送信息到其他蓝牙设备".getBytes("utf-8"));
174             }
175         } catch (Exception e) {
176             // TODO: handle exception
177         }
178     }
179 
180     /** 服务端的东西 */  
181     private class AcceptThread extends Thread {
182         private BluetoothServerSocket serverSocket;
183         private BluetoothSocket socket;
184         private InputStream is;
185         private OutputStream os;
186 
187         public AcceptThread() {
188             try {
189                 serverSocket = bluetoothAdapter
190                         .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
191             } catch (Exception e) {
192                 // TODO: handle exception
193             }
194         }
195 
196         public void run() {  
197             // 截获 客户端的  信息。
198             try {
199                 socket = serverSocket.accept();
200                 is = socket.getInputStream();
201                 os = socket.getOutputStream();
202 
203                 while (true) {
204                     byte[] buffer = new byte[128];
205                     int count = is.read(buffer);
206                     Message msg = new Message();
207                     msg.obj = new String(buffer, 0, count, "utf-8");
208                     handler.sendMessage(msg);
209                 }
210             } catch (Exception e) {
211                 // TODO: handle exception
212             }
213 
214         }
215     }
216 
217 }
1 <uses-permission android:name="android.permission.BLUETOOTH" />
2 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 
 
 
 
 
原文地址:https://www.cnblogs.com/androidsj/p/3857257.html