首先需要添加权限
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Android中的蓝牙是通过BluetoothAdapter来操作的,
//先获取BlueToothAdapter的实例 BluetoothAdapter blueToothAdapter=BluetoothAdapter.getDefaultAdapter();
打开蓝牙,断开蓝牙
//判断蓝牙是否打开 if (!bluetoothAdapter.isEnabled()) { //第一种 调用enable()直接打开 bluetoothAdapter.enable(); //断开蓝牙 bluetoothAdapter.disable(); Toast.makeText(this, "蓝牙功能已开启", Toast.LENGTH_SHORT).show(); }
设置蓝牙可见性,能被周围设备扫描到
if (bluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //设置最多可见时间为300秒 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); }
蓝牙的搜索功能
blueToothAdapter.startDiscovery();
当搜索到设备后系统会以广播的形式接收,自定义一个广播
class BluetoothReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { Log.e(getPackageName(), "找到新设备了"); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } } }
注册广播
//注册广播 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); registerReceiver(new BluetoothReceiver(), intentFilter);
注意 ,如果你的代码将运行在(Build.VERSION.SDK_INT >= 23)的设备上,需要获取设备的定位权限才能进行蓝牙搜索功能,并在代码中动态的申请权限.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
动态申请权限
private void requestPermission() { if (Build.VERSION.SDK_INT >= 23) { int checkAccessFinePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); if (checkAccessFinePermission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_ACCESS_LOCATION); Log.e(getPackageName(), "没有权限,请求权限"); return; } Log.e(getPackageName(), "已有定位权限"); //这里可以开始搜索操作 } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case REQUEST_PERMISSION_ACCESS_LOCATION: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.e(getPackageName(), "开启权限permission granted!"); //这里可以开始搜索操作 } else { Log.e(getPackageName(), "没有定位权限,请先开启!"); } } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
蓝牙的配对,调用BluetoothDevice的createBondde()方法,如果我们想监听配对的这个过程,那么我们可以为广播接收器再注册一个action。
try { Method method = null; method = BluetoothDevice.class.getMethod("createBond"); Log.e(getPackageName(), "开始配对"); method.invoke(device); flag = true; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { Log.e(getPackageName(), "配对失败"); e.printStackTrace(); }
如果想监听配对过程,可以通过广播的形式,在注册一个action
//绑定状态发生变化 intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
广播接收器中
if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (device.getBondState()) { case BluetoothDevice.BOND_NONE: Log.e(getPackageName(), "取消配对"); break; case BluetoothDevice.BOND_BONDING: Log.e(getPackageName(), "配对中"); break; case BluetoothDevice.BOND_BONDED: Log.e(getPackageName(), "配对成功"); break; } }
配对设配发送数据
发送数据分为客户端和服务端,通过Socket来进行消息交互
服务端
new Thread(new Runnable() { @Override public void run() { InputStream is = null; try { BluetoothServerSocket serverSocket = blueToothAdapter.listenUsingRfcommWithServiceRecord("serverSocket", uuid); mHandler.sendEmptyMessage(startService); BluetoothSocket accept = serverSocket.accept(); is = accept.getInputStream(); byte[] bytes = new byte[1024]; int length = is.read(bytes); Message msg = new Message(); msg.what = getMessageOk; msg.obj = new String(bytes, 0, length); mHandler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } }).start();
客户端
new Thread(new Runnable() { @Override public void run() { OutputStream os = null; try { BluetoothSocket socket = strArr.get(i).createRfcommSocketToServiceRecord(uuid); socket.connect(); os = socket.getOutputStream(); os.write("testMessage".getBytes()); os.flush(); mHandler.sendEmptyMessage(sendOver); } catch (Exception e) { e.printStackTrace(); } } }).start();
可以看到无论是服务端还是客户端,都需要新起一个子线程来操作。那么服务端和客户端是怎么识别对方的呢,那么就需要用到UUID了,只有当服务端和客户端的UUID相同的时候才能够建立连接。
private static final UUID uuid = UUID.fromString(Constants.CONNECTTION_UUID);
public static final String CONNECTTION_UUID = "fa87c0d0-afac-11de-8a39-0800200c9a66";