Android 支持的蓝牙协议栈有:java
蓝牙协议栈 | 说明 |
---|---|
Bluz | Linux官方蓝牙协议栈,最成熟的开源蓝牙协议栈,灵活高效。 |
BlueDroid | 从Android 4.2开始,Google在Android中推出了它和博通公司一块儿开发的BlueDroid以替代BlueZ,框架结构变得更为简洁和清晰。 |
BLE | 低功耗蓝牙协议栈,传输距离远,速率快。 |
Android 系统本地蓝牙表明本地的蓝牙适配器,也是全部蓝牙交互的入口点,能够对本地或者其余终端设备进行操做。其中 BluetoothAdapter 是重要的类,表明本地蓝牙适配器。android
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // null:表示不支持蓝牙 boolean enabled = mBluetoothAdapter.isEnabled(); // true:处于打开状态, false:处于关闭状态
// 添加蓝牙权限,不须要动态受权 // <uses-permission android:name="android.permission.BLUETOOTH" /> // <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
在AndroidManifest文件中添加须要的权限:sql
<!-- 适配Android6.0/7.0 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
因为蓝牙所须要的权限包含Dangerous Permissions,因此咱们须要在Java代码中进行动态受权处理:markdown
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); }
接下来咱们就能够静默开启和关闭本地蓝牙了:网络
mBluetoothAdapter.enable(); // 开启 //mBluetoothAdapter.disable(); // 关闭
搜索分为主动搜索和被动搜索。咱们开始进行主动搜索:框架
1.建立 BluetoothAdapter 对象,首先获取已经配对的蓝牙设备:socket
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices(); // 获取已经配对的蓝牙设备
2.下面咱们定义广播接收器ide
// 设置广播信息过滤 IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一个设备就会发送一个该广播 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//当所有搜索完后发送该广播 filter.setPriority(Integer.MAX_VALUE);//设置优先级 // 注册蓝牙搜索广播接收者,接收并处理搜索结果 this.registerReceiver(receiver, filter);
3.开始搜索周边蓝牙:ui
//若是当前在搜索,就先取消搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } //开启搜索 mBluetoothAdapter.startDiscovery();
两个蓝牙设备进行链接时须要使用同一个UUID。但不少读者可能发现,有不少型号的手机(多是非Android系统的手机)之间使用了不一样的程序也可使用蓝牙进行通信。从表面上看,它们之间几乎不可能使用同一个UUID。this
UUID的格式以下:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UUID的格式被分红5段,其中中间3段的字符数相同,都是4,第1段是8个字符,最后一段是12个字符。因此UUID其实是一个8-4-4-4-12的字符串。
实际上,UUID和TCP的端口同样,也有一些默认的值。例如,将蓝牙模拟成串口的服务就使用了一个标准的UUID:
00001101-0000-1000-8000-00805F9B34FB
除此以外,还有不少标准的UUID,以下面就是两个标准的UUID:
信息同步服务:00001104-0000-1000-8000-00805F9B34FB 文件传输服务:00001106-0000-1000-8000-00805F9B34FB
经过蓝牙传输数据与Socket相似。在网络中使用Socket和ServerSocket控制客户端和服务端的数据读写。而蓝牙通信也由客户端和服务端Socket来完成。蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket。这两个类都在android.bluetooth包中。
不管是BluetoothSocket,仍是BluetoothServerSocket,都须要一个UUID(全局惟一标识符,Universally Unique Identifier),UUID至关于Socket的端口,而蓝牙地址至关于Socket的IP。
咱们开始进行模拟一个蓝牙数据的传输:
首先来看客户端:
(1)定义全局常量变量
private ListView lvDevices; private BluetoothAdapter mBluetoothAdapter; private List<String> bluetoothDevices = new ArrayList<String>(); private ArrayAdapter<String> arrayAdapter; private final UUID MY_UUID = UUID .fromString("abcd1234-ab12-ab12-ab12-abcdef123456");//随便定义一个 private BluetoothSocket clientSocket; private BluetoothDevice device; private OutputStream os;//输出流
(2)在onCreate方法中作初始化操做
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
lvDevices = (ListView) findViewById(R.id.lv_devices);
//获取已经配对的蓝牙设备 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { bluetoothDevices.add(device.getName() + ":"+ device.getAddress()); } } arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices); lvDevices.setAdapter(arrayAdapter); lvDevices.setOnItemClickListener(this);//Activity实现OnItemClickListener接口 //每搜索到一个设备就会发送一个该广播 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(receiver, filter); //当所有搜索完后发送该广播 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(receiver, filter);
蓝牙设备的广播接收器以下:
/** * 定义广播接收器 */ private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { bluetoothDevices.add(device.getName() + ":" + device.getAddress()); arrayAdapter.notifyDataSetChanged();//更新适配器 } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //已搜素完成 } } };
(4)咱们建立一个Button按钮,当点击Button时进行搜索,Button点击事件以下:
//若是当前在搜索,就先取消搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } //开启搜索 mBluetoothAdapter.startDiscovery();
(5)接下来咱们设置列表的点击事件:
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String s = arrayAdapter.getItem(position); String address = s.substring(s.indexOf(":") + 1).trim();//把地址解析出来 //主动链接蓝牙服务端 try { //判断当前是否正在搜索 if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } try { if (device == null) { //得到远程设备 device = mBluetoothAdapter.getRemoteDevice(address); } if (clientSocket == null) { //建立客户端蓝牙Socket clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID); //开始链接蓝牙,若是没有配对则弹出对话框提示咱们进行配对 clientSocket.connect(); //得到输出流(客户端指向服务端输出文本) os = clientSocket.getOutputStream(); } } catch (Exception e) { } if (os != null) { //往服务端写信息 os.write("蓝牙信息来了".getBytes("utf-8")); } } catch (Exception e) { } }
(2)定义服务端线程类:
private Handler handler = new Handler() { public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), String.valueOf(msg.obj), Toast.LENGTH_LONG).show(); super.handleMessage(msg); } }; //服务端监听客户端的线程类 private class AcceptThread extends Thread { public AcceptThread() { try { serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (Exception e) { } } public void run() { try { socket = serverSocket.accept(); is = socket.getInputStream(); while(true) { byte[] buffer =new byte[1024]; int count = is.read(buffer); Message msg = new Message(); msg.obj = new String(buffer, 0, count, "utf-8"); handler.sendMessage(msg); } } catch (Exception e) { } } }
(3)在onCreate方法中初始化线程类并开启
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
acceptThread = new AcceptThread();
acceptThread.start();
咱们运行程序看一下效果图:
点击“搜索蓝牙设备”按钮,就会搜索到另外一台手机的蓝牙信息,咱们点击条目,另外一台手机会出现以下变化:
弹出Toast,此时证实咱们的蓝牙数据已经传输过来了。