I have an iOS/iPadOS app and 'm trying to communicate with usb smart card reader using CryptoTokenKit on all platforms (ios/ipados/macos).
Minimal Repro Code
import CryptoTokenKit
import SwiftUI
struct ContentView: View {
@State var status = ""
var body: some View {
VStack {
Text("Status: \(status)")
}
.padding()
.onAppear {
let manager = TKSmartCardSlotManager.default
if manager != nil {
status = "Initialized"
} else {
status = "Unsupported"
}
}
}
}
And my entitlement file has only one key:
com.apple.security.smartcard = YES
Behavior
• iPadOS (on device): status = "Initialized" ✅
• macOS (native macOS app, with the required CryptoTokenKit entitlement): status = "Initialized" ✅
• macOS (Designed for iPad, regardless of CryptoTokenKit entitlement): status = "Unsupported" → TKSmartCardSlotManager.default is nil ❌
Expectation
Given that the same iPadOS build initializes TKSmartCardSlotManager, I expected the iPad app running in Designed for iPad mode on Apple silicon Mac to behave the same (or to have a documented limitation).
Questions
Is CryptoTokenKit (and specifically TKSmartCardSlotManager) supported for iPad apps running on Mac in Designed for iPad mode?
If support exists, what entitlements / capabilities are required for USB smart-card access in this configuration?
If not supported, is Mac Catalyst the correct/only path on macOS to access USB smart-card readers via CryptoTokenKit?
Are there recommended alternatives for iPad apps on Mac (Designed for iPad) to communicate with USB smart-card readers (e.g., ExternalAccessory, DriverKit, etc.), or is this scenario intentionally unsupported?
Thanks!
Hardware
RSS for tagDelve into the physical components of Apple devices, including processors, memory, storage, and their interaction with the software.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi, we have developed an application that streams data from two BLE peripherals at a rate of 14.5kbps per peripheral. Until now, our devices streamed in near real time with no lag on all Apple devices with Bluetooth 5.0 or greater. Since the release of the iPhone 17 series and the iPad A16, we have reports from users of the data being streamed at significantly lower rates than expected.
Any help here would be greatly appreciated as our customers are being affected by this change.
I am creating a barcode reader using the AVfoundation framework for iOS and IPadOS. The read result goes into payloadstringvalue, but I want to check the control characters contained in the symbol, so I am using the raw data of the description, which is a property of NSObjectProtocol inherited by VNBarcodeObservation. However, I noticed that if the length set in the raw data exceeds 26, some of the raw data in the description is omitted. So my question is, is it possible to set it so that all the raw data in the description is written out without omitting any raw data? If so, could you please tell me how to set this up? Also, if you know of any other way to extract the raw barcode data, I would appreciate it if you could let me know.
Thank you.
I am using NFC when the phone is near the NFC reader times below the error:
2024-07-15 15:43:03.608427+0800 TestNFC[16022:1038141] [xpc.exceptions] <NSXPCConnection: 0x282ba90e0> connection to service with pid 58 named com.apple.nfcd.service.corenfc: Exception caught during decoding of received selector didDetectExternalReaderWithNotification:, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: decodeObjectForKey: class "NFFieldNotification" not loaded or does not exist
my code:
#import <CoreNFC/CoreNFC.h>
@interface ViewController ()<NFCTagReaderSessionDelegate>
@property (strong, nonatomic) NFCTagReaderSession *session;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
if (@available(iOS 13.0, *)) {
// 初始化 NFC 设置代理 NFCTagReaderSessionDelegate
if (NFCNDEFReaderSession.readingAvailable)
{
self.session = [[NFCTagReaderSession alloc]
initWithPollingOption:NFCPollingISO14443 delegate:self queue:nil];
// NFC 显示提示信息
self.session.alertMessage = @"准备扫描,请将卡片贴近手机";
// 开启 NFC
[self.session beginSession];
}
} else {
}
}
#pragma mark - NFCNDEFReaderSessionDelegate
//读取失败回调-读取成功后还是会回调这个方法
- (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession *)session API_AVAILABLE(ios(13.0)){
NSLog(@"tagReaderSessionDidBecomeActive");
}
- (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(13.0)){
NSLog(@"readerSession:didInvalidateWithError: (%@)", [error localizedDescription]);
}
- (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCTag>> *)tags API_AVAILABLE(ios(13.0)){
}
I am working on a Bluetooth Low Energy (BLE) project using the nRF52840 Development Kit (DK), which has been reconfigured to simulate an nRF52805 chip. The firmware is based on Nordic Semiconductor's ble_app_hids_keyboard example, with modifications to implement a BLE HID Gamepad. I am using the S113 SoftDevice and have successfully tested the functionality with Android devices. The gamepad is recognized as a HID device, and it works as expected on Android, verified using the hardwareTester website.
However, when I connect the gamepad to an iPhone via BLE, the same hardwareTester website does not respond as it does on Android, indicating that the iPhone does not recognize the device as a gamepad. The BLE connection is established successfully, but it seems iOS does not interpret the HID report descriptor or the BLE HID service correctly. I suspect there might be compatibility issues with the HID descriptor or the GATT attributes for iOS-specific BLE HID requirements.
I would like to have some help.
New projects in Xcode do not include an Info.plist. Where do I put the IDs for Supported External Accessory Protocols?
I upgraded my iPhone 13 Pro Max last week, but I am unable to connect my Sony WH-1000XM5 headphones via Bluetooth. I'm not sure why everything else connects just fine except my headphones. Please send help.
Topic:
App & System Services
SubTopic:
Hardware
Six months ago I wrote FB14122473, detailing how the built-in CDC (or FTDI) VCP serial port driver is limited to 3 Mbps or less. Thing is, there are some FTDI devices that can do 12 Mbps (maybe more), and I have devices I need to communicate with at 4 Mbps. I had to use the FTDI SDK to be able to communicate with these.
I was hoping this post might help draw attention to that bug report.
Topic:
App & System Services
SubTopic:
Hardware
I have a 4-input, 4-output hardware device and an 8-input, 8-output virtual device, which I combine into an aggregate device. I am using the SimplyCoreAudio library to get the channel count. The code is as follows:
aggregationDevice!.channels(scope: .input) =>> 12 aggregationDevice!.channels(scope: .output) =>> 12
When the program's MicrophoneMode is set to standard, the channel count is correct. However, when I set the MicrophoneMode to voiceIsolation, the channel count is incorrect:
aggregationDevice!.channels(scope: .input) =>> 4 aggregationDevice!.channels(scope: .output) =>> 12
Below is the code for creating the aggregate device:
func createAggregateDevice(mainDevice: AudioDevice,
secondDevice: AudioDevice?,
named name: String,
uid: String) -> AudioDevice?
{
guard let mainDeviceUID = mainDevice.uid else { return nil }
var deviceList: [[String: Any]] = [
[
kAudioSubDeviceUIDKey: mainDeviceUID,
kAudioSubDeviceDriftCompensationKey:1
]
]
// make sure same device isn't added twice
if let secondDeviceUID = secondDevice?.uid, secondDeviceUID != mainDeviceUID {
deviceList.append([
kAudioSubDeviceUIDKey: secondDeviceUID,
kAudioSubDeviceDriftCompensationKey:1,
kAudioSubDeviceInputChannelsKey:8
])
}
let desc: [String: Any] = [
kAudioAggregateDeviceNameKey: name,
kAudioAggregateDeviceUIDKey: uid,
kAudioAggregateDeviceSubDeviceListKey: deviceList,
kAudioAggregateDeviceMainSubDeviceKey: mainDeviceUID,
kAudioAggregateDeviceIsPrivateKey:false,
]
var deviceID: AudioDeviceID = 0
let error = AudioHardwareCreateAggregateDevice(desc as CFDictionary, &deviceID)
guard error == noErr else {
return nil
}
return AudioDevice.lookup(by: deviceID)
}
I hope someone can tell me the reason Thank you!
Receiving "The disk you attached was not readable by this computer." for an external USB recorder that worked with MacOS 14
Aiworth voice recorder.
Hello!
We currently require the development of an iOS system for encrypting and authorizing photos, videos, voice memos, or other files stored on our devices to a connected USB-C storage. The encrypted files can be accessed through authorization. We have already encrypted and authorized the files to be stored on the app's mobile storage, and cannot directly store them to USB-C (this requirement is based on the Apple camera RroRes, which uses external storage for direct storage). We are seeking technical support from Apple.
Apple intelligence isn’t working, it says i have it but that’s it’s also downloading. Whenever i do have it on none of the features work, what do i do
Topic:
App & System Services
SubTopic:
Hardware
why is it that this code doesn't show the bluetooth device name but in the iOS settings it is displayed correctly. Thank you.
import UIKit
import CoreBluetooth
import CoreLocation
class BluetoothViewController: UIViewController, CBCentralManagerDelegate, CLLocationManagerDelegate {
var centralManager: CBCentralManager!
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Initialize central manager
centralManager = CBCentralManager(delegate: self, queue: nil)
// Initialize location manager to request location access
locationManager = CLLocationManager()
locationManager.delegate = self
}
// CBCentralManagerDelegate Methods
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
// Bluetooth is powered on, request location permission if needed
if CLLocationManager.locationServicesEnabled() {
locationManager.requestWhenInUseAuthorization()
}
startScanning()
case .poweredOff:
print("Bluetooth is powered off.")
case .resetting:
print("Bluetooth is resetting.")
case .unauthorized:
print("Bluetooth is unauthorized.")
case .unknown:
print("Bluetooth state is unknown.")
case .unsupported:
print("Bluetooth is unsupported on this device.")
@unknown default:
fatalError("Unknown Bluetooth state.")
}
}
func startScanning() {
// Start scanning for devices (you can add service UUIDs to filter specific devices)
centralManager.scanForPeripherals(withServices: nil, options: [CBScanOptionAllowDuplicatesKey: true])
print("Scanning for Bluetooth devices...")
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi: NSNumber) {
// This method is called when a peripheral is discovered
let deviceName = peripheral.name ?? "Unknown"
let deviceAddress = peripheral.identifier.uuidString
print("Found device: \(deviceName), \(deviceAddress)")
// Optionally, you can stop scanning after discovering a device
// centralManager.stopScan()
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected to peripheral: \(peripheral.name ?? "Unknown")")
}
// CLLocationManagerDelegate Methods (for location services)
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
// Permission granted, now start scanning
startScanning()
} else {
print("Location permission is required for Bluetooth scanning.")
}
}
// Optionally handle when scanning stops or any errors occur
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("Failed to connect to peripheral: \(error?.localizedDescription ?? "Unknown error")")
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected from peripheral: \(peripheral.name ?? "Unknown")")
}
}
Current if we use the removeAccessory(_:completionHandler:) method in ASAccessorySession, it removes the accessory from the system and all apps that have previously paired also lose access.
Is there a way to remove the paired accessory only from the app from where the removeAccessory() call is being made? This would be useful in cases where one or more accessories are shared across apps and we need to manage them.
We would like to be able to distinguish between iPhones and Apple Watches when scanning for devices using a Laird BLE module.
We know that we can identify an Apple device from the manufacturer data returned in the scan report. 0x004C is the registered identifier for Apple.
In the remaining data returned is it possible identify the device type?
We note that empirically, 4C001005 seems to correlate to an Apple Watch. How reliable is this?
It is useful for us, because it means we do not need to connect to this device to see if it is advertising a service that we own.
Connecting over BLE is of course an expensive operation.
Here is a simple snippet of a Swift App doing a similar thing, to illustrate the question:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
{
guard
let manufData: Data = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data
else
{
return
}
let hexEncodedManufData: String = manufData.map { String(format: "%02hhx", $0) }.joined()
print("Manufacturer Data: \(hexEncodedManufData): ")
// Manufacturer Data: 4c001007351ff9f9036238: Apple device
// Manufacturer Data: 4c001006331ec0640f88: Apple device
// Manufacturer Data: 4c0010052b18804eb1: Apple watch?
// Manufacturer Data: 4c0010052b18804eb1: Apple watch?
}
I have a device. After pairing, it is shown as connected in the Bluetooth list of the mobile phone. Before iOS 18, I could retrieve the device through the retrieveConnectedPeripherals method, but after iOS 18, I cannot retrieve it. What is the reason? Because when the device is connected, it no longer sends broadcast packets. How can I retrieve the device?
I am working on an iOS application that relies on CoreMotion Attitude, and I need clarification regarding the behavior of reference frames.
According to the documentation, when setting the attitude reference frame to CMAttitudeReferenceFrameXTrueNorthZVertical:
The Z-axis of the reference frame is vertical (aligned with gravity).
The X-axis of the reference frame points to the geographic North Pole (True North).
When a device’s orientation matches this reference frame, the roll, pitch, and yaw values reported by CMAttitude should be (0,0,0).
However, in my testing:
When I align the device’s position with the CMAttitudeReferenceFrameXTrueNorthZVertical reference frame by orienting the screen (device Z-axis) upward and the right side (device X-axis) toward north, the yaw value reported by CMAttitude is 90 degrees instead of the expected 0 degrees.
To have CMAttitude report yaw as 0, I must instead orient the top side (device Y-axis) toward north.
This seems to contradict my understanding that the X-axis of the device should be aligned with True North, to have the device match the attitude reference frame and have roll, pitch, and yaw values reported by CMAttitude should be (0,0,0).
What I'm missing?
Thank you for your time and assistance.
Topic:
App & System Services
SubTopic:
Hardware
We just updated our ATS to the latest 8.3.0 version and tried to run the iAP2 Session Test via BPA100 Bluetooth Analyzer and we are experiencing this EXC_BAD_INSTRUCTION. This same test still seems to work on ATS version 6. Please advise.
Process: ATS [1782]
Path: /private/var/folders/*/ATS.app/Contents/MacOS/ATS
Identifier: com.apple.ATSMacApp
Version: 8.3.0 (1826)
Build Info: ATSMacApp-1826000000000000~2 (1A613)
Code Type: X86-64 (Native)
Parent Process: launchd [1]
User ID: 501
Date/Time: 2025-01-27 11:05:21.1334 -0800
OS Version: macOS 15.2 (24C101)
Report Version: 12
Bridge OS Version: 9.2 (22P2093)
Anonymous UUID: 098E2BB5-CB98-CA1C-CEFE-188AF6EFE8CF
Time Awake Since Boot: 9700 seconds
System Integrity Protection: enabled
Crashed Thread: 2 com.apple.ATSMacApp.FrontlineFrameworkInterface
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [1782]
Topic:
App & System Services
SubTopic:
Hardware
Tags:
Developer Tools
External Accessory
Testing
Core Bluetooth
what do i do is it going down too fast?
Hello everyone,
I want send haptics to ps4 controller.
CHHapticPatternPlayer and CHHapticAdvancedPatternPlayer good work with iPhone.
On PS4 controller If I use CHHapticPatternPlayer all work good, but if I use CHHapticAdvancedPatternPlayer I get error. I want use CHHapticAdvancedPatternPlayer to use additional settings. I don't found any information how to fix it -
CHHapticEngine.mm:624 -[CHHapticEngine finishInit:]_block_invoke: ERROR: Server connection broke with error 'Не удалось завершить операцию. (com.apple.CoreHaptics, ошибка -4811)'
The engine stopped because a system error occurred.
AVHapticClient.mm:1228 -[AVHapticClient getSyncDelegateForMethod:errorHandler:]_block_invoke: ERROR: Sync XPC call for 'loadAndPrepareHapticSequenceFromEvents:reply:' (client ID 0x21) failed: Не удалось установить связь с приложением-помощником.
Не удалось создать или воспроизвести паттерн: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service with pid 5087 named com.apple.GameController.gamecontrollerd.haptics" UserInfo={NSDebugDescription=connection to service with pid 5087 named com.apple.GameController.gamecontrollerd.haptics}
My Haptic class -
import Foundation
import CoreHaptics
import GameController
protocol HapticsControllerDelegate: AnyObject {
func didConnectController()
func didDisconnectController()
func enginePlayerStart(value: Bool)
}
final class HapticsControllerManager {
static let shared = HapticsControllerManager()
private var isSetup = false
private var hapticEngine: CHHapticEngine?
private var hapticPlayer: CHHapticAdvancedPatternPlayer?
weak var delegate: HapticsControllerDelegate? {
didSet {
if delegate != nil {
startObserving()
}
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func startObserving() {
guard !isSetup else { return }
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidConnect),
name: .GCControllerDidConnect,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(controllerDidDisconnect),
name: .GCControllerDidDisconnect,
object: nil
)
isSetup = true
}
@objc private func controllerDidConnect(notification: Notification) {
delegate?.didConnectController()
self.createAndStartHapticEngine()
}
@objc private func controllerDidDisconnect(notification: Notification) {
delegate?.didDisconnectController()
hapticEngine = nil
hapticPlayer = nil
}
private func createAndStartHapticEngine() {
guard let controller = GCController.controllers().first else {
print("No controller connected")
return
}
guard controller.haptics != nil else {
print("Haptics not supported on this controller")
return
}
hapticEngine = createEngine(for: controller, locality: .default)
hapticEngine?.playsHapticsOnly = true
do {
try hapticEngine?.start()
} catch {
print("Не удалось запустить движок тактильной обратной связи: \(error)")
}
}
private func createEngine(for controller: GCController, locality: GCHapticsLocality) -> CHHapticEngine? {
guard let engine = controller.haptics?.createEngine(withLocality: locality) else {
print("Failed to create engine.")
return nil
}
print("Successfully created engine.")
engine.stoppedHandler = { reason in
print("The engine stopped because \(reason.message)")
}
engine.resetHandler = {
print("The engine reset --> Restarting now!")
do {
try engine.start()
} catch {
print("Failed to restart the engine: \(error)")
}
}
return engine
}
func startHapticFeedback(haptics: [CHHapticEvent]) {
do {
let pattern = try CHHapticPattern(events: haptics, parameters: [])
hapticPlayer = try hapticEngine?.makeAdvancedPlayer(with: pattern)
hapticPlayer?.loopEnabled = true
try hapticPlayer?.start(atTime: 0)
self.delegate?.enginePlayerStart(value: true)
} catch {
self.delegate?.enginePlayerStart(value: false)
print("Не удалось создать или воспроизвести паттерн: \(error)")
}
}
func stopHapticFeedback() {
do {
try hapticPlayer?.stop(atTime: 0)
self.delegate?.enginePlayerStart(value: false)
} catch {
self.delegate?.enginePlayerStart(value: true)
print("Не удалось остановить воспроизведение вибрации: \(error)")
}
}
}
extension CHHapticEngine.StoppedReason {
var message: String {
switch self {
case .audioSessionInterrupt:
return "the audio session was interrupted."
case .applicationSuspended:
return "the application was suspended."
case .idleTimeout:
return "an idle timeout occurred."
case .systemError:
return "a system error occurred."
case .notifyWhenFinished:
return "playback finished."
case .engineDestroyed:
return "the engine was destroyed."
case .gameControllerDisconnect:
return "the game controller disconnected."
@unknown default:
return "an unknown error occurred."
}
}
}
custom haptic events -
static func changeVibrationPower(power: HapricPower) -> [CHHapticEvent] {
let continuousEvent = CHHapticEvent(eventType: .hapticContinuous, parameters: [
CHHapticEventParameter(parameterID: .hapticSharpness, value: 1.0),
CHHapticEventParameter(parameterID: .hapticIntensity, value: power.value)
], relativeTime: 0, duration: 0.5)
return [continuousEvent]
}