问题
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