admin管理员组文章数量:1131174
import SwiftUI
import CoreBluetooth
import os
class BluetoothViewModel: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
@Published var peripherals: [CBPeripheral] = [] // List of discovered peripherals
@Published var connectedPeripheral: CBPeripheral? // The selected peripheral that is connected
@Published var discoveredServices: [CBService] = [] // List of discovered services
@Published var discoveredServiceNames: [String] = [] // List of names of discovered services
@Published var peripheralNames: [String] = [] // List of peripheral names found during scanning
@Published var filteredPeripheralNames: [String] = [] // List of filtered peripheral names
var cbManager: CBCentralManager?
private var peripheralNameReceived = false // Flag to track when the name is received
override init() {
super.init()
self.cbManager = CBCentralManager(delegate: self, queue: .main)
}
// Start scanning for peripherals (without connecting to them)
func startScanning() {
os_log("Start scanning for all peripherals.")
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
cbManager?.scanForPeripherals(withServices: nil, options: options) // Scan for all peripherals
}
// Stop scanning for peripherals
func stopScanning() {
os_log("Stop scanning.")
cbManager?.stopScan()
}
// MARK: - CBCentralManagerDelegate Methods
// Called when the central manager's state changes
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
os_log("Bluetooth is powered on.")
case .poweredOff:
os_log("Bluetooth is powered off.")
case .unauthorized:
os_log("Bluetooth unauthorized.")
case .unknown:
os_log("Bluetooth state is unknown.")
case .resetting:
os_log("Bluetooth is resetting.")
case .unsupported:
os_log("Bluetooth is unsupported.")
@unknown default:
os_log("Unknown Bluetooth state.")
}
}
// Called when a peripheral is discovered (but no connection is made)
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi: NSNumber) {
os_log("Discovered peripheral: %@", peripheral.name ?? "Unknown")
// Filter out peripherals by name if found in the filtered list
if let name = peripheral.name {
if !isPeripheralNameFiltered(name) {
// Add name to the list if it is not filtered out
peripheralNames.append(name)
os_log("Peripheral name added: %@", name)
} else {
os_log("Peripheral name %@ is filtered out", name)
}
}
// Add peripheral to the list if it's not already there
if !peripherals.contains(peripheral) {
peripherals.append(peripheral)
}
}
// Function to check if a peripheral name is in the filtered list
func isPeripheralNameFiltered(_ name: String) -> Bool {
return filteredPeripheralNames.contains(name)
}
// Function to filter out a specific peripheral by name
func filterOutPeripheralName(_ name: String) {
if !filteredPeripheralNames.contains(name) {
filteredPeripheralNames.append(name)
os_log("Peripheral name %@ added to filtered list", name)
}
}
// Called when a peripheral is connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
os_log("Connected to peripheral: %@", peripheral.name ?? "Unknown")
// Set the peripheral delegate to discover its services
peripheral.delegate = self
connectedPeripheral = peripheral
// Discover all services on the connected peripheral
peripheral.discoverServices(nil) // Pass nil to discover all services
}
// Called when a peripheral connection fails
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
os_log("Failed to connect to peripheral: %@", peripheral.name ?? "Unknown")
}
// Called when a peripheral is disconnected
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
os_log("Disconnected from peripheral: %@", peripheral.name ?? "Unknown")
connectedPeripheral = nil
discoveredServices.removeAll()
discoveredServiceNames.removeAll()
peripheralNames.removeAll()
filteredPeripheralNames.removeAll()
}
// MARK: - CBPeripheralDelegate Methods
// Called when the peripheral discovers its services
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
os_log("Failed to discover services: %@", error.localizedDescription)
return
}
os_log("Discovered services for peripheral: %@", peripheral.name ?? "Unknown")
// Define the UUIDs for Device Information and Battery Service
let deviceInformationServiceUUID = CBUUID(string: "180A") // Device Information
let batteryServiceUUID = CBUUID(string: "180F") // Battery Service
// Loop through discovered services and fetch their names
for service in peripheral.services ?? [] {
discoveredServices.append(service)
discoveredServiceNames.append(service.uuid.uuidString)
os_log("Service found: %@", service.uuid.uuidString)
// Check if the service is Device Information or Battery Service
if service.uuid == deviceInformationServiceUUID {
os_log("Device Information Service found")
} else if service.uuid == batteryServiceUUID {
os_log("Battery Service found")
} else {
os_log("Other service found: %@", service.uuid.uuidString)
}
// If device information service is found, discover characteristics
if service.uuid == deviceInformationServiceUUID {
peripheral.discoverCharacteristics([CBUUID(string: "2A00")], for: service) // Device Name characteristic
}
}
}
// Called when a peripheral discovers characteristics for a given service
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
os_log("Failed to discover characteristics for service: %@", error.localizedDescription)
return
}
os_log("Discovered characteristics for service: %@", service.uuid.uuidString)
// If the Device Information Service is found, read the device name characteristic (2A00)
for characteristic in service.characteristics ?? [] {
if characteristic.uuid == CBUUID(string: "2A00") { // Device Name characteristic
peripheral.readValue(for: characteristic)
}
}
}
// Called when a characteristic's value is updated
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
os_log("Failed to read characteristic value: %@", error.localizedDescription)
return
}
if characteristic.uuid == CBUUID(string: "2A00") { // Device Name characteristic
if let nameData = characteristic.value, let deviceName = String(data: nameData, encoding: .utf8) {
os_log("Device Name from Device Info Service: %@", deviceName)
peripheralNames.append(deviceName) // Add device name to list
peripheralNameReceived = true // Mark the name as received
}
}
}
// Handle Manufacturer Data (custom name or metadata) if present
func peripheral(_ peripheral: CBPeripheral, didReadValueFor characteristic: CBCharacteristic, error: Error?) {
if let manufacturerData = characteristic.value, characteristic.uuid == CBUUID(string: "2A29") {
os_log("Manufacturer Data: %@", convertDataToHexString(manufacturerData))
}
}
// Helper function to convert Data to a hexadecimal string for logging
private func convertDataToHexString(_ data: Data) -> String {
return data.map { String(format: "%02hhx", $0) }.joined()
}
// A method to check if the name was received before moving on
func waitForName() {
while !peripheralNameReceived {
// Implement a small delay or check, or you can return here and handle other logic asynchronously
usleep(100000) // Sleep for 0.1 seconds for example
}
}
}
results, The unknown is being displayed in ios settings with its device name.
Discovered peripheral: [TV] Cia tv
Peripheral name added: [TV] Cia tv
Discovered peripheral: Unknown
Discovered peripheral: Unknown
Discovered peripheral: [TV] Cia tv
Peripheral name added: [TV] Cia tv
Discovered peripheral: Unknown
import SwiftUI
import CoreBluetooth
import os
class BluetoothViewModel: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
@Published var peripherals: [CBPeripheral] = [] // List of discovered peripherals
@Published var connectedPeripheral: CBPeripheral? // The selected peripheral that is connected
@Published var discoveredServices: [CBService] = [] // List of discovered services
@Published var discoveredServiceNames: [String] = [] // List of names of discovered services
@Published var peripheralNames: [String] = [] // List of peripheral names found during scanning
@Published var filteredPeripheralNames: [String] = [] // List of filtered peripheral names
var cbManager: CBCentralManager?
private var peripheralNameReceived = false // Flag to track when the name is received
override init() {
super.init()
self.cbManager = CBCentralManager(delegate: self, queue: .main)
}
// Start scanning for peripherals (without connecting to them)
func startScanning() {
os_log("Start scanning for all peripherals.")
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
cbManager?.scanForPeripherals(withServices: nil, options: options) // Scan for all peripherals
}
// Stop scanning for peripherals
func stopScanning() {
os_log("Stop scanning.")
cbManager?.stopScan()
}
// MARK: - CBCentralManagerDelegate Methods
// Called when the central manager's state changes
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
os_log("Bluetooth is powered on.")
case .poweredOff:
os_log("Bluetooth is powered off.")
case .unauthorized:
os_log("Bluetooth unauthorized.")
case .unknown:
os_log("Bluetooth state is unknown.")
case .resetting:
os_log("Bluetooth is resetting.")
case .unsupported:
os_log("Bluetooth is unsupported.")
@unknown default:
os_log("Unknown Bluetooth state.")
}
}
// Called when a peripheral is discovered (but no connection is made)
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi: NSNumber) {
os_log("Discovered peripheral: %@", peripheral.name ?? "Unknown")
// Filter out peripherals by name if found in the filtered list
if let name = peripheral.name {
if !isPeripheralNameFiltered(name) {
// Add name to the list if it is not filtered out
peripheralNames.append(name)
os_log("Peripheral name added: %@", name)
} else {
os_log("Peripheral name %@ is filtered out", name)
}
}
// Add peripheral to the list if it's not already there
if !peripherals.contains(peripheral) {
peripherals.append(peripheral)
}
}
// Function to check if a peripheral name is in the filtered list
func isPeripheralNameFiltered(_ name: String) -> Bool {
return filteredPeripheralNames.contains(name)
}
// Function to filter out a specific peripheral by name
func filterOutPeripheralName(_ name: String) {
if !filteredPeripheralNames.contains(name) {
filteredPeripheralNames.append(name)
os_log("Peripheral name %@ added to filtered list", name)
}
}
// Called when a peripheral is connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
os_log("Connected to peripheral: %@", peripheral.name ?? "Unknown")
// Set the peripheral delegate to discover its services
peripheral.delegate = self
connectedPeripheral = peripheral
// Discover all services on the connected peripheral
peripheral.discoverServices(nil) // Pass nil to discover all services
}
// Called when a peripheral connection fails
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
os_log("Failed to connect to peripheral: %@", peripheral.name ?? "Unknown")
}
// Called when a peripheral is disconnected
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
os_log("Disconnected from peripheral: %@", peripheral.name ?? "Unknown")
connectedPeripheral = nil
discoveredServices.removeAll()
discoveredServiceNames.removeAll()
peripheralNames.removeAll()
filteredPeripheralNames.removeAll()
}
// MARK: - CBPeripheralDelegate Methods
// Called when the peripheral discovers its services
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
os_log("Failed to discover services: %@", error.localizedDescription)
return
}
os_log("Discovered services for peripheral: %@", peripheral.name ?? "Unknown")
// Define the UUIDs for Device Information and Battery Service
let deviceInformationServiceUUID = CBUUID(string: "180A") // Device Information
let batteryServiceUUID = CBUUID(string: "180F") // Battery Service
// Loop through discovered services and fetch their names
for service in peripheral.services ?? [] {
discoveredServices.append(service)
discoveredServiceNames.append(service.uuid.uuidString)
os_log("Service found: %@", service.uuid.uuidString)
// Check if the service is Device Information or Battery Service
if service.uuid == deviceInformationServiceUUID {
os_log("Device Information Service found")
} else if service.uuid == batteryServiceUUID {
os_log("Battery Service found")
} else {
os_log("Other service found: %@", service.uuid.uuidString)
}
// If device information service is found, discover characteristics
if service.uuid == deviceInformationServiceUUID {
peripheral.discoverCharacteristics([CBUUID(string: "2A00")], for: service) // Device Name characteristic
}
}
}
// Called when a peripheral discovers characteristics for a given service
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
os_log("Failed to discover characteristics for service: %@", error.localizedDescription)
return
}
os_log("Discovered characteristics for service: %@", service.uuid.uuidString)
// If the Device Information Service is found, read the device name characteristic (2A00)
for characteristic in service.characteristics ?? [] {
if characteristic.uuid == CBUUID(string: "2A00") { // Device Name characteristic
peripheral.readValue(for: characteristic)
}
}
}
// Called when a characteristic's value is updated
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
os_log("Failed to read characteristic value: %@", error.localizedDescription)
return
}
if characteristic.uuid == CBUUID(string: "2A00") { // Device Name characteristic
if let nameData = characteristic.value, let deviceName = String(data: nameData, encoding: .utf8) {
os_log("Device Name from Device Info Service: %@", deviceName)
peripheralNames.append(deviceName) // Add device name to list
peripheralNameReceived = true // Mark the name as received
}
}
}
// Handle Manufacturer Data (custom name or metadata) if present
func peripheral(_ peripheral: CBPeripheral, didReadValueFor characteristic: CBCharacteristic, error: Error?) {
if let manufacturerData = characteristic.value, characteristic.uuid == CBUUID(string: "2A29") {
os_log("Manufacturer Data: %@", convertDataToHexString(manufacturerData))
}
}
// Helper function to convert Data to a hexadecimal string for logging
private func convertDataToHexString(_ data: Data) -> String {
return data.map { String(format: "%02hhx", $0) }.joined()
}
// A method to check if the name was received before moving on
func waitForName() {
while !peripheralNameReceived {
// Implement a small delay or check, or you can return here and handle other logic asynchronously
usleep(100000) // Sleep for 0.1 seconds for example
}
}
}
results, The unknown is being displayed in ios settings with its device name.
Discovered peripheral: [TV] Cia tv
Peripheral name added: [TV] Cia tv
Discovered peripheral: Unknown
Discovered peripheral: Unknown
Discovered peripheral: [TV] Cia tv
Peripheral name added: [TV] Cia tv
Discovered peripheral: Unknown
1 Answer
Reset to default 0Generally speaking, the peripheral.name property in your code is derived from the CBAdvertisementDataLocalNameKey. This means that if a device advertises its name as part of its advertisement data, it will appear in your scan result - this is what is happening with devices like "Cia tv."
However, not all devices include their name in the advertisement data. In such cases, I believe iOS Settings may display the name using two additional methods:
- Cached Names: iOS may retrieve the name from previously cached information if the device has been paired or discovered before.
- GATT Queries: iOS can actively query the remote device's GATT table. Some devices provide their name in the Device Information service (UUID: 0x180A), specifically in the Device Name characteristic (UUID: 0x2A00), even if it is not broadcast in advertisement data.
You can verify if the local name is present in the advertisement data by modifying the didDiscoverPeripheral method:
// Check if the advertisement data contains the local name
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
os_log("Advertisement data name: %@", name)
if !peripheralNames.contains(name) {
peripheralNames.append(name)
}
} else {
os_log("Peripheral name is not in advertisement data.")
}
Here are some relevant discussions and documentation that provide further context:
- CoreBluetooth fetch device names
- Advertisement data missing local name
- Apple Developer forums discussion on peripheral names
- Handling incorrect peripheral names
本文标签:
版权声明:本文标题:Why Swift code bluetooth showing devices as unknown while iOS Settings bluetooth is showing them correclty? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736768586a1951961.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论