Posts

Post not yet marked as solved
1 Replies
148 Views
struct SheetView: View { @Binding var showSheet: Bool var body: some View { LazyVStack { Button("Dismiss") { showSheet.toggle() } } } } struct ContentView: View { @State private var showSheet = false var body: some View { Button("Show") { showSheet.toggle() } .sheet(isPresented: $showSheet) { SheetView(showSheet: $showSheet) } } } Xcode displays === AttributeGraph: cycle detected through attribute 119104 === message in console when SheetView is presented on screen. Environment: macOS 14.4.1 Xcode: Version 15.2
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
0 Replies
286 Views
Based on official docs click is available for iPadOS apps. We utilized click action to create universal UITests for macOS and iPadOS targets. It works fine on iPadOS 16.x but, unfortunately, stops to work in iOS 17 simulators for iPad. Environment: MacOS - 13.5.2 (22G91). Xcode - Version 15.0 (15A240d). Simulator - Version 15.0 (1015.2). SimulatorKit 935.1. CoreSimulator 920.6. Steps to reproduce: Create new multiplatform app Add simple button. For example: struct ContentView: View { @State var title = "Click Me" var body: some View { VStack { Button(title) { title = "Clicked" } .background(Color.blue) .foregroundColor(.white) } .padding() } } Add UITest that clicks on button. For example: func testClick() throws { let app = XCUIApplication() app.launch() app.buttons["Click Me"].click() XCTAssertTrue(app.buttons["Clicked"].exists) } Expected result: test is passed Actual result: test is failed since buttons["Click Me"].click() doesn't click in button. Workaround: Replacement .click() to .tap() fixes the issue but it makes impossible to create universal tests with single action for both platforms
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
1 Replies
1.1k Views
We are developing driver for our USB device. Our approach is to run and test driver on macOS first and then verify on iPadOS 16. In the driver we add custom property -"kUSBSerialNumberString" into default properties: OSDictionary * Driver::devicePropertiesWithSerialNumber() {     kern_return_t ret;     OSDictionary *properties = NULL;     OSDictionary *dictionary = NULL;     OSObjectPtr value;     const IOUSBDeviceDescriptor *deviceDescriptor;     deviceDescriptor = ivars->device->CopyDeviceDescriptor();          ret = CopyProperties(&properties);     value = copyStringAtIndex(deviceDescriptor->iSerialNumber, kIOUSBLanguageIDEnglishUS);     Log("Serial number: %{public}s", ((OSString *)value)->getCStringNoCopy());          dictionary = OSDictionary::withDictionary(properties, 0);     OSSafeReleaseNULL(properties);     if (value) {         OSDictionarySetValue(dictionary, "kUSBSerialNumberString", value);         OSSafeReleaseNULL(value);     }     return  dictionary; } next in kern_return_t IMPL(Driver, Start) we call SetProperties:     ret = SetProperties(devicePropertiesWithSerialNumber());     if(ret != kIOReturnSuccess) {         Log("Start() - Failed to set properties: 0x%08x.", ret);         goto Exit;     } We can read our property on macOS using:     func getDeviceProperty(device: io_object_t, key: String) -> AnyObject? {         IORegistryEntryCreateCFProperty(             device, key as CFString, kCFAllocatorDefault, .zero         )?.takeRetainedValue()     }         if let serialNumber = getDeviceProperty(device: driver, key: "kUSBSerialNumberString") {             print("serialNumber: \(serialNumber)")         } However getDevicePropertyon iPadOS returns nil. We are wondering is any limitation for IORegistry entries(properties) on iPadOS16? Is any way to add custom property to IORegistry? BTW, we added debug method to print all the available properties for IORegistry:     private func debugRegistry(device: io_object_t) {         var dictionary: Unmanaged<CFMutableDictionary>?         IORegistryEntryCreateCFProperties(device, &dictionary, kCFAllocatorDefault, .zero)         if let dictionary = dictionary {             let values = dictionary.takeUnretainedValue()             print(values)         }     } It returns just 1 property for iPadOS: { IOClass = IOUserService; } and much more for macOS including our custom one: { CFBundleIdentifier = "****"; CFBundleIdentifierKernel = "com.apple.kpi.iokit"; IOClass = IOUserService; IOMatchCategory = "***"; IOMatchedPersonality = { CFBundleIdentifier = "****"; CFBundleIdentifierKernel = "com.apple.kpi.iokit"; IOClass = IOUserService; IOMatchCategory = "****"; IOPersonalityPublisher = "****"; IOProviderClass = IOUSBHostInterface; IOResourceMatch = IOKit; IOUserClass = Driver; IOUserServerCDHash = 9cfd03b5c1b90da709ffb1455a053c5d7cdf47ac; IOUserServerName = "*****"; UserClientProperties = { IOClass = IOUserUserClient; IOUserClass = DriverUserClient; }; bConfigurationValue = 1; bInterfaceNumber = 1; bcdDevice = 512; idProduct = XXXXX; idVendor = XXXXX; }; IOPersonalityPublisher = "*****"; IOPowerManagement = { CapabilityFlags = 2; CurrentPowerState = 2; MaxPowerState = 2; }; IOProbeScore = 100000; IOProviderClass = IOUSBHostInterface; IOResourceMatch = IOKit; IOUserClass = Driver; IOUserServerCDHash = 9cfd03b5c1b90da709ffb1455a053c5d7cdf47ac; IOUserServerName = "*****"; UserClientProperties = { IOClass = IOUserUserClient; IOUserClass = DriverUserClient; }; bConfigurationValue = 1; bInterfaceNumber = 1; bcdDevice = 512; idProduct = XXXXX; idVendor = XXXXXX; kUSBSerialNumberString = XXXXXXXXXXX; }
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
2 Replies
918 Views
Apple Docs mentions that driver should be approved(enabled) in Settings app. I wonder is there any API available to check that driver is not enabled? To my mind, App with driver should have a following flow: Run App Check that driver is(not) enabled Display message(alert) and ask to enable driver in Settings. Optionally: provide shortcut to exact Settings page Unfortunately, it's not obvious how to check that driver is enabled.
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
6 Replies
1.7k Views
In following code example: struct ContentView: View {     @State var text: String = "sample text"     var body: some View {         VStack {             TextField("", text: $text)             Button(action: { print("action performed!") }) {                 Text("Click me")             }             .keyboardShortcut(.defaultAction)         }         .padding(40)     } } .keyboardShortcut(.defaultAction) that is attached to Button perfectly works on macOs Big Sur(11.6) and I see "action performed!" in Xcode console when tap Enter key on keyboard. Unfortunately, same example doesn't work on macOs Monterey(12.0.1) and Xcode 13.1. So nothing happens(I don't see any logs) when I tap Enter key on keyboard. Also I noticed that it happens only when focus is set in TextField. I checked that onSubmit can solve this issue. Unfortunately, I can't use since it's available in macOs 12 or newer but my App has deployment target is macOs 11. So any workarounds are welcomed.
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
0 Replies
765 Views
We are experiencing missing coverage for private variables in SwiftUI views after update from Xcode 14.3 to Xcode 14.2. Steps to reproduce: Create new SwiftUI project in Xcode Enable code coverage Modify ContentView to struct ContentView: View { private let title = "Hello, world!" let text: String var body: some View { VStack { Text(title) Text(text) } .padding() } } Run UITest - CoverageTestTests::testExample Check coverage in Xcode for ContentView Actual result: Line private let title = "Hello, world!" is not covered. Expected result: Line should be covered Workaround: Generate initialiser for ContentView init(text: String) { self.text = text } Coverage is correct when initialiser is added explicitly Test project: https://github.com/yuri-qualtie/CoverageTest
Posted
by myurik2.
Last updated
.
Post marked as solved
2 Replies
1.6k Views
We are experimenting with DriverKit on macOS while DriverKit is still in beta on iPadOS. We want to build a Driver for iPad that will allow to communicate our iPad App with USB device. What we did: Configured and implemented a driver that uses USBDriverKit::IOUSBHostInterface as provider. This driver is automatically matched/started by macOS when we plug our device into USB port. Next we utilised USBDriverKit::IOUSBHostPipe to send/receive data from our device. We print data from device in logs for now. Studied Communicating Between a DriverKit Extension and a Client App Configured and implemented a driver that based on IOUserClient and allows to open communication channel by macOs App using IOServiceOpen API. Driver has callback to pass data to macOS Client App. Currently we want to combine 2 drivers and pass data received from USB device to our client App using callback. Unfortunately, we stuck since now we have 2 instances of driver: First instance is automatically run by macOS when device is plugged Second instance is created when we are connecting from Client App and virtual kern_return_t NewUserClient(uint32_t type, IOUserClient** userClient) method is called. So we can't use second instance to do USB device communication since it has wrong provider(IOUserClient) in kern_return_t Start(IOService * provider) but we need IOUSBHostInterface to start:     ivars->interface = OSDynamicCast(IOUSBHostInterface, provider);     if(ivars->interface == NULL) {         ret = kIOReturnNoDevice;         goto Exit;     } Are we doing it wrong? Maybe instead of automatic matching for IOUSBHostInterface we should do it manually from UserClient driver or use another approach? As we learned we have to create a new service instance in NewUserClient method and can't return driver that was run by OS: kern_return_t IMPL(MyDriver, NewUserClient) {     kern_return_t ret = kIOReturnSuccess;     IOService* client = nullptr;     ret = Create(this, "UserClientProperties", &client);     if (ret != kIOReturnSuccess)     {         goto Exit;     }     *userClient = OSDynamicCast(IOUserClient, client);     if (*userClient == NULL)     {         client->release();         ret = kIOReturnError;         goto Exit;     } Exit:     return ret; } BTW, maybe there is much easier way to forward data from USB device to iPadOS App?
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
0 Replies
821 Views
We are building iPadOS App that uses bundled DriveKit driver to communicate with USB device. This bundled driver should be enabled first by user from App's settings or Privacy & Security page. We read in Apple Docs that openSettingsURLString is recommended way to navigate user to App's settings. We added alert that is shown on App launch and has option to open settings. Our solution perfectly works on local DEBUG build. So user is navigated to App's settings when he click "Open Settings". However it doesn't work for TestFlight/App Store builds. "Open Settings" just opens system Settings app on some random page. Code: let settingsURL = URL(string: UIApplication.openSettingsURLString)! UIApplication.shared.open(settingsURL) Environment: Xcode Version 14.1(14B47b) iPadOS 16.1.1(20B101) Note: Our Settings.bundle contains Root.plist with no custom settings: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict/> </plist> We read speculations that some permission request should be triggered before navigation. Unfortunately, there is no API that checks or requests permission for DriverKit in the moment.
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
6 Replies
986 Views
We got development entitlement for our Driver that we requested here: https://developer.apple.com/contact/request/system-extension/ Next we tested our Driver on test devices and now want to upload build into TestFlight. But it looks like we need distribution version of same entitlements. Where we can request them? BTW, Apple Docs: Requesting Entitlements for DriverKit Development describe only development approach. It would be good to add instructions for Distribution as well.
Posted
by myurik2.
Last updated
.
Post marked as Apple Recommended
5.6k Views
We used Locale::usesMetricSystem to distinguish between metric and Imperial(US) measurement systems. We set "-AppleLocale en_US" as launch argument for App in UITests but usesMetricSystem still returns true in case user's locale are not equal to "US" in System Preferences - Language and Region - Region. Here is a demo project to illustrate the issue: https://github.com/yuri-qualtie/UseMetricSystemDemo Precondition: Change user region to not US(for example Australia) in System Preferences - Language and Region - Region We expect that code: print(Locale.current.usesMetricSystem) prints false when -AppleLocale en_US is set but actual result is true Probably there is alternative way how to change measurement system via launch arguments or App's settings in Xcode?
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
5 Replies
2.3k Views
We created Driver sample by Xcode template and following macro was added into code: #define Log(fmt, ...) os_log(OS_LOG_DEFAULT, "Driver - " fmt "\n", ##__VA_ARGS__) We used this macro in init and start. For example: bool ForcePlateDriver::init() { Log("init()"); But our logs are not displayed in Console app. Did we miss something? Is anything else is required to have logs for Driver? Our environment: MacOS Monterey - 12.4 (21F79) Xcode - Version 13.4 (13F17a)
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
1 Replies
885 Views
We are developing our Driver using DriverKit. In client App we successfully discover our driver but can't get IORegistry properties except IOClass. So in a client App we use following code to read properties:     private func debugRegistry(device: io_object_t) {         var dictionary: Unmanaged<CFMutableDictionary>?         IORegistryEntryCreateCFProperties(device, &dictionary, kCFAllocatorDefault, .zero)         if let dictionary = dictionary {             let values = dictionary.takeUnretainedValue()             print(values)         }     } output is: {     IOClass = IOUserService; } We tested same code on macOS and output contains about 20+ properties. It looks like IOKi doesn't allow to read other properties except IOClass. Environment: Xcode - Version 14.1 beta 2 (14B5024i). iPadOS - iOS 16.1 (20B5050f)
Posted
by myurik2.
Last updated
.
Post marked as solved
1 Replies
848 Views
We are developing driver for our USB device. We've implemented commutation using IOUSBHostPipe::IO and it perfectly works for data packets that less than 256 bytes. However it hangs when reply from USB device is about 512 bytes. We see 0x2ed // device not responding error when we unplug our device and driver is stopped. Here is our code for setup: constexpr uint32_t kOutEndpointAddress = 1; constexpr uint32_t kInEndpointAddress = 129; constexpr uint16_t kBufferSize = 256; ..... struct ForcePlateDriver_IVars { ....     IOUSBHostPipe            *inPipe;     IOBufferMemoryDescriptor *inData;     uint16_t                  maxPacketSize; }; .....     ret = ivars->interface->CopyPipe(kInEndpointAddress, &ivars->inPipe);     ret = ivars->interface->CreateIOBuffer(kIOMemoryDirectionIn,                                            ivars->maxPacketSize,                                            &ivars->inData); We use following code for reading data from USB device:     uint32_t bytesTransferred = 0;     ret = ivars->inPipe->IO(                             ivars->inData,                             ivars->maxPacketSize,                             &bytesTransferred,                             0); What we tried: Increase kBufferSize to 512 but drive still hangs Change 0 to 2000 (timeout) for inPipe->IO method. Result method returns - 0x2d6(// I/O Timeout)
Posted
by myurik2.
Last updated
.
Post marked as solved
9 Replies
3.8k Views
We use .xcresult files on our CI and recently noticed that size of file significantly increased. So previously we had files ~ 50 MB but now they are ~ 300 MB. After investigation of .xcresult contents we found that it contains macOS Logs - test-session-systemlogs-2022.01.05_13-13-07-+0000 In testmanagerd .log we see in a last line: Moved logarchive from /var/tmp/test-session-systemlogs-2022.01.05_13-13-07-+0000.logarchive to ../Staging/1_Test/Diagnostics/My Mac_4203018E-580F-C1B5-9525-B745CECA79EB/test-session-systemlogs-2022.01.05_13-13-07-+0000.logarchive Issue is reproducible on a new project. Steps: File -> New -> Project Select macOS -> App Enable include test For simplicity disable(comment) all the UITests except ResultSampleUITests::testExample Add XCTAssertTrue(false) after app.launch() Run tests from console and specify path to resultBundlePath xcodebuild -project ResultSample.xcodeproj -scheme ResultSample -resultBundlePath ~/Downloads/2/all-tests -test-timeouts-enabled YES test 7. When tests are finished navigate to resultBundlePath and check size of all-tests.xcresult. It has size 51.6 MB for me. If change XCTAssertTrue(false) to XCTAssertTrue(true) then size of all-tests.xcresult is decreased to 31 KB. Any idea how to disable/delete macOS diagnostic logs or decrease a size of .xcresult
Posted
by myurik2.
Last updated
.
Post not yet marked as solved
2 Replies
1.4k Views
We implemented communication between Swift App and DriverKit driver using IOConnectCallAsyncStructMethod. So in Swift App we have following code to setup AsyncDataCallback: func AsyncDataCallback(refcon: UnsafeMutableRawPointer?, result: IOReturn, args: UnsafeMutablePointer<UnsafeMutableRawPointer?>?, numArgs: UInt32) -> Void { // handle args } var asyncRef: [io_user_reference_t] = .init(repeating: 0, count: 8) asyncRef[kIOAsyncCalloutFuncIndex] = unsafeBitCast(AsyncDataCallback as IOAsyncCallback, to: UInt64.self) asyncRef[kIOAsyncCalloutRefconIndex] = unsafeBitCast(self, to: UInt64.self) ...... let notificationPort = IONotificationPortCreate(kIOMasterPortDefault) let machNotificationPort = IONotificationPortGetMachPort(notificationPort) let runLoopSource = IONotificationPortGetRunLoopSource(notificationPort)! CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource.takeUnretainedValue(), CFRunLoopMode.defaultMode) var input = "someinput".map { UInt8($0.asciiValue!) } let inputSize = input.count IOConnectCallAsyncStructMethod(             connection,             123,             machNotificationPort,             &asyncRef,             UInt32(kIOAsyncCalloutCount),             &input,             inputSize,             nil,             nil ) In the driver's ExternalMethod we save callback in ivars: ivars->callbackAction = arguments->completion; ivars->callbackAction->retain(); Next we start communication with our device in a separate thread and execute callback when we get data from device: SendDataAsync(void *data, uint32_t dataLength) { const int asyncDataCount = 16; if (ivars->callbackAction != nullptr) {         Log("SendDataAsync() - got %u bytes", dataLength);         uint64_t asyncData[asyncDataCount] = { };         asyncData[0] = dataLength;         memcpy(asyncData + 1, data, dataLength);         AsyncCompletion(ivars->callbackAction, kIOReturnSuccess, asyncData, asyncDataCount);     } Limitation 1: Our device produces data packet every 10 ms. So driver gets 100 data packets per second. Receive rate is good and we verified it by logs. However we see some delay in AsyncCallback in Swift App. It looks like async calls are queued since we see that Swift App gets callbacks for a few seconds when we stopped to send data from Driver. We measured receive rate in Swift App and it is about 50 data packets per second. So what's a minimum call rate for AsyncCompletion? Is it higher than 10 ms? Maybe there is other more efficient way to asynchronously pass data from Driver to Swift App? Limitation 2: We thought we can buffer data packets and decrease AsyncCompletion call rate. However asyncData could be only 16 of uint64_t by declaration typedef uint64_t IOUserClientAsyncArgumentsArray[16];. Size of our data packer is 112 bytes that perfectly fits to max args size(8*16 = 128 bytes). So we can't cache and send 2 data packets. How we can avoid this limitation and send more data via AsyncCompletion? Is there any other API for asynchronous communication that allows send more data back?
Posted
by myurik2.
Last updated
.