Ble: Send advertise data to iOS from Android

。_饼干妹妹 提交于 2021-01-07 06:35:57

问题


I have to send some advertise data via ble to an iOS central app. On Android peripheral side, when i create advertise i do:

    var byteArrayData = dataToSend.toByteArray(Charsets.UTF_8)

    var data = AdvertiseData.Builder().apply {
        addServiceData(
            ParcelUuid(MY_SERVICE_UUID),
            byteArrayData
        )
    }
    bleAdvertiser.startAdvertising(mySettings.build(), data.build(), myAdvertiseCallback)

but it seems that iOS is not able to read custom service data.

So, there's a way to sent some small data (few bytes) via BLE to iOS (and receive also data when Android is central and iOS is pheripheral)?

I would avoid, if is possible, to open a connection between central an peripheral.


回答1:


iOS is very restrictive regarding advertisement data. Both when sending and receiving it, you can only control a small subset of it. Most of it is controlled by iOS itself and — in case of the central manager role — not even forwarded to the app.

The exceptions are the Advertisement Data Retrieval Keys, applicable for the advertisementData parameter of centralManager(_:didDiscover:advertisementData:rssi:).

A more specific example is mentioned in this answer.

Update

Even though one of the keys is for service data, I don't think the data is forwarded to the app. But I might be wrong. I guess you are asking this question because the key CBAdvertisementDataServiceDataKey is not set.

Update 2

I've created a minimal Android and iOS example and got it working without any problem. I don't see no obvious problem in your Android code. So you will need to talk to your iOS colleague...

The service data is "ABC" (or 61 62 63 in hex) and the 16-bit UUID is FF01. The iOS log output is:

2019-09-05 16:39:18.987142+0200 BleScanner[18568:3982403] [Scanner] Advertisement data: FF01: <616263>

Android - MainActivity.kt

package bleadvertiser

import android.bluetooth.BluetoothManager
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

    private var peripheral: Peripheral? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        super.onStart()
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        peripheral = Peripheral(bluetoothManager.adapter)
        peripheral?.startAdvertising()
    }
}

Android - Peripheral.kt

package bleadvertiser

import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.os.ParcelUuid
import android.util.Log
import java.util.*

private const val TAG = "Peripheral"

class Peripheral(private val bluetoothAdapter: BluetoothAdapter) {

    fun startAdvertising() {
        val advertiseSettings = AdvertiseSettings.Builder().build()
        val serviceData = "abc".toByteArray(Charsets.UTF_8)
        val advertiseData = AdvertiseData.Builder()
            .addServiceData(ParcelUuid(SERVICE_UUID), serviceData)
            .build()
        val advertiser = bluetoothAdapter.bluetoothLeAdvertiser
        advertiser.startAdvertising(advertiseSettings, advertiseData, advertiseCallback)
    }

    private val advertiseCallback = object: AdvertiseCallback() {
        override fun onStartFailure(errorCode: Int) {
            Log.w(TAG, String.format("Advertisement failure (code %d)", errorCode))
        }
        override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
            Log.i(TAG, "Advertisement started")
        }
    }

    companion object {
        val SERVICE_UUID: UUID = UUID.fromString("0000ff01-0000-1000-8000-00805F9B34FB")
    }
}

iOS - ViewController.swift

import UIKit

class ViewController: UIViewController {

    var bleScanner: BleScanner?

    override func viewDidLoad() {
        super.viewDidLoad()
        bleScanner = BleScanner()
    }
}

iOS - BleScanner.swift

import Foundation
import CoreBluetooth
import os.log

class BleScanner : NSObject {

    static let serviceUUID = CBUUID(string: "FF01")
    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Scanner")

    private var centralManager: CBCentralManager!
    private var scanningTimer: Timer?

    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }

    func startScanning() {
        scanningTimer = Timer.scheduledTimer(withTimeInterval: TimeInterval(20), repeats: false, block: { (_) in
            self.stopScanning()
        })
        centralManager.scanForPeripherals(withServices: [ BleScanner.serviceUUID ], options: nil)
    }

    func stopScanning() {
        centralManager.stopScan()
    }
}

extension BleScanner : CBCentralManagerDelegate {

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if centralManager.state == .poweredOn {
            startScanning()
        }
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        for (key, value) in advertisementData {
            if key == CBAdvertisementDataServiceDataKey {
                let serviceData = value as! [CBUUID : NSData]
                for (uuid, data) in serviceData {
                    os_log("Advertisement data: %{public}s: %{public}s", log: BleScanner.log, type: .info, uuid.uuidString, data.debugDescription)
                }
            }
        }
    }
}


来源:https://stackoverflow.com/questions/57805222/ble-send-advertise-data-to-ios-from-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!