插件地址 https://github.com/852172891/XposedBLE
實現之前先了解一下android BLE的數據讀寫流程。
android BLE的數據讀寫流程
首先獲取BluetoothGatt
BluetoothGatt mGatt = device.connectGatt(mContext, false, gattCallback);
寫數據
boolean result = mGatt.writeCharacteristic(characteristic);
讀數據
mGatt.readCharacteristic(characteristic)
從上邊的代碼可以看出,藍牙的讀寫都是調用BluetoothGatt 中的方法。
下邊分別看一下BluetoothGatt 的writeCharacteristic和readCharacteristic實現。這兩個方法中參數都是BluetoothGattCharacteristic ,在BluetoothGattCharacteristic 中有兩個最重要的參數 protected byte[] mValue;
protected UUID mUuid;一個是傳輸的內容,一個是對應的UUID,做過藍牙開發的都知道這2 個參數的重要性。
/**
* Writes a given characteristic and its values to the associated remote device.
*
* <p>Once the write operation has been completed, the
* {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
* reporting the result of the operation.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic Characteristic to write on the remote device
* @return true, if the write operation was initiated successfully
*/
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
&& (characteristic.getProperties() &
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;
if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
BluetoothDevice device = service.getDevice();
if (device == null) return false;
synchronized(mDeviceBusy) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
try {
mService.writeCharacteristic(mClientIf, device.getAddress(),
characteristic.getInstanceId(), characteristic.getWriteType(),
AUTHENTICATION_NONE, characteristic.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
mDeviceBusy = false;
return false;
}
return true;
}
readCharacteristic 方法
/**
* Reads the requested characteristic from the associated remote device.
*
* <p>This is an asynchronous operation. The result of the read operation
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
*/
public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() &
BluetoothGattCharacteristic.PROPERTY_READ) == 0) return false;
if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
if (mService == null || mClientIf == 0) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
BluetoothDevice device = service.getDevice();
if (device == null) return false;
synchronized(mDeviceBusy) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
try {
mService.readCharacteristic(mClientIf, device.getAddress(),
characteristic.getInstanceId(), AUTHENTICATION_NONE);
} catch (RemoteException e) {
Log.e(TAG,"",e);
mDeviceBusy = false;
return false;
}
return true;
}
插件的實現
關鍵代碼:首先獲取 BluetoothGatt,hook readCharacteristic 和writeCharacteristic方法。
Class bluetooth = lpparam.classLoader.loadClass("android.bluetooth.BluetoothGatt");
try {
if (bluetooth != null) {
XposedHelpers.findAndHookMethod(bluetooth, "writeCharacteristic", BluetoothGattCharacteristic.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
BluetoothGattCharacteristic bluetoothGattCharacteristic = (BluetoothGattCharacteristic) param.args[0];
byte[] mValue = bluetoothGattCharacteristic.getValue();
String str = "";
if (mValue != null) {
for (int i = 0; i < mValue.length; i++) {
str += String.format("%x ", mValue[i]);
}
}
Log.e("packageName" + lpparam.packageName, "writeCharacteristic str :" + str + " bluetoothGattCharacteristic" + bluetoothGattCharacteristic.getUuid().toString());
}
});
XposedHelpers.findAndHookMethod(bluetooth, "readCharacteristic", BluetoothGattCharacteristic.class, new XC_MethodHook() {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
BluetoothGattCharacteristic bluetoothGattCharacteristic = (BluetoothGattCharacteristic) param.args[0];
byte[] mValue = bluetoothGattCharacteristic.getValue();
String str = "";
if (mValue != null) {
for (int i = 0; i < mValue.length; i++) {
str += String.format("%x ", mValue[i]);
}
}
Log.e("packageName" + lpparam.packageName, "readCharacteristic str :" + str + " bluetoothGattCharacteristic" + bluetoothGattCharacteristic.getUuid().toString());
}
});
}
} catch (Exception e) {
Log.e("wanghaha", e.toString());
}
效果展示:用某手環和它配套的app測試了一下
插件的意義
分析藍牙傳輸過程,當你沒有協議的時候。
我是IT小王,如果喜歡我的文章,可以掃碼關注我的微信公衆號