cordova-plugin-ble-central

repository·master·Indexed 21 days ago

https://github.com/don/cordova-plugin-ble-central

A Bluetooth Low Energy (BLE) Central plugin for Apache Cordova and Capacitor (version 2.0.0) that enables mobile applications to scan, connect, and communicate with BLE peripherals. The plugin supports standard services such as Battery and Heart Rate, as well as hardware like Adafruit Bluefruit LE, MetaWear, and RedBear Lab BLE boards.

Tokens
16.1K
Snippets
64
Records
82
Agent score
75%

What's inside cordova-plugin-ble-central

  1. How Cordova hooks work and how to use them

    master

    Cordova hooks are scripts that allow you to customize Cordova commands by executing code before or after specific lifecycle events. This is useful for integrating custom build systems, version control, or automated tasks.

    Key Rules

    • Execution Timing: Scripts are executed based on the directory name they reside in (e.g., before_prepare/ runs before the prepare command).
    • Permissions: You must make your scripts executable.
    • Error Handling: If a hook script returns a non-zero exit code, the parent Cordova command will be aborted.
    • Execution Context: All scripts run from the project's root directory, and the root directory path is passed as the first argument to the script.
  2. How Cordova Hooks work

    master

    Cordova Hooks are scripts used to customize Cordova commands. They are executed before or after specific Cordova CLI commands. This is useful for integrating custom build systems or version control workflows.

    Key Requirements:

    • Scripts must be made executable.
    • Scripts are run from the project's root directory.
    • The root directory is passed as the first argument to the script.
    • If a script returns a non-zero exit code, the parent Cordova command is aborted.
  3. Understand and use Cordova Hooks

    master

    Cordova hooks are scripts used to customize Cordova commands. They are executed either before or after specific Cordova CLI commands. This is useful for integrating custom build systems or version control workflows into the Cordova lifecycle.

    Important Requirements:

    • Scripts must be made executable.
    • Scripts are run from the project's root directory.
    • The first argument passed to the script is the project's root directory.
    • If a script returns a non-zero exit code, the parent Cordova command will be aborted.
  4. Understand Peripheral Data structures

    master

    When scanning or connecting, the plugin returns peripheral objects. The structure changes depending on the connection state.

    Scanning State: Contains basic info like name, id, advertising (raw bytes or dictionary), and rssi.

    Connected State: Includes the scanning data plus services, characteristics (with service, characteristic, and properties), and descriptors (with uuid).

    Example Connected Peripheral Object:

    {
        "name": "Battery Demo",
        "id": "20:FF:D0:FF:D1:C0",
        "rssi": -55,
        "services": ["1800", "1801", "180f"],
        "characteristics": [
            {
                "service": "180f",
                "characteristic": "2a19",
                "properties": ["Read"],
                "descriptors": [{ "uuid": "2901" }]
            }
        ]
    }
  5. Use L2CAP channels for efficient binary data transfer

    master

    L2CAP (Logical Link Control and Adaptation Protocol) provides a duplex byte stream interface, similar to a network socket, which is more efficient for binary data transfer than standard GATT operations. This is useful for streaming applications like the Bluetooth Object Transfer Service.

    Supported Platforms: iOS, Android (>= 10).

    Key Operations:

    • Open a channel: Use l2cap.open with a device_id and a psm (Protocol/Service Multiplexer). On Android, you can specify a secureChannel boolean in the options object to control encryption.
    • Write data: Use l2cap.write. If data exceeds the transmit buffer, it is automatically sent in chunks.
    • Receive data: Use l2cap.receiveData to set a callback that triggers whenever new bytes arrive on the channel.
    • Close a channel: Use l2cap.close to abort pending operations and close the stream.
    // Open an L2CAP channel with promises
    await ble.withPromises.l2cap.open(device_id, { psm: psm, secureChannel: true }, disconnectCallback);
    
    // Write data
    await ble.withPromises.l2cap.write(device_id, psm, data);
    
    // Receive data
    ble.l2cap.receiveData(device_id, psm, (data) => {
        console.log('Received:', data);
    });
    
    // Close channel
    await ble.withPromises.l2cap.close(device_id, psm);
  6. What are Cordova Hooks and how do they work

    master

    Cordova Hooks are special scripts used to customize Cordova commands during the build process. They allow developers to inject custom logic at specific lifecycle events (e.g., before a build starts or after a plugin is installed).

    Hooks are executed serially in this order:

    1. Application hooks from the /hooks directory.
    2. Application hooks defined in config.xml.
    3. Plugin hooks defined in plugin.xml.

    Important: Ensure your script files are marked as executable.

  7. Run the Bluefruit LE example on Android

    master

    To run the Adafruit UART example on an Android device, use the following Cordova commands.

    Troubleshooting Android Scanning: Some Android devices fail to find peripherals when filtering by a specific Service UUID. If your device cannot find the Bluetooth peripheral, modify the ble.scan call to use an empty array [] instead of a specific service UUID to remove the filter.

    cordova platform add android
    cordova run android --device

    If scanning fails, change:

    ble.scan([bluefruit.serviceUUID], 5, app.onDiscoverDevice, app.onError);

    To:

    ble.scan([], 5, app.onDiscoverDevice, app.onError);

  8. Define Plugin hooks via plugin.xml

    master

    Plugin developers can define hooks in plugin.xml. Certain hooks are exclusive to the plugin lifecycle:

    • before_plugin_install / after_plugin_install: Executed exclusively when the plugin is being installed.
    • before_plugin_uninstall: Executed exclusively when the plugin is being uninstalled.
    <hook type="before_plugin_install" src="scripts/beforeInstall.js" />
    <hook type="after_build" src="scripts/afterBuild.js" />
    <hook type="before_plugin_install" src="scripts/beforeInstall.js" />
    <hook type="after_build" src="scripts/afterBuild.js" />
    
    <platform name="wp8">
        <hook type="before_plugin_install" src="scripts/wp8BeforeInstall.js" />
        <hook type="before_build" src="scripts/wp8BeforeBuild.js" />
    </platform>
  9. Handle platform-specific Advertising Data

    master

    Advertising data format varies significantly between Android and iOS.

    Android

    Returns an ArrayBuffer in the advertising field. You must convert this to a Uint8Array and parse it manually using GAP type constants.

    var adData = new Uint8Array(peripheral.advertising);

    iOS

    Returns a dictionary of data using Apple's Advertisement Data Retrieval Keys (e.g., kCBAdvDataLocalName). Some values like kCBAdvDataManufacturerData are ArrayBuffers. Convert them using:

    const mfgData = new Uint8Array(device.advertising.kCBAdvDataManufacturerData);

    To achieve consistent payloads across platforms, consider using the ble-central-advertisements module.

    function onDiscoverDevice(device) {
        console.log('Found Device', JSON.stringify(device, null, 2));
    
        // on iOS, print the manufacturer data if it exists
        if (device.advertising && device.advertising.kCBAdvDataManufacturerData) {
            const mfgData = new Uint8Array(device.advertising.kCBAdvDataManufacturerData);
            console.log('Manufacturer Data is', mfgData);
        }
    }
    
    ble.scan([], 5, onDiscoverDevice, onError);
  10. Convert data using Typed Arrays

    master

    The plugin uses TypedArrays or ArrayBuffers for all data transfers. You must convert your application data (like strings) to ArrayBuffers before sending, and convert received ArrayBuffers back to your desired format.

    Example: ASCII String Conversion

    // Convert string to ArrayBuffer
    function stringToBytes(string) {
        var array = new Uint8Array(string.length);
        for (var i = 0, l = string.length; i < l; i++) {
            array[i] = string.charCodeAt(i);
        }
        return array.buffer;
    }
    
    // Convert ArrayBuffer to string
    function bytesToString(buffer) {
        return String.fromCharCode.apply(null, new Uint8Array(buffer));
    }
    // ASCII only
    function stringToBytes(string) {
        var array = new Uint8Array(string.length);
        for (var i = 0, l = string.length; i < l; i++) {
            array[i] = string.charCodeAt(i);
        }
        return array.buffer;
    }
    
    // ASCII only
    function bytesToString(buffer) {
        return String.fromCharCode.apply(null, new Uint8Array(buffer));
    }
  11. Define Cordova hooks via the /hooks directory

    master

    You can define hooks by creating subfolders inside a hooks directory named after the hook type. Any script placed in that subfolder will be automatically executed when that hook type is fired.

    Example structure:

    # This script runs automatically after every build
    hooks/after_build/after_build_custom_action.js
    hooks/after_build/after_build_custom_action.js