蓝牙(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。但很多读者可能发现,有很多型号的手机(可能是非Android系统的手机)之间使用了不同的程序也可以使用蓝牙进行通讯。从表面上看,它们之间几乎不可能使用同一个UUID。
实际上,UUID和TCP的端口一样,也有一些默认的值。例如,将蓝牙模拟成串口的服务就使用了一个标准的UUID:
00001101-0000-1000-8000-00805F9B34FB。除此之外,还有很多标准的UUID,如下面就是两个标准的UUID。
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" />