You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android BLE写入回调onCharacteristicWrite返回GATT_WRITE_NOT_PERMITTED求助

Hey there! Let’s troubleshoot why your custom Android BLE app is giving you grief with the HM-10 module—especially since you confirmed other store apps work fine with it. I’ve spent a fair bit of time tinkering with HM-10s, so let’s walk through the most common pitfalls and check your code against them.

1. Double-Check HM-10’s Service & Characteristic UUIDs

HM-10 modules almost universally use the full 128-bit UUIDs:

  • Service UUID: 0000ffe0-0000-1000-8000-00805f9b34fb
  • Write/Read Characteristic UUID: 0000ffe1-0000-1000-8000-00805f9b34fb

A super common mistake is using the short FFE0/FFE1 UUIDs instead of the full version—Android requires the full 128-bit format for non-standard BLE profiles, so skipping this will break service/characteristic discovery.

2. Nail Down Permissions (Critical for Android 10+)

If you’re targeting Android 10 (API 29) or higher, missing runtime permissions is one of the top culprits:

  • For scanning: BLUETOOTH_SCAN (add android:usesPermissionFlags="neverForLocation" if you don’t need location data; pre-Android 12, you’ll still need ACCESS_FINE_LOCATION for BLE scanning)
  • For connecting/writing: BLUETOOTH_CONNECT

Make sure these are added to your AndroidManifest.xml and that you request them at runtime before attempting any BLE operations.

3. Follow the Correct Asynchronous Connection Flow

BLE is inherently asynchronous—you can’t call connectGatt() and immediately try to write a characteristic. You need to wait for each step to complete via callbacks:

  1. Call bluetoothDevice.connectGatt(context, false, gattCallback)
  2. Wait for onConnectionStateChange() to confirm STATE_CONNECTED, then call gatt.discoverServices()
  3. Wait for onServicesDiscovered() to fire (with GATT_SUCCESS status), then retrieve the HM-10 service and characteristic
  4. Only then attempt to write data

If you’re skipping any of these steps (like writing before services are discovered), your app will fail silently or throw errors.

4. Verify Characteristic Write Properties

HM-10’s FFE1 characteristic supports both WRITE and WRITE_NO_RESPONSE properties, but you need to confirm this before writing. Add a check in onServicesDiscovered():

if ((writeChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0 ||
    (writeChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) {
    // Safe to proceed with writes
}

Also, set the correct write type before sending data—HM-10 often works better with WRITE_TYPE_NO_RESPONSE for faster transfers:

writeChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
5. MAC Address Connection Caveats

Using a hardcoded MAC address works, but keep these in mind:

  • Ensure the MAC is formatted correctly (uppercase, colon-separated: AA:BB:CC:DD:EE:FF)
  • On Android 12+, you need to have scanned the device recently or have it paired to connect via MAC (due to privacy restrictions)
  • HM-10s typically use static MACs, but double-check yours with a BLE scanner app if you’re unsure
6. Debug Your Gatt Callback Thoroughly

Add logs to every callback in your BluetoothGattCallback to pinpoint where things are breaking:

  • Does onConnectionStateChange() ever hit STATE_CONNECTED, or does it disconnect immediately?
  • Does onServicesDiscovered() return GATT_SUCCESS, or an error like GATT_FAILURE?
  • Does onCharacteristicWrite() fire, and what’s the status code? (0 = success; any other code means failure—look up BluetoothGatt error constants for details)

For example, if onServicesDiscovered() returns GATT_FAILURE, it might mean the HM-10 didn’t respond to the service discovery request (try adding a short delay before calling discoverServices()).

7. Stick to Main Thread & Check Adapter State

All BLE operations (connect, discover services, write characteristics) must run on the main thread—Android’s BLE APIs are not thread-safe. Also, always confirm the Bluetooth adapter is enabled before attempting to connect:

if (!bluetoothAdapter.isEnabled()) {
    // Prompt user to enable Bluetooth
}
Example Working Code Snippet

Here’s a condensed version of a reliable HM-10 write flow:

private BluetoothGatt gatt;
private BluetoothGattCharacteristic writeCharacteristic;

private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.d("BLE", "Connected—discovering services...");
            gatt.discoverServices();
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.d("BLE", "Disconnected from HM-10");
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            BluetoothGattService hm10Service = gatt.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
            if (hm10Service != null) {
                writeCharacteristic = hm10Service.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
                if (writeCharacteristic != null) {
                    // Now ready to send data
                    sendBytesToHM10(new byte[]{0x01, 0x02, 0x03});
                }
            }
        }
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Log.d("BLE", "Data written successfully!");
        } else {
            Log.e("BLE", "Write failed with status: " + status);
        }
    }
};

private void sendBytesToHM10(byte[] data) {
    if (writeCharacteristic == null || gatt == null) return;
    writeCharacteristic.setValue(data);
    writeCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
    gatt.writeCharacteristic(writeCharacteristic);
}

// To initiate connection:
BluetoothDevice hm10Device = bluetoothAdapter.getRemoteDevice("AA:BB:CC:DD:EE:FF");
gatt = hm10Device.connectGatt(this, false, gattCallback);
Final Quick Tips
  • Use a BLE debugging app (like nRF Connect) to inspect the HM-10’s services/characteristics and test writes—this confirms the hardware is working as expected.
  • HM-10 has a 20-byte MTU limit per write, so split large data into chunks if needed.
  • Always call gatt.close() when you’re done with the connection to avoid resource leaks.

内容的提问来源于stack exchange,提问作者Olliek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:44:11