Hi,
I have few questions regarding the widgets.
I would like to know whether widget and app extensions are same ? This link(https://developer.apple.com/app-extensions/) says widget is type of app extension but I am not quite sure as few link in web says they are different. so need to confirm here :)
Can a widget share same bundle id as the main app ? so basically can we use the same provisioning profile as the main app?
If we use the same bundle id and provisioning profile, will there be any issue during the app store submission process.?
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am revising my app to support NSWritingToolsCoordinator/ NSWritingToolsCoordinatorDelegate.
When proofreading some paragraphs, it works well.
But, when proofreading many paragraphs (for example, 56 paragraphs), it can't complete the proofreading.
I am not sure which is wrong with my app or macOS API.
I think I implemented all NSWritingToolsCoordinatorDelegate methods.
Is there any information for such an issue?
Phenomenon
For paragraphs 1-9, text animation completed. But, for paragraphs 10-56, text animation does not complete.
It shows 5 corrected items, but I can't jump to items 3, 4, 5, when I click the ">" button in the "Proofread" window.
Items 3, 4, 5 were not corrected actually.
Log
For each NSWritingToolsCoordinatorDelegate method, the method name and main arguments are output by NSLog.
requestsContextsForScope
willChangeToState newState:2
requestsPreviewForTextAnimation range:(0, 18233)
prepareForTextAnimation range:(0, 18233)
willChangeToState newState:3
requestsPreviewForTextAnimation range:(0, 18233)
finishTextAnimation range:(0, 18233)
requestsPreviewForRect
requestsPreviewForTextAnimation range:(0, 1837)
replaceRange proposedText:an range:(208, 2)
replaceRange proposedText:you range:(443, 4)
prepareForTextAnimation range:(1836, 16396)
requestsPreviewForTextAnimation range:(0, 1836)
requestsBoundingBezierPathsForRange range:(208, 2)
requestsBoundingBezierPathsForRange range:(443, 3)
requestsPreviewForRect
prepareForTextAnimation range:(0, 1836)
prepareForTextAnimation range:(1836, 0)
finishTextAnimation range:(1836, 16396)
requestsPreviewForTextAnimation range:(1836, 16396)
requestsBoundingBezierPathsForRange range:(208, 2)
requestsBoundingBezierPathsForRange range:(443, 3)
prepareForTextAnimation range:(1836, 16396)
finishTextAnimation range:(0, 1836)
finishTextAnimation range:(0, 1836)
replaceRange proposedText:an range:(208, 2)
requestsUnderlinePathsForRange range:(208, 2)
requestsUnderlinePathsForRange range:(443, 3)
selectRanges ranges.count:1
requestsBoundingBezierPathsForRange range:(208, 2)
replaceRange proposedText:an range:(208, 2)
requestsUnderlinePathsForRange range:(208, 2)
requestsUnderlinePathsForRange range:(443, 3)
selectRanges ranges.count:1
replaceRange proposedText:you range:(443, 3)
requestsUnderlinePathsForRange range:(208, 2)
requestsUnderlinePathsForRange range:(443, 3)
selectRanges ranges.count:1
requestsBoundingBezierPathsForRange range:(443, 3)
replaceRange proposedText:you range:(443, 3)
requestsUnderlinePathsForRange range:(208, 2)
requestsUnderlinePathsForRange range:(443, 3)
selectRanges ranges.count:1
macOS version is 15.3.1 (24D70)
I want to keep the sidebar fixed in NavigationSplitView. I don’t want the user to be able to open or close the sidebar. I removed the toggle button, but I still couldn’t make the sidebar stay fixed. It can still be closed using Cmd + Alt + S or by dragging.
What I want is just to disable the resize feature of the sidebar. Isn’t it possible with SwiftUI?
NavigationSplitView is kind of blackhole :)
LeftSidebarView()
.environmentObject(detailView)
.toolbar(removing: .sidebarToggle)
.navigationSplitViewColumnWidth(240)
In UIKit, certain events like a button tap can be simulated using:
button.sendActions(for: .touchUpInside)
This allows us to trigger the button’s action programmatically.
However, in SwiftUI, there is no direct equivalent of sendActions(for:) for views like Button. What is the recommended approach to programmatically simulate a SwiftUI button tap and trigger its action?
Is there an alternative mechanism to achieve this(and for other events under UIControl.event) , especially in scenarios where we want to test interactions or trigger actions without direct user input?
Our Apple TV provides UIImages with renderingMode forced to .alwaysTemplate (the images are also configured with "Render As" to "Template image" in the Asset catalog) to UIActions as UIMenuElement when building a UICollectionView UIContextMenuConfiguration.
Problem: these images are not displayed with vibrancy effect by the system.
The issue does not occur with system images (SVG from SF Catalog).
Here is a screenshot showing the issue with custom images ("Trailer" and "Remove from favourites"):
I don't know the underlying implementation of the context menu items image but UIImageView already implements the tintColorDidChange() method and the vibrancy should work if the UIImage is rendered as template.
According to my tests, the vibrancy is correctly applied when using Symbols sets instead of Images sets but I understand that custom images rendered as template should support it as-well, shouldn't they?
I want to present a textfield inside a sheet.
However when the keyboard is shown, the sheet view produces extra padding even though I explicitly set the frame of the textfield and the presentationDent to be the exact same height.
Reproducible example:
struct ContentView: View {
@State var showSheet: Bool = false
@State var text = ""
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
Button {
showSheet.toggle()
} label: {
Text("Show Sheet")
}
}
.sheet(isPresented: $showSheet) {
TextField("Hello", text: $text)
.frame(height: 44)
.background(.red)
.presentationDetents([.height(44)])
.presentationDragIndicator(.hidden)
}
}
}
Does anyone know how to resolve this issue?
There are two issues about SFSafariViewController.
After rotate from landscape to portrait,
The topAnchor is destroyed.
The specified bar tint color and control tint color are invalidated.(Returns to system color)
Regarding the second issue, I’ve found a temporary workaround.
Override the viewWillTransition(to:with:) and keep it empty. Don't call super.viewWillTransition(to:with:).
Since UIKit is not open source, I don’t know the exact cause, but I found something that could be the key to the issue. So, I reported it to Apple Feedback Assistant. You can check the details and the sample project in the GitHub repository below.
https://github.com/ueunli/SafariViewer
If you add the .scaleEffect() modifier to a parent view inside of which there are children with contextMenu()-s, the context menu preview unfortunately keeps the original, unscaled size of the child view. This results in a very weird, glitchy user experience.
Unfortunately, providing a custom preview that is scaled up also does not help, since even though it is the right size, it gets cropped to the unscaled size of the child view.
Adding scaleEffect() to each child element individually (BEFORE the contextMenu() modifier!) does make the problem disappear. However, I would like to avoid this, since my use case is zooming into a complex graph with context menus on its nodes, and having to recalculate the position of each node manually seems to perform much worse than delegating that work to scaleEffect().
Tested on iOS 18.2 (device + emulator)
Is there a workaround?
Here is a minimal working example that demonstrates the problem:
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
Rectangle()
.frame(width: 100, height: 100)
.contextMenu {
Button("Test") {}
Button("Test") {}
}
Rectangle()
.frame(width: 100, height: 100)
.contextMenu {
Button("Test") {}
Button("Test") {}
}
}
.scaleEffect(1.5)
}
}
Screenshot (problem: The two squares are the same size. However, the long-tapped upper square got shrunk down before the context menu got displayed.)
Topic:
UI Frameworks
SubTopic:
SwiftUI
The behavior of the Button in ScrollView differs depending on how the View is displayed modally.
When the View is displayed as a .fullScreenCover, if the button is touched and scrolled without releasing the finger, the touch event is canceled and the action of the Button is not called.
On the other hand, if the View is displayed as a .sheet, the touch event is not canceled even if the view is scrolled without lifting the finger, and the action is called when the finger is released.
In order to prevent accidental interaction, I feel that the behavior of .fullScreenCover is better, as it cancels the event immediately when scrolling. Can I change the behavior of .sheet?
Demo movie is here:
https://x.com/kenmaz/status/1896498312737611891
Sample code
import SwiftUI
@main
struct SampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State private var showSheet = false
@State private var showFullScreen = false
var body: some View {
VStack(spacing: 16) {
Button("Sheet") {
showSheet.toggle()
}
Button("Full screen") {
showFullScreen.toggle()
}
}
.sheet(isPresented: $showSheet) {
SecondView()
}
.fullScreenCover(isPresented: $showFullScreen) {
SecondView()
}
.font(.title)
}
}
struct SecondView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
ScrollView {
Button("Dismiss") {
dismiss()
}
.buttonStyle(MyButtonStyle())
.padding(.top, 128)
.font(.title)
}
}
}
private struct MyButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration
.label
.foregroundStyle(.red)
.background(configuration.isPressed ? .gray : .clear)
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hello togehter,
i do have the following question.
If I have my App run in landscape mode and a sheet view get's called, will it be possible to switch automatically from landscape mode in portrait mode and fix this device orientation?
Once the sheet view get's dismissed or closed, the original view will come back and the device orientation shall switch back to landscape mode.
Thanks you so much for your help!
Description
I'm developing a tvOS application where I utilize a UISearchController embedded within a UISearchContainerViewController for search functionality. In a particular flow, a custom view controller contains a TVDigitEntryViewController as a child, with its modalPresentationStyle set to .blurOverFullScreen. The issue arises when a user initiates the PIN entry but decides to cancel and return to the search interface without entering a PIN. Upon returning, the search keyboard is no longer visible, and attempts to focus or interact with it are unsuccessful.
Steps to Reproduce
Initialize and present a UISearchContainerViewController that contains a UISearchController with a results view controller.
Within the search results, present a custom view controller containing TVDigitEntryViewController as a child, setting its modalPresentationStyle to .blurOverFullScreen.
Dismiss the custom view controller without entering a PIN (e.g., by pressing the Menu button on the remote).
Observe that upon returning to the search interface, the keyboard is missing, and focus interactions are unresponsive.
Observed Behavior
After dismissing the custom view controller with TVDigitEntryViewController, the search keyboard does not reappear, and the focus system seems to lose track of the search input field.
Expected Behavior
The search keyboard should remain visible and functional after dismissing the custom view controller, allowing users to continue their search without interruption.
Additional Context
I have reviewed the TVDigitEntryViewController documentation (developer.apple.com) and related discussions on the Apple Developer Forums but have not found a solution to this specific issue.
Questions
Has anyone encountered a similar issue or have insights into why the search keyboard becomes unresponsive after dismissing a .blurOverFullScreen modal with a child TVDigitEntryViewController?
Are there recommended practices to ensure the search keyboard remains active and focusable after such modal presentations?
Any guidance or suggestions would be greatly appreciated. Thank you!
I have a SwiftUI View I've introduced to a UIKit app, using UIHostingController. The UIView instance that contains the SwiftUI view is animated using auto layout constraints. In this code block, when a view controller's viewDidAppear method I'm creating the hosting controller and adding its view as a subview of this view controller's view, in addition to doing the Container View Controller dance.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let hostingViewController = UIHostingController(rootView: TestView())
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
addChild(hostingViewController)
view.addSubview(hostingViewController.view)
let centerXConstraint = hostingViewController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let topConstraint = hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor)
widthConstraint = hostingViewController.view.widthAnchor.constraint(equalToConstant: 361)
heightConstraint = hostingViewController.view.heightAnchor.constraint(equalToConstant: 342)
NSLayoutConstraint.activate([centerXConstraint, topConstraint, widthConstraint, heightConstraint])
hostingViewController.didMove(toParent: self)
self.hostingViewController = hostingViewController
}
I add a button to the UI which will scale the UIHostingViewController by adjusting its height and width constraints. When it's tapped, this action method runs.
@IBAction func animate(_ sender: Any) {
widthConstraint.constant = 120.3
heightConstraint.constant = 114.0
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
}
The problem is, the SwiftUI view's contents "jump" at the start of the animation to the final height, then animate into place. I see this both using UIView.animate the UIKit way, or creating a SwiftUI animation and calling `UIView.
What else do I need to add to make this animate smoothly?
I have a UITextField in my application, and I want to detect all the keys uniquely to perform all relevant task. However, there is some problem in cleanly identifying some of the keys.
I m not able to identify the backspace key press in the textField(_:shouldChangeCharactersIn:replacementString:) method.
Also I don't know how to detect the Caps Lock key.
I am intending to so this because I want to perform some custom handling for some keys. Can someone help me with what is the way of detecting it under the recommendation from apple. Thanks in advance.
Note: checking for replacementString parameter in shouldChangeCharactersIn method for empty does not help for backspace detection as it overlaps with other cases.
I have created an AppIntent and added it to shortcuts to be able to read by Siri. When I say the phrase, the Siri intent dialog appears just fine. I have added a custom SwiftUI View inside Siri dialog box with 2 buttons with intents. The callback or handling of those buttons is not working when initiated via Siri. It works fine when I initiate it in shortcuts. I tried using the UIButton without the intent action as well but it did not work. Here is the code.
static let title: LocalizedStringResource = "My Custom Intent"
static var openAppWhenRun: Bool = false
@MainActor
func perform() async throws -> some ShowsSnippetView & ProvidesDialog {
return .result(dialog: "Here are the details of your order"), content: {
OrderDetailsView()
}
}
struct OrderDetailsView {
var body: some View {
HStack {
if #available(iOS 17.0, *) {
Button(intent: ModifyOrderIntent(), label : {
Text("Modify Order")
})
Button(intent: CancelOrderIntent(), label : {
Text("Cancel Order")
})
}
}
}
}
struct ModifyOrderIntent: AppIntent {
static let title: LocalizedStringResource = "Modify Order"
static var openAppWhenRun: Bool = true
@MainActor
func perform() async throws -> some OpensIntent {
// performs the deeplinking to app to a certain page to modify the order
}
}
struct CancelOrderIntent: AppIntent {
static let title: LocalizedStringResource = "Cancel Order"
static var openAppWhenRun: Bool = true
@MainActor
func perform() async throws -> some OpensIntent {
// performs the deeplinking to app to a certain page to cancel the order
}
}
Button(action: {
if let url = URL(string: "myap://open-order") {
UIApplication.shared.open(url)
}
}
I have the MainView as the active view if the user is logged in(authenticated). the memory allocations when we run profile is pretty good. We have graphql fetching, we have token handling eg: This is All heap:
1 All Heap & Anonymous VM 13,90 MiB 65408 308557 99,10 MiB 373965 Ratio: %0.14, %0.86
After what i have checked this is pretty good for initialise and using multiple repositories eg. But when we change tabs:
1 All Heap & Anonymous VM 24,60 MiB 124651 543832 156,17 MiB 668483 Ratio: %0.07, %0.40
And that is not pretty good. So i guess we need to "kill" it or something. How? I have tried some techniques in a forum this was a recommended way:
public struct LazyView<Content: View>: View {
private let build: () -> Content
@State private var isVisible = false
public init(_ build: @escaping () -> Content) {
self.build = build
}
public var body: some View {
build()
Group {
if isVisible {
build()
} else {
Color.clear
}
}
.onAppear { isVisible = true }
.onDisappear { isVisible = false }
}
}
But this did not help at all. So under here is the one i use now. So pleace guide me for making this work.
import DIKit
import CoreKit
import PresentationKit
import DomainKit
public struct MainView: View {
@Injected((any MainViewModelProtocol).self) private var viewModel
private var selectedTabBinding: Binding<MainTab> {
Binding(
get: { viewModel.selectedTab },
set: { viewModel.selectTab($0) }
)
}
public init() {
// No additional setup needed
}
public var body: some View {
NavigationStack(path: Binding(
get: { viewModel.navigationPath },
set: { _ in }
)) {
TabView(selection: selectedTabBinding) {
LazyView {
FeedTabView()
}
.tabItem {
Label("Feed", systemImage: "house")
}
.tag(MainTab.feed)
LazyView {
ChatTabView()
}
.tabItem {
Label("Chat", systemImage: "message")
}
.tag(MainTab.chat)
LazyView {
JobsTabView()
}
.tabItem {
Label("Jobs", systemImage: "briefcase")
}
.tag(MainTab.jobs)
LazyView {
ProfileTabView()
}
.tabItem {
Label("Profile", systemImage: "person")
}
.tag(MainTab.profile)
}
.accentColor(.primary)
.navigationDestination(for: MainNavigationDestination.self) { destination in
switch destination {
case .profile(let userId):
Text("Profile for \(userId)")
case .settings:
Text("Settings")
case .jobDetails(let id):
Text("Job details for \(id)")
case .chatThread(let id):
Text("Chat thread \(id)")
}
}
}
}
}
import SwiftUI
public struct LazyView<Content: View>: View {
private let build: () -> Content
public init(_ build: @escaping () -> Content) {
self.build = build
}
public var body: some View {
build()
}
}
I've encountered an issue where storing a throws(PermissionError) closure as a property inside a SwiftUI View causes a runtime crash on iOS 17, while it works correctly on iOS 18.
Here’s an example of the affected code:
enum PermissionError: Error {
case denied
}
struct PermissionCheckedView<AllowedContent: View, DeniedContent: View>: View {
var protectedView: () throws(PermissionError) -> AllowedContent
var deniedView: (PermissionError) -> DeniedContent
init(
@ViewBuilder protectedView: @escaping () throws(PermissionError) -> AllowedContent,
@ViewBuilder deniedView: @escaping (PermissionError) -> DeniedContent
) {
self.protectedView = protectedView
self.deniedView = deniedView
}
public var body: some View {
switch Result(catching: protectedView) {
case .success(let content): content
case .failure(let error): deniedView(error)
}
}
}
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
PermissionCheckedView {
} deniedView: { _ in
}
}
}
}
Specifically this is the stack trace (sorry for the picture I didn't know how to get the txt):
If I use var protectedView: () throws -> AllowedContent without typed throws it works.
In our application we have two usecases for a Hotkey/Shortcut identification API/method.
We have some predefined shortcuts that will ship with our MacOS application. They may or may not change dynamically, based on what the user has already set as shortcuts/hotkeys, and also to avoid any important system wide shortcuts that the user may or may not have changed.
We allow the user to customize the shortcuts/hotkeys in our application, so we want to show what shortcuts the user already has in use system-wide and across their OS experience.
This gives rise to the need for an API that lets us know which shortcut/hotkeys are currently being used by the user and also the current system wide OS shortcuts in use.
Please let me know if there are any APIs in AppKit or SwiftUI we can use for the above
When pushing a page in the navigation, changing the state of interactivePopGestureRecognizer causes the page to freeze.
Just like this:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
CGFloat red = (arc4random_uniform(256) / 255.0);
CGFloat green = (arc4random_uniform(256) / 255.0);
CGFloat blue = (arc4random_uniform(256) / 255.0);
CGFloat alpha = 1.0; //
self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 100, 44);
btn.backgroundColor = [UIColor redColor];
btn.center = self.view.center;
[btn setTitle:@"push click" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)click:(id)sender {
[self.navigationController pushViewController:[ViewController new] animated:YES];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
@end
I'm testing using Group Activities and having no trouble iOS<->iOS or starting an activity on macOS and joining via iOS. However, when I start an activity and then try to join it from another macOS client, the starting side joins the session just fine, but the receiving side acts like I don't have the required app, even when it is already running.
I see the active SharePlay icon in the menu bar, and the Current Activity is shown, but instead of an "Open" button there is a "MyApp Required" string and a "View" button that goes to the App Store. (Where the app is not available yet, as expected, since I'm still working on it.) There is no GroupSession started on that Mac yet, obviously.
I'm looking for any hints to help debug what is going on. How does Group Activities find the app for the activity on macOS and how can I figure out why it isn't finding mine?
Thanks!
I must admit my knowledge of swift is limited, and I cannot wrap my head around this problem.
I've defined this protocol, so I can use different auth providers in my app.
protocol AuthRepository {
associatedtype AuthData
associatedtype AuthResponseData
associatedtype RegistrationData
associatedtype RegistrationResponseData
func login(with data: AuthData) async throws -> AuthResponseData?
func register(with data: RegistrationData) async throws -> RegistrationResponseData?
}
and an implementation for my server
struct MyServerAuthData {
let email: String
let password: String
}
struct MyServerAuthResponseData {
let token: String
}
struct MyServerRegistrationData {
let email: String
let password: String
let name: String
}
actor AuthRepositoryImpl: AuthRepository {
func login(with data: MyServerAuthData) async throws -> MyServerAuthResponseData? {
...
}
func register(with data: MyServerRegistrationData) async throws -> Void? {
...
}
}
To use across the app, I've created this ViewModel
@MainActor
final class AuthViewModel<T: AuthRepository>: ObservableObject {
private let repository: T
init(repository: T) {
self.repository = repository
}
func login(data: T.AuthData) async throws -> T.AuthResponseData? {
try await repository.login(with: data)
}
func register(with data: T.RegistrationData) async throws {
try await repository.register(with: data)
}
}
defined in the app as
@main
struct MyApp: App {
@StateObject var authViewModel = AuthViewModel(repository: AuthRepositoryImpl())
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(self.authViewModel)
}
}
}
and consumed as
@EnvironmentObject private var authViewModel: AuthViewModel<AuthRepositoryImpl>
But with this code, the whole concept of having a generic implementation for the auth repository is useless, because changing the AuthRepostory will need to search and replace AuthViewModel<AuthRepositoryImpl> across all the app.
I've experienced this directly creating a MockAuthImpl to use with #Preview, and the preview crashed because it defines AuthViewModel(repository: MockAuthImpl()) but the view expects AuthViewModel.
There is a better way to do that?