A simple BLE Android client
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
dependencies {
implementation 'com.github.Karewan:KnBle:3.0.5'
}Do not forget to add internet permissions in manifest
<!-- For all Android versions -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--
Android 6+: Needed for BLE scan
Optionnal permission on Android 12+, use only if you need to derive location from scan results
neverForLocation is optional, please also set the never location in the scanner settings default => true
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" android:usesPermissionFlags="neverForLocation"/>
<!-- Android 10+: For background BLE scan (Optional) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:minSdkVersion="31"/>
<!-- Android 12+: BLE scan (neverForLocation is optional, please also set the never location in the scanner settings default => true) -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:minSdkVersion="31" android:usesPermissionFlags="neverForLocation"/>
<!-- Android 12+: BLE connect to already paired device -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />Then initialize, return false if device is not BLE compatible
boolean success = KnBle.gi().init(getApplicationContext());At any time you can check if the initialization is correct, return false if the device is not BLE compatible
boolean isInit = KnBle.gi().isInit();KnBle.gi().startScan(new BleScanCallback() {
@Override
public void onScanStarted() {
}
@Override
public void onScanFailed(int error) {
// BleScanCallback.BT_DISABLED
// BleScanCallback.LOCATION_DISABLED
// BleScanCallback.SCANNER_UNAVAILABLE
// BleScanCallback.UNKNOWN_ERROR
// BleScanCallback.SCAN_FEATURE_UNSUPPORTED
}
@Override
public void onScanResult(@NonNull BleDevice bleDevice) {
}
@Override
public void onDeviceUpdated(@NonNull BleDevice bleDevice) {
}
@Override
public void onScanFinished(@NonNull List<BleDevice> scanResult) {
}
});KnBle.gi().stopScan();// Check ScanSettings class to see all settings
ScanSettings settings = new ScanSettings.Builder().build();
KnBle.gi().setScanSettings(settings);// Check ScanFilters class to see all filters
ScanFilters filters = new ScanFilters.Builder().build();
KnBle.gi().setScanFilter(filters);boolean isScanning = KnBle.gi().isScanning();int error = KnBle.gi().getLastError();ScanSettings settings = KnBle.gi().getScanSettings();ScanFilters filters = KnBle.gi().getScanFilters();@NonNull
List<BleDevice> devices = KnBle.gi().getScannedDevices();KnBle.gi().clearScannedDevices();KnBle.gi().resetScan(true, true);@Nullable
BleDevice device = KnBle.gi().getBleDeviceFromMac("FF:FF:FF:FF:FF:FF");@NonNull
List<BleDevice> devices = KnBle.gi().getConnectedDevices();boolean connected = KnBle.gi().isConnected(device);int state = KnBle.gi().getDeviceConnState(device);
// BleGattCallback.DISCONNECTED
// BleGattCallback.CONNECTING
// BleGattCallback.CONNECTEDKnBle.gi().connect(device, new BleGattCallback() {
@Override
public void onConnecting() {
}
@Override
public void onConnectSuccess(@NonNull List<BluetoothGattService> services) {
}
@Override
public void onDisconnected(boolean connectFailed) {
}
});KnBle.gi().getService(device, "service uuid", new BleGetService() {
@Override
public void onSuccess(@NonNull BluetoothGattService service) {
}
@Override
public void onFailed() {
}
});
// OR
KnBle.gi().getService(device, serviceUUID, new BleGetService() {
@Override
public void onSuccess(@NonNull BluetoothGattService service) {
}
@Override
public void onFailed() {
}
});KnBle.gi().getCharacteristic(device, "service uuid", "characteristic uuid", new BleGetCharacteristic() {
@Override
public void onSuccess(@NonNull BluetoothGattCharacteristic characteristic) {
}
@Override
public void onFailed() {
}
});
// OR
KnBle.gi().getCharacteristic(device, serviceUUID, characteristicUUID, new BleGetCharacteristic() {
@Override
public void onSuccess(@NonNull BluetoothGattCharacteristic characteristic) {
}
@Override
public void onFailed() {
}
});KnBle.gi().getDescriptor(device, "service uuid", "characteristic uuid", "descriptor uuid", new BleGetDescriptor() {
@Override
public void onSuccess(@NonNull BluetoothGattDescriptor descriptor) {
}
@Override
public void onFailed() {
}
});
// OR
KnBle.gi().getDescriptor(device, serviceUUID, characteristicUUID, descriptorUUID, new BleGetDescriptor() {
@Override
public void onSuccess(@NonNull BluetoothGattDescriptor descriptor) {
}
@Override
public void onFailed() {
}
});KnBle.gi().read(device, "service uuid", "characteristic uuid", new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});
// OR
KnBle.gi().read(device, serviceUUID, characteristicUUID, new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});
// OR
KnBle.gi().read(device, service, characteristic, new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});KnBle.gi().write(device, "service uuid", "characteristic uuid", data, noResponse, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().write(device, serviceUUID, characteristicUUID, data, noResponse, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().write(device, service, characteristic, data, noResponse, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});KnBle.gi().splittedWrite(device, "service uuid", "characteristic uuid", data, splitSize, noResponse, intervalBetweenTwoPackage, new BleSplittedWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteProgress(int current, int total) {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().splittedWrite(device, serviceUUID, characteristicUUID, data, splitSize, noResponse, intervalBetweenTwoPackage, new BleSplittedWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteProgress(int current, int total) {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().splittedWrite(device, service, characteristic, data, splitSize, noResponse, intervalBetweenTwoPackage, new BleSplittedWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteProgress(int current, int total) {
}
@Override
public void onWriteSuccess() {
}
});KnBle.gi().enableNotify(device, "service uuid", "characteristic uuid", new BleNotifyCallback() {
@Override
public void onNotifyEnabled() {
}
@Override
public void onNotifyDisabled() {
}
@Override
public void onNotify(@NonNull byte[] data) {
}
});
// OR
KnBle.gi().enableNotify(device, serviceUUID, characteristicUUID, new BleNotifyCallback() {
@Override
public void onNotifyEnabled() {
}
@Override
public void onNotifyDisabled() {
}
@Override
public void onNotify(@NonNull byte[] data) {
}
});
// OR
KnBle.gi().enableNotify(device, service, characteristic, new BleNotifyCallback() {
@Override
public void onNotifyEnabled() {
}
@Override
public void onNotifyDisabled() {
}
@Override
public void onNotify(@NonNull byte[] data) {
}
});KnBle.gi().disableNotify(device, "service uuid", "characteristic uuid");
// OR
KnBle.gi().disableNotify(device, serviceUUID, characteristicUUID);
// OR
KnBle.gi().disableNotify(device, service, characteristic);KnBle.gi().readDesc(device, "service uuid", "characteristic uuid", "descriptor uuid", new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});
// OR
KnBle.gi().readDesc(device, serviceUUID, characteristicUUID, descriptorUUID, new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});
// OR
KnBle.gi().readDesc(device, service, characteristic, descriptor new BleReadCallback() {
@Override
public void onReadSuccess(@NonNull byte[] data) {
}
@Override
public void onReadFailed() {
}
});KnBle.gi().writeDesc(device, "service uuid", "characteristic uuid", "descriptor uuid", data, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().writeDesc(device, serviceUUID, characteristicUUID, descriptorUUID, data, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});
// OR
KnBle.gi().writeDesc(device, service, characteristic, descriptor, data, new BleWriteCallback() {
@Override
public void onWriteFailed() {
}
@Override
public void onWriteSuccess() {
}
});KnBle.gi().requestConnectionPriority(device, connectionPriority);int mtu = KnBle.gi().getMtu(device);KnBle.gi().requestMtu(device, mtu);
// OR
KnBle.gi().requestMtu(device, mtu, new BleMtuChangedCallback() {
@Override
public void onMtuChanged(int mtu) {
}
});KnBle.gi().readPhy(device, new BlePhyValueCallback() {
@Override
public void onPhyValue(int txPhy, int rxPhy) {
}
});KnBle.gi().setPreferredPhy(device, txPhy, rxPhy, phyOptions);
// OR
KnBle.gi().setPreferredPhy(device, txPhy, rxPhy, phyOptions, new BlePhyValueCallback() {
@Override
public void onPhyValue(int txPhy, int rxPhy) {
}
});KnBle.gi().setGattCallback(device, newCallback);KnBle.gi().disconnect(device);KnBle.gi().disconnectAll();@Nullable
BluetoothGatt gatt = KnBle.gi().getBluetoothGatt(device);KnBle.gi().destroyDevice(device);KnBle.gi().destroyAllDevices();boolean enabled = KnBle.gi().isBluetoothEnabled();// Enable
KnBle.gi().enableBluetooth(true);
// Disable
KnBle.gi().enableBluetooth(false);@Nullable
BluetoothAdapter adapter = KnBle.gi().getBluetoothAdapter();@Nullable
BluetoothManager btManager = KnBle.gi().getBluetoothManager();@Nullable
Context ctx = KnBle.gi().getContext();KnBle.DEBUG = false;The MIT License (MIT)
Copyright (c) 2019-2025 Florent VIALATTE
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.