Construct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.

UIKit Documentation

Post

Replies

Boosts

Views

Activity

What is ChronoKit.InteractiveWidgetActionRunner.Errors Code 1?
This is a follow up to this post about building a Control Center widget to open the app directly to a particular feature. I have it working in a sample app, but when I do the same thing in my full app I get this error: [[com.olivetree.BR-Free::com.olivetree.BR-Free.VerseWidget:com.olivetree.BR-Free.ContinueReadingPlanControl:-]] Control action: failed with error: Error Domain=ChronoKit.InteractiveWidgetActionRunner.Errors Code=1 "(null)" Google has nothing for any of that. Can anyone shed light on what it means? This is my control and its action: @available(iOS 18.0, *) struct ContinueReadingPlanControl : ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: "com.olivetree.BR-Free.ContinueReadingPlanControl") { ControlWidgetButton(action: ContinueReadingPlanIntent()) { Image(systemName: "book") } } .displayName("Continue Reading Plan") } } @available(iOS 18.0, *) struct ContinueReadingPlanIntent : ControlConfigurationIntent { static let title: LocalizedStringResource = "Continue Reading Plan" static let description = IntentDescription(stringLiteral: "Continue the last-used reading plan") static let isDiscoverable = false static let opensAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult & OpensIntent { let strUrl = "olivetree://startplanday" UserDefaults.standard.setValue(strUrl, forKey: "StartupUrl") return .result(opensIntent: OpenURLIntent(URL(string: strUrl)!)) } } Note also that I'm pulling this from Console.app, streaming the logs from my device. I don't know of a way to debug a Control Center widget in Xcode, though this thread implies that it's possible.
2
0
451
Sep ’24
How does OpenIntent in a control widget actually open the app to the target feature?
I want to add a Control Center widget for my app that will open the app to a particular feature. I'm looking at the "Open your app with a control" example here, which seems like exactly what I want: Set your control’s action to an app intent that conforms to OpenIntent to open your app when someone uses a control. Using OpenIntent allows you to take someone to a specific area of your app when a control performs its action. The example doesn't show exactly how to hook up the LaunchAppIntent to a control widget, but I'm guessing it's something like this: @available(iOS 18.0, *) struct OpenFeatureControl : ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: "com.example.OpenFeature") { ControlWidgetButton(action: LaunchAppIntent()) { Image(systemName: "book") } } .displayName("Launch Feature") } } But there's one critical piece missing here: how is the target feature actually opened? My initial assumption would have been that once the app launches or resumes, there's a call to some method like continueUserActivity that has a user-info dict with some key whose value is the LaunchAppEnum. But I've put breakpoints on all those methods in my app and none of them get called (I'm using UIKit scene lifecycle). I also tried a regular AppIntent with a perform method that talks to my app directly: @available(iOS 18.0, *) struct OpenFeatureIntent : AppIntent { static let title: LocalizedStringResource = "Open My Feature" static let opensAppWhenRun: Bool = true init() {} func perform() async throws -> some IntentResult { //MAIN_APP is defined in Active Compilation Conditions in build settings #if MAIN_APP let url = URL(string: "myapp://openfeature")! UrlHandler.instance().handle(url) #endif return .result() } } But when run, this simply does nothing. Launching an app directly to a particular view or feature seems like a common use-case for control widgets, and there are apps doing it, but I can't find an example of how it's supposed to work. And the docs are really not helpful. Can anyone provide the missing piece here? What's the expected plumbing in an OpenIntent that actually launches particular UI in the app?
3
1
723
Sep ’24
How can you use ContactAccessButton() or contactAccessPicker() with a storyboard?
I've got an existing app using storyboards and would like to incorporate the new iOS 18 ContactAccessButton() and contactAccessPicker() into the GUI. However, how can that be done? If I try to do something like add a UIView to a view controller in the storyboard, then ContactAccessButton can't be assigned to it (even though ContactAccessButton inherits from UIView). Nor can a ContactAccessButton be used as a type within the Storyboard/the View Controller. How do I go about integrating this new iOS feature into an existing app using Storyboards and view controllers?
2
0
290
Sep ’24
Scene Delegate Migration Lifecycle
We are in the process of migrating our application to SceneDelegate. We currently check in a variety of places if the app is running in the background for analytics reasons. The app may be running in the background due to location updates, notifications being received, or background refresh. With scene delegate, the app starts in the background state and only becomes active once a scene has connected. We have been unable to find a way if an app is truly running in the background or if a scene delegate is about to be launched.
2
0
215
Sep ’24
Syntax Highlighting with TextKit 2
Based on this TextKit 2 demo project I thought that I could implement syntax highlighting by parsing syntax block tokens (e.g. comments like <!-- --> or /* */) in processEditing and storing their locations, and then actually applying the rendering with NSTextContentStorageDelegate in textContentStorage(_:textParagraphWith:) by checking the location of each paragraph against the store of syntax tokens. This sort of works except that the rendering is only updated for paragraphs which are changed. Is there a way to trigger NSTextContentStorage to re-fetch paragraphs in a given range? Or is this a totally misguided approach to the problem?
1
0
316
Sep ’24
[Need help ASAP] UIKit - TabbarController - Tabbar is behind selected VC's view with Xcode16 RC + iOS18 RC combo, but the rest combo are just fine
So we are testing our app code base with Xcode16 and fix any compile errors. After it builds and run, we found our tar bar controller's tar bar is behind the selected VC's view. We thought it is our bug, but we have tested below combo: Xcode15 + iOS18 - Fine we are invited to your office to test the new iPhone 16 series, they are iOS18, and our app on the app store is totally fine (built with Xcode 15) Xcode15 + iOS < 18 - Fine Apparentely ok, it's shipped. Xcode16 RC + iOS 17 device - Fine it's also fine Xcode16 RC + iOS18 RC: tar bar is behind selected VC because we are not able to add iPhone 16 model to our account, we flushed our in-house device to iOS18 RC to test Xcode16 built app, The tar bar is behind the selected VC. We want to ask for help ASAP because we are totally out of mind what's going on. I have filed FB 15120641 but want to raise it here to gain more support and insights.
2
1
275
Sep ’24
How to make iPad app move to display show full-screen and center align
I wrote an app that can show live streaming. When using iPad, I can connect an external display and move app to display, that I can do what I want on my iPad and watch live streaming on external display using cable. But app moving to display is not always full screen, and on some displays it shows larger than the external display range that I should go to Settings -> Display & Brightness -> External Display -> Switching "Allow Display Mode Changes" to fix this issue. Are there APIs to make the App "move to display" programmatically, keep app full-screen, matching the external display's resolution on the External display?
2
0
349
Sep ’24
Xcode 16 RC iPhone16 ProMax simulator status bar height is wrong
I am using Xcode 16 RC to debug an iPhone 16 app. The status bar height returned by iPhone 16 and iPhone 16 Pro is 54, while the height of the status bar returned by iPhone 16 ProMax is 44. Why is this? Here is the code I use: [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager.statusBarFrame.size.height
1
0
533
Sep ’24
UIApplication.shared.open iOS 18
Making the call as: UIApplication.shared.open(websiteURL) doesn't open the browser and gives the following in the console: BUG IN CLIENT OF UIKIT: The caller of UIApplication.openURL(:) needs to migrate to the non-deprecated UIApplication.open(:options:completionHandler:). Force returning false (NO). However, making the call as: UIApplication.shared.open(websiteURL) { _ in } opens the browser and there is nothing in the cosole. Does someone understand why is this or if it's Apple's iOS 18 bug? In the iOS & iPadOS 18 RC Release Notes | Apple Developer Documentation there is a section around resolving this or something similar, unsure.
9
5
4.9k
Sep ’24
navigationItem.title now showing in iOS 18 UITabBarController
navigationItem.title does not display on the first view controller in the new UITabBarController on iPad. Also, if I set navigationItem.titleMenuProvider an empty space is displayed. Everything displays as expected if it isn’t the first view controller. let tabBarController = UITabBarController(tabs: [ UITab(title: "Tab 1", image: nil, identifier: "tab1", viewControllerProvider: { _ in return UINavigationController(rootViewController: ViewController()) }) ]) class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "First" navigationItem.titleMenuProvider = { suggestions in return UIMenu(children: [ UIAction(title: "Option 1", handler: { _ in self.navigationController?.pushViewController(SecondViewController(), animated: true) }), UIAction(title: "Option 2", handler: { _ in }) ]) } } } class SecondViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Second" navigationItem.titleMenuProvider = { suggestions in return UIMenu(children: [ UIAction(title: "Option 1", handler: { _ in }), UIAction(title: "Option 2", handler: { _ in }) ]) } } }
3
0
345
Sep ’24
iPadOS 18 - Move Tab Bar to bottom
As iPadOS 18 shows Tab Bar on top (tvOS'esq), can someone please tell me what changes do I need to make to get tab bar shown as a regular one (Pre iPadOS 18 style)? Tab bar being at the bottom is easily accessible. And, it being on top needs too much of hands movement. That being on top is is occupying, in a way, more screen real estate. Any ideas appreciated. Thank you.
5
3
1.6k
Sep ’24
Save large PDF file with UIDocument
Hi, I'm working with UIDocument to store a PDF file. This is code I use for saving a file. document.close(completionHandler: { (success) in if success { document.save(to: url, for: .forOverwriting, completionHandler: { (success) in if success { print("Saved file successfully") } }) } }) This code works well with a small file size. But if it's a large file like 100MB, it takes around 2-5 minutes to save the file. Is there a way to save file with the changes only? Or create an auto save function triggered whenever the user edit the file?
2
0
269
Sep ’24
If you cancel a print job using AirPrint while the printer is turned off, the print center remains on the app switcher and subsequent printing cannot be performed correctly.
-Environment iPad:10th、iOS:17.6.1、Printer:EPSON PX-S730 -Question Is this phenomenon due to iOS specifications? Restarting the iPad solves the problem, but I don't think it's best practice to restart it every time you reproduce it. Please let me know if you have a good solution. -Problem I am developing a print preview screen using AirPrint's print method. If you submit a print job using AirPrint on an iPad while the printer is turned off and then cancel it, the print center remains on the app switcher. After that, when I turned on the printer, I was no longer able to print using AirPrint on my iPad. When using AirPrint's API "print" and when printing by launching AirPrint from Safari, we have confirmed the same behavior in both cases. -How to reproduce Turn off the printer Print from iPad to printer using AirPrint Launch the print center from the app switcher, cancel the print job, and set the number of print jobs to 0. When you start the app switcher, the Print Center app remains. In step 4, turn on the printer and print from the iPad to the printer using AirPrint. When you start Print Center from the app switcher, the print job status becomes "Waiting" and the print job is not executed. -Expected result When there are no print jobs on the print center, the print center is closed on the app switcher. You can print from your iPad to the printer using AirPrint, and then print from the printer. -Actual results When there are no print jobs on the print center, the print center remains on the app switcher without being closed. In the above situation, when printing from the iPad to the printer using AirPrint, the printer does not print. When I start the print center, the print job status is "Waiting" and is queued. -Code printInfo.jobName = "Print Job" printController.printInfo = printInfo let pdfURL = Bundle.main.url(forResource: "sample", withExtension: "pdf")! printController.printingItem = pdfURL let printer = UIPrinter(url: printerUrl) printController.print(to: printer, completionHandler: { [self] printController, completed, error in if(error != nil){ print("error"). }else if completed{ print("completed") //this scenario handles completion response }else{ print("cancel") } }) -Link of API used Apple Developer-AirPrint-print -Similar inquiries Apple Developer Forum - Print Center on my iPhone shows a pending document to print and I can't get rid of it
1
0
428
Sep ’24
macOS Sequoia – NSToolbar on Catalyst disappeared
Hello, I have a macOS Catalyst app that I now began updating and building against the iOS 18/macOS Sequoia SDKs. Most things appear to be working just fine as before, apart from my NSToolbar. At the root of my app I am presenting a UISplitViewController which gets a custom SidebarViewController and a UITabBarController as its viewControllers. Then at same point in the apps lifecycle the UITabBarController presents another ViewController modally. I then associate the controllers window with a custom NSToolbar like this: let toolbar = NSToolbar(identifier: "mainToolbar") toolbar.displayMode = .iconAndLabel toolbar.delegate = self toolbar.allowsUserCustomization = false titleBar.toolbarStyle = .automatic titleBar.titleVisibility = .hidden titleBar.toolbar = toolbar I also disable automatic NSToolbar hosting via: https://developer.apple.com/documentation/uikit/uinavigationbardelegate/3987959-navigationbarnstoolbarsection (returning .none). Now all of this worked fine on macOS Sonoma and previous versions but on Sequoia my custom toolbar refuses to show up. My suspicion is that is has something to do with the new tab and sidebar behaviour introduced with the new SDKs (https://developer.apple.com/documentation/uikit/uinavigationbardelegate/3987959-navigationbarnstoolbarsection). For now within my UITabBarController I was able to revert to the old look using: if #available(iOS 18.0, *) { mode = .tabSidebar sidebar.isHidden = true isTabBarHidden = true } This result in a look similar to the previous macOS version but my NSToolbar unfortunately remains hidden. Is there an easy fix for this? Since I am a solo developer I would prefer to spend my available resources currently on other features and adopt the new tab/sidebars a couple months down the line. Appreciate any help and hints, thanks! There used to be a toolbar here on the right side. ↑
2
1
456
Sep ’24
UIButton starts out focused but can't navigate back to it
I'm an experienced iOS developer but new to tvOS, and I'm finding the focus engine to be somewhat confounding. My app launches with a UINavigationController, whose root view is a UITableViewController. When I select a row, a UIViewController is pushed. That view controller contains a bunch of nested UICollectionViews. One of the collection view cells contains 3 UIButtons. When the view first appears, the first of those (Button1) has focus. I can move focus from Button1 to Button2, and from Button2 to Button3. I can also go back from Button3 to Button2. But I cannot navigate back to Button1, and I'm trying to figure out why. I have focus logging turned on. It's very verbose, but here are the parts that seem useful to me: When the view controller displays initially, I see Updating focus from <UITableViewCell: 0x104841a00> to <DXETV.CustomButton: 0x104232610> in focus system <UIFocusSystem: 0x60000370c900>. The result of the focus update was determined from the following preferred focus search: | | Starting preferred focus search. | <UINavigationController: 0x10600f000> | └ <DXETV.RenderExampleViewController: 0x10484ae00> | └ <DXETV.RenderExampleView: 0x10421ab70> | └ <DXETV.LayoutElementView: 0x107021000> | └ <DXETV.LayoutCollectionView: 0x10707d200> | └ <DXETV.LayoutViewCell: 0x10681ee00> | └ <DXETV.LayoutElementView: 0x106862000> | └ <DXETV.LayoutCollectionView: 0x106865a00> | └ <DXETV.LayoutViewCell: 0x106851000> | └ <DXETV.LayoutElementView: 0x104891800> | └ <DXETV.LayoutCollectionView: 0x10488da00> | └ <DXETV.LayoutViewCell: 0x1048de600> | └ <DXETV.CustomButton: 0x104232610> | (info) It's focusable! | This seems right... focus moves from the table view cell to Button1, and this is he view hierarchy I expect. Then we see Creating focus scroll animator entry for environment <DXETV.LayoutCollectionView: 0x10707d200> This is the topmost collection view. This is followed by many lines about locking and unlocking this collection view, followed by Removing focus scroll animator entry for environment <DXETV.LayoutCollectionView: 0x10707d200> I don't know if this is normal or not. After I move focus from Button1 to Button2, I see Updating focus with context <UIFocusUpdateContext: 0x6000033200a0: previouslyFocusedItem=<DXETV.CustomButton 0x104232610>, nextFocusedItem=<DXETV.CustomButton 0x104312900>, focusHeading=Down>: Moving focus from <DXETV.CustomButton: 0x104232610> to <DXETV.CustomButton: 0x104312900> in focus system <UIFocusSystem: 0x60000370c900>. Which seems correct. When I move focus from Button2 to Button3, I get this, which is now expected: Updating focus with context <UIFocusUpdateContext: 0x60000330c5a0: previouslyFocusedItem=<DXETV.CustomButton 0x104312900>, nextFocusedItem=<DXETV.CustomButton 0x1043134d0>, focusHeading=Down>: Moving focus from <DXETV.CustomButton: 0x104312900> to <DXETV.CustomButton: 0x1043134d0> in focus system <UIFocusSystem: 0x60000370c900>. Followed by another round of creating and removing a focus scroll animator entry, this time for the middle collection view. Moving from Button3 back to Button2 also looks as expected: Updating focus with context <UIFocusUpdateContext: 0x600003318f00: previouslyFocusedItem=<DXETV.CustomButton 0x1043134d0>, nextFocusedItem=<DXETV.CustomButton 0x104312900>, focusHeading=Up>: Moving focus from <DXETV.CustomButton: 0x1043134d0> to <DXETV.CustomButton: 0x104312900> in focus system <UIFocusSystem: 0x60000370c900>. But here, everything stops. When I press the up arrow again to go back to Button1, nothing happens. Nothing is printed to the console, and the focused button does not change. Any hints as to what may be wrong or how to debug this further would be most appreciated!!!
0
0
334
Sep ’24
highlightPreviewForItemAt for Collection View not working at all
Hello, I have collection view with context menu using contextMenuConfigurationForItemAt and I wanted to customize the preview, when user long presses and context menu is shown. Something maybe like in the Music app when you long press on an album it shows the album in bigger size... I found some snippets online for highlightPreviewForItemAt and dismissalPreviewForItemAt but it just doesn't work. As soon as a implemented these delegate methods, nothing happens when I long press, not even the standard preview with context menu. These two methods aren't being called at all. Do I need to do something else? Do I need the previewProvider when creating the context menu? It is my understanding that that is needed only when the item should also open further detail on tap - which is something I don't need and want. Below is my relevant implementation: private func shareMenuConfiguration(for itemAt: URL, indexPath: IndexPath) -> UIContextMenuConfiguration { let share = UIAction(title: "Share".localized(), image: UIImage(systemName: "square.and.arrow.up")) { [unowned self] _ in let shareVC = UIActivityViewController(activityItems: [itemAt], applicationActivities: nil) if let cell = collectionView.cellForItem(at: indexPath) { shareVC.popoverPresentationController?.sourceView = cell.contentView shareVC.popoverPresentationController?.sourceRect = cell.contentView.bounds } self.present(shareVC, animated: true) } return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in UIMenu(title: "", children: [share]) } } func collectionView(_ collectionView: UICollectionView, contextMenuConfiguration configuration: UIContextMenuConfiguration, highlightPreviewForItemAt indexPath: IndexPath) -> UITargetedPreview? { guard let item = datasource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) as? GalleryImageCell else { return nil } let parameters = UIPreviewParameters() let visibleRect = cell.contentView.bounds.insetBy(dx: 1/3, dy: 1/3) let visiblePath = UIBezierPath(roundedRect: visibleRect, cornerRadius: 4) parameters.visiblePath = visiblePath return UITargetedPreview( view: cell.contentView, parameters: parameters, target: .init(container: collectionView, center: collectionView.convert(cell.contentView.center, from: cell.contentView)) ) } func collectionView(_ collectionView: UICollectionView, contextMenuConfiguration configuration: UIContextMenuConfiguration, dismissalPreviewForItemAt indexPath: IndexPath) -> UITargetedPreview? { guard let item = datasource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) as? GalleryImageCell else { return nil } let parameters = UIPreviewParameters() let visibleRect = cell.contentView.bounds.insetBy(dx: 1/3, dy: 1/3) let visiblePath = UIBezierPath(roundedRect: visibleRect, cornerRadius: 4) parameters.visiblePath = visiblePath return UITargetedPreview( view: cell.contentView, parameters: parameters, target: .init(container: collectionView, center: collectionView.convert(cell.contentView.center, from: cell.contentView)) ) } Thanks!
0
0
259
Sep ’24