android实现手机通过蓝牙连接使用socket与芯片进行数据交换
来源:互联网 发布:淘宝转化率 编辑:程序博客网 时间:2024/05/16 08:18
1.权限的申请
<!--经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限--><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
如果设备支持LE蓝牙模式,注明:只有Android手机4.0,并且系统是4.3版本以上才支持LE蓝牙模式
要注明一点,如果是android手机与手机之间的socket通信则需要另外添加一条权限<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2.蓝牙连接通常都需要有一个service去实时实现与服务器端进行数据交互
a、b都是在Activity中的:
a.初始化并且判断设备是否支持BL技术
/** * 是否支持BLE蓝牙 */private void bltIsSupport() { if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); }获取蓝牙管理器和蓝牙适配器// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to // BluetoothAdapter through BluetoothManager.final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter(); // Checks if Bluetooth is supported on the device.if (mBluetoothAdapter == null) {Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();return;
}}/** * 检查蓝牙是否开启 */public void checkBleDevice(Context context) { if (mBluetoothAdapter != null) { //蓝牙若没开启便让它开启 if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(enableBtIntent); } } else { Log.i("blueTooth", "该手机不支持蓝牙"); }}b.在确认蓝牙开启以后,需要开始扫描周边蓝牙设备
/** * 开始扫描,如果已经再扫描种便不会再进行 * * @param enable 传入boolen值来决定扫描还是停止 */ private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { if (mScanning) { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback);// invalidateOptionsMenu(); } } }, SCAN_PERIOD); mScanning = true; //F000E0FF-0451-4000-B000-000000000000 mLeDevices.clear(); mHandler.sendEmptyMessage(1); mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } if (!connectResult) { mBluetoothLeService.connect(mDeviceAddress); } }这里面主要逻辑就是,延迟10秒发送停止扫描命令,然后清空之前扫描的开始扫描,这里要注意的是mLeScanCallback,这是系统中BluetoothAdapter中的一个回调函数,扫描命令都会默认执行该函数。/** * 蓝牙扫描设备回调函数 */private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { mLeDevices.add(device); mDeviceName = device.getName(); mDeviceAddress = device.getAddress(); mHandler.sendEmptyMessage(1); //如果找到对应地址的蓝牙,就绑定后台蓝牙服务,并注册各种广播接受者 if (mDeviceName.equals("EC1601010002775533")) { Intent gattServiceIntent = new Intent(MainActivity.this, BluetoothLeService.class); Log.d(TAG, "Try to bindService=" + bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE)); registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); if (mBluetoothLeService != null) { connectResult = mBluetoothLeService.connect(mDeviceAddress); Log.d(TAG, "Connect request result=" + connectResult); } } } }); } };当扫描到可匹配的蓝牙设备时,就会执行该函数,该函数可以获取到蓝牙设备的具体信息,通常获取名字和MAC地址,如果希望指定某一个蓝牙连接的话就可以加判断语句。当认为找到合适的蓝牙连接的话,就需要用到一个服务和一个广播接收者,接下来我先介绍这个服务里面的内容。Service中:
先自定义以下几个广播:连接public final static String ACTION_GATT_CONNECTED = "com.example.xy005_8.feizhuchu.ACTION_GATT_CONNECTED";
无连接public final static String ACTION_GATT_DISCONNECTED = "com.example.xy005_8.feizhuchu.ACTION_GATT_DISCONNECTED";
已发现蓝牙设备public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.xy005_8.feizhuchu.ACTION_GATT_SERVICES_DISCOVERED";
从服务器端接收到数据public final static String ACTION_DATA_AVAILABLE = "com.example.xy005_8.feizhuchu.ACTION_DATA_AVAILABLE";
其他数据
public final static String EXTRA_DATA = "com.example.xy005_8.feizhuchu.EXTRA_DATA";
用于与蓝牙特征识别码种的UUID比较
public final static UUID UUID_NOTIFY = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
用于与蓝牙服务种的UUID比较public final static UUID UUID_SERVICE = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
关于服务与activity的绑定,我就简单解释,贴代码,原理就是去继承Binder这个实现类,获取到IBinder对象,并返回给acitivity,
public final static String ACTION_GATT_CONNECTED = "com.example.xy005_8.feizhuchu.ACTION_GATT_CONNECTED";
无连接public final static String ACTION_GATT_DISCONNECTED = "com.example.xy005_8.feizhuchu.ACTION_GATT_DISCONNECTED";
已发现蓝牙设备public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.xy005_8.feizhuchu.ACTION_GATT_SERVICES_DISCOVERED";
从服务器端接收到数据public final static String ACTION_DATA_AVAILABLE = "com.example.xy005_8.feizhuchu.ACTION_DATA_AVAILABLE";
其他数据
public final static String EXTRA_DATA = "com.example.xy005_8.feizhuchu.EXTRA_DATA";
用于与蓝牙特征识别码种的UUID比较
public final static UUID UUID_NOTIFY = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");用于与蓝牙服务种的UUID比较public final static UUID UUID_SERVICE = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
由activity种的onreceiver方法去接收到BluetoothLeService这个对象,方便调用服务种的方法
public class LocalBinder extends Binder { public BluetoothLeService getService() { return BluetoothLeService.this; }}@Overridepublic IBinder onBind(Intent intent) { return mBinder;}@Overridepublic boolean onUnbind(Intent intent) { // After using a given device, you should make sure that BluetoothGatt.close() is called // such that resources are cleaned up properly. In this particular example, close() is // invoked when the UI is disconnected from the Service. close(); return super.onUnbind(intent);}private final IBinder mBinder = new LocalBinder();
c.初始化适配器对象和GATT回调函数的介绍
获取蓝牙管理器,并且获取到适配器对象mBluetoothAdapter ,用于查找到设备要执行connect方法时候使用
public boolean initialize() { // For API level 18 and above, get a reference to BluetoothAdapter through // BluetoothManager. if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.e(TAG, "Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false; } return true;}
这是很关键的一个回调函数
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
当连接状态发生改变的时候就会执行该方法,先是判断是否GATT连接成功,当连接成功时,是的话发出一个连接成功的广播,
失败则发出连接失败的广播,并且关闭GATT
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; Log.i(TAG, "oldStatus=" + status + " NewStates=" + newState); if(status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; mBluetoothGatt.close(); mBluetoothGatt = null; Log.i(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); } } }当蓝牙被匹配的时候执行该方法,这里要区分以下在前面定义的ACTION_GATT_SERVICES_DISCOVERED,这里是一旦发先有匹配的
就去判断该蓝牙的特征识别码的UUID是否与设备一致,一致则会发出ACTION_GATT_SERVICES_DISCOVERED。 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Log.w(TAG, "onServicesDiscovered received: " + status); findService(gatt.getServices()); } else { if(mBluetoothGatt.getDevice().getUuids() == null) Log.w(TAG, "onServicesDiscovered received: " + status); } }特征识别码一旦被服务器端读取成功,就会发送数据送达广播,该特征识别码会携带数据 @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } }一旦特征识别码改变也会发送该广播 @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.e(TAG, "OnCharacteristicWrite"); }还有其余的一些需要重写的方法就不一一列举了
d.findService方法和broadcastUpdate方法
用于判断特征识别码是否匹配
public void findService(List<BluetoothGattService> gattServices) { Log.i(TAG, "Count is:" + gattServices.size()); for (BluetoothGattService gattService : gattServices) { Log.i(TAG, gattService.getUuid().toString());Log.i(TAG, UUID_SERVICE.toString()); if(gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString())) { List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); Log.i(TAG, "Count is:" + gattCharacteristics.size()); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { if(gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString())) { Log.i(TAG, gattCharacteristic.getUuid().toString()); Log.i(TAG, UUID_NOTIFY.toString()); mNotifyCharacteristic = gattCharacteristic; setCharacteristicNotification(gattCharacteristic, true); broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); return; } } } } }
用于客户端连接时广播状态的改变
public void broadcastUpdate(final String action) { final Intent intent = new Intent(action); sendBroadcast(intent);}主要用于服务器返回特征识别码的时候,将数据读取出来以广播的形式发送到activity中
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { intent.putExtra(EXTRA_DATA, new String(data)); } sendBroadcast(intent);}
Activity中的广播接收者和服务:
注册自己定义的几个广播用于服务的连接
private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (!mBluetoothLeService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); } Log.e(TAG, "mBluetoothLeService is okay"); // Automatically connects to the device upon successful start-up initialization. mBluetoothLeService.connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; }};
private static IntentFilter makeGattUpdateIntentFilter() { //注册接收的事件 final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); intentFilter.addAction(BluetoothDevice.ACTION_UUID); return intentFilter;}
到此,就可以接收到服务器发送来的消息了,其中WriteValue方法实际上是调用
mBluetoothGatt.writeCharacteristic(mNotifyCharacteristic);即GATT中发送的特征识别码的方法。
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //连接成功 Log.e(TAG, "Only gatt, just wait"); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { //断开连接 mConnected = false; } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) //已找到可以连接的蓝牙 { mConnected = true; //判断是否连接的boolean值,没有的话执行connect函数 Utils.showToast("连接成功,现在可以进行通信了", MainActivity.this); Log.e(TAG, "In what we need"); mBluetoothLeService.WriteValue(Utils.addReturnStr("RBL=1")); } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //收到数据 Log.e(TAG, "RECV DATA"); data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);//特征码数据 if (data == null) { return; } Log.e(TAG, data); if (data.equals(Utils.addReturnStr("TBL=1"))) { mBluetoothLeService.WriteValue(Utils.addReturnStr("SBL=00006789")); Log.e(TAG, "SBL=00006789 is send"); } } }};顺带贴下连接的方法,实质就是获取到MAC地址,根据地址获取到设备,然后取执行系统的连接方法,执行时有执行GATT回调函数
public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false. if(mBluetoothGatt != null) { mBluetoothGatt.close(); mBluetoothGatt = null; } mBluetoothGatt = device.connectGatt(this, false, mGattCallback); //mBluetoothGatt.connect(); Log.d(TAG, "Trying to create a new connection."); return true; }
结语
总算是搞定了,第一次写博客,算是记录以下这段时间的心得,有不对之处望大家斧正。
阅读全文
0 0
- android实现手机通过蓝牙连接使用socket与芯片进行数据交换
- android通过蓝牙实现两台手机传输数据
- Android 手机端与服务器端通过http交换数据 Json
- 树莓派3B使用板载蓝牙与手机蓝牙进行Socket通信(RFCOMM)
- Android 使用Socket实现服务器与手机客户端的长连接五:使用队列封装请求
- Android 使用Socket实现服务器与手机客户端的长连接一:一对一聊天
- Android 使用Socket实现服务器与手机客户端的长连接六:二次封装
- Android 使用Socket实现服务器与手机客户端的长连接八
- Android客户端与服务器端通过SOCKET连接进行读写(将JSON数据转化为字符串后传输)
- 使用黑莓8900通过蓝牙连接华为交换机进行现场网络配置与操作(一)
- ubuntu如何通过蓝牙与手机连接上网
- Android手机客户端与Servlet交换数据
- android网络通信,与socket交换数据
- android手机通过蓝牙连接佳博打印机
- Anroid中两台手机连接同一wifi通过socket进行通信
- Android 使用Socket实现服务器与手机客户端的长连接四:使用回调函数与Service调用
- Android通过蓝牙与单片机(HC-05)进行通信,接收数据
- Android手机通过socket与pc通信
- 认真学习php面向对象-4
- 剑指Offer_面试题27_二叉搜索树与双向链表
- 2017中国增材制造产业创新峰会在泰州召开
- TCP基础知识
- 时光流逝
- android实现手机通过蓝牙连接使用socket与芯片进行数据交换
- 基于谓词筛选值序列Enumerable.Where()
- 序列补零、插值后对FFT变换的影响以及频率分辨率的理解
- ubuntu下配置wpsscan
- 数可重入性与不可冲入性及编写规范
- hpu暑假训练【最长公共子序列&&回溯输出】
- 《Android那些事》——Fragment的生命周期及常见问题
- PE文件 节表IMAGE_SECTION_HEADER的正确定位方法
- JZOJ5243【GDOI2018模拟8.8】超级绵羊异或 类欧几里得算法