I have a swift project which uses macros for conditional compilation.
How to set macro: Go to Target -> BuildSettings -> Swift Compiler - Custom Flags -> Active Compilation Conditions and add your macro (Ex: sample macro - ELDIABLO in this case).
Then the following swift code,
#if ELDIABLO
NSLog("ELDIABLO macro detected!")
#else
NSLog("ELDIABLO macro not detected!")
#endif
...produces the desired output.
ELDIABLO macro detected!
Now, how do I achieve this through cmake?
When I do the following,
set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS} ELDIABLO")
the macro gets added to Swift Compiler - Custom Flags -> Other Swift Flags (shown in the above image besides Active Compilation Conditions).
But it must be added in Swift Compiler - Custom Flags -> Active Compilation Conditions, else (here's why), it will not get detected in swift files.
How can I set swift macros in Active Compilation Conditions through cmake?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a sample app to test push notifications. The app has a Notification Service Extension to intercept remote notifications, update/enhance the content and then display it to user.
But there are some scenarios where the app shouldn't end up displaying a notification to user... Like, due to slow internet, the time taken to download media content (like images) exceeds the 30 sec time limit. There are more app specific scenarios. Basically, every push received from APNS need not be shown to user. Notification Service Extension did not have this power to suppress remote notifications. In the end, it will always display a notification to user.
From iOS 13.3 onwards, Notification Service Extension has the ability to filter out these remote notifications. The first step is (quoting form the documentation),
This entitlement allows a notification service extension to receive remote notifications without displaying the notification to the user. To apply for this entitlement, see Request Notification Service Entitlement.
When I click on the hyperlink (you need to be an account holder to view that page), Apple asks for some info like 'App Store URL', 'When extension runs, what system and network resources does it need?' and so on. I only have a sample app to help understand the aspects of notifications. I don't have any full-fledged app in AppStore... yet... and I have no clue what all my full-fledged app will be doing in the extension (since I'm just in learning stage). I only have a sample app, where I log and perform some basic string operations when my extension is invoked.
Due to this, I'm unable to see the extension filtering out notifications.
How does anyone test this feature? Has anyone tried it? Really appreciate any guidance. I'm not sure how to proceed..
According to swift documentation, the following describes the various forms of the Import declaration.
Grammar of an import declaration
import-declaration → attributes? import import-kind? import-path
import-kind → typealias | struct | class | enum | protocol | let | var | func
import-path → identifier | identifier . import-path
Questions:
Attributes and import-kind are optional. import-kind refers to the type of the import (class, struct, enum etc etc).... defined in the second line. Does attributes refers to @available which can used to add an import for a specific platform version?
In the 3rd line, I understand that identifier here refers to the names of modules, classes, funcs etc., but what does import-path mean? Can I give the actual path in disk? What all comes under this? I couldn't understand from this documentation.
I've reached out to AppleDTS for code-level support on Dec 19th 2023. It's been 3 weeks now (Jan 11, 2024). I sent a follow-up 3 days ago, but no response yet. Their response time is supposed to be within 3 business days.. experiencing this level of delay in a paid support is disappointing.
I'm not raising a new TSI but resuming an old one after almost 8 months because it is a continuation of the same problem. Delayed response from my side is a problem? I hope not (I didn't find any restrictions in the documentation).
What should I do in this situation?
I have an iOS app, which uses Notification Service Extension (NSE) for its functioning. When I build the app, I get the following error:
error: Embedded binary's bundle identifier is not prefixed with the parent app's bundle identifier.
Embedded Binary Bundle Identifier: (null)
Parent App Bundle Identifier: com.example.sample
This error occurs when NSE doesn't have the app's bundle identifier prefixed to it (Reference post).
In my case, the bundle ID of the app is com.example.sample and the bundle ID of the extension, com.example.sample.NSESample (checked these values in Project -> Target -> Signing & capabilities -> bundle identifier label). I believe this is as expected. I don't understand this error now, which says the embedded bundle identifier is null. I cleaned and built the app again..... same error.
According to this stackoverflow post, you have to enable 'Copy only when installing'. When I tried, it worked. I don't know what this setting means and how this solves the issue. I'm unable to find any documentation reg this setting. Idk if this is even a valid solution, because the error says 'Embedded Binary Bundle Identifier' is null.
Why is the embedded bundle identifier null (despite the Xcode interface showing a valid bundle ID)? How can I solve this?
In iPhone, if you open Files app and tap on an associated file type, its corresponding app is launched. I have implemented this functionality in my iOS SwiftUI app - associated a file type - .csk, with my iOS app and handled its launch using the onOpenURL(perform:) modifier.
WindowGroup {
FileContentView()
.onOpenURL(perform: { (fileUrl: URL) in
Log(String(format: "File Url = %@", fileUrl.absoluteString))
// Update UI with the content of the file
})
}
I want to achieve the same for my watchOS app. I noticed that the UTExportedTypesDeclaration key, which is used to declare the file types created and owned by the app, is not available for watchOS. But the CFBundleDocumentTypes key, which is used to associate a file type with the app is available. So, I expect my app to respond to taps on those associated file types, but I've run into a snag. There is no Files app in AppleWatch nor is there a way to view my iCloud storage. I have my .csk file (which is associated with the watchOS app) in iCloud.
So, how can I test this launch? How can an AppleWatch user tap a file and view it in his app? It should be possible to handle file launches since CFBundleDocumentTypes is available for watchOS.
I have an iOS project with the following targets:
SwiftExtensions (AppTarget) -> depends on Experience
Experience (StaticLibrary) -> depends on Lifecycle
Lifecycle (StaticLibrary)
I have defined the SceneDelegate in Lifecycle library:
public class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// scene(_:willConnectTo:options:) is implemented in Experience
// scene(_:openURLContexts:) is implemented in Experience
// Other methods such as sceneWillEnterForeground(_:), sceneDidBecomeActive(_:) etc.
}
As shown above, scene(_:willConnectTo:options:) and scene(_:openURLContexts:) are not defined here.
In the Experience library, SceneDelegate is extended:
extension SceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
NSLog("[Experience]: SceneDelegate.scene(_:willConnectTo:options:)")
if (connectionOptions.urlContexts.isEmpty) {
NSLog("[Experience]: Not launched using file!")
} else {
NSLog("[Experience]: Launched using file!")
let urlContexts: Set<UIOpenURLContext> = connectionOptions.urlContexts
for (index, urlContext) in urlContexts.enumerated() {
NSLog(String(format: "[Experience]: url[%d] = %@ ", index, urlContext.url.path()))
}
}
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
NSLog("[Experience]: SceneDelegate.scene(_:openURLContexts:)")
for (index, urlContext) in URLContexts.enumerated() {
NSLog(String(format: "[Experience]: url[%d] = %@ ", index, urlContext.url.path()))
}
}
}
Now, when I tap the app icon, scene(_:willConnectTo:options:) is not invoked. When I tap an associated file type, scene(_:willConnectTo:options:) is not invoked, again. If app is running in background, and I foreground the app by tapping an associated file type, scene(_:openURLContexts:) is not invoked.
Basically, when I define these two methods outside the target, despite with public access modifier, iOS doesn't invoke my delegate methods defined in the other library. My understanding was, Extensions can be used to break up the class. What is missing here?
This page describes the procedure to create deep links in iOS. I was able to launch an IOS Companion app (name of the app in my case) using its deep link.
But the same is not working in AppleWatch. This is my plist to register a custom scheme - Companion:
<?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>
<key>CFBundleURLTypes</key>
<array>
<dict>
<!-- <key>CFBundleTypeRole</key>
<string>Viewer</string> -->
<key>CFBundleURLName</key>
<string><some unique ID></string>
<key>CFBundleURLSchemes</key>
<array>
<string>Companion</string>
</array>
</dict>
</array>
</dict>
</plist>
I have implemented onOpenURL(perform:) to handle app launches using a deep link (url).
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL(perform: { (link: URL) in
Log(String(format: "Link = %@", link.absoluteString))
// Use then deep link
})
}
}
In iOS, I tested deep links in two ways:
Wrote the full deep link in Notes app and tapped it.
Created another app called AppLauncher with a Button saying 'Launch using Deep link'.... which when clicked opens the deep link using open(_:options:completionHandler:).
Both the approaches work in iOS, but in watchOS, I can only try 2 because Notes app is not available for AppleWatch. So, I created another watchOS app called AppLauncher, which displays a SwiftUI Button saying 'Launch using Deep link', which when tapped, tries to open the link using openSystemURL(_:). But as mentioned in the documentation (linked earlier),
Opens the specified system URL.
this API only works for links associated with System apps i.e., Apple's call and message apps.
So, how else can I use deep link to launch another app? I believe it's possible to launch an app using its deep link because the info.plist keys required to define a deep link scheme association (CFBundleURLTypes, CFBundleURLSchemes etc) is valid for watchOS too.
I have a SwiftUI project which has the following hierarchy:
IOSSceneDelegate (App target) - depends on EntryPoint and Presentation static libs.
Presentation (Static library) - Depends on EntryPoint static lib. Contains UI related logic and updates the UI after querying the data layer.
EntryPoint (Static library) - Contains the entry point, AppDelegate (for its lifecycle aspects) etc.
I've only listed the relevant targets here.
SceneDelegate was initially present in EntryPoint library, because the AppDelegate references it when a scene is created.
public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Set the SceneDelegate dynamically
let sceneConfig: UISceneConfiguration = UISceneConfiguration(name: "mainWindow", sessionRole: connectingSceneSession.role)
sceneConfig.delegateClass = SceneDelegate.self
return sceneConfig
}
The intent is to move the SceneDelegate to the Presentation library.
When moved, the EntryPoint library fails to compile because it's referencing the SceneDelegate (as shown above).
To remove this reference, I tried to set up the SceneDelegate in the old way - In the info.plist file, mention a SceneConfiguration and set the SceneDelegate in Presentation.
// In the Info.plist file
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>Presentation.SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
// In the AppDelegate
public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Refer to a static UISceneconfiguration listed in the info.plist file
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
As shown above, the Presentation.SceneDelegate is referred in the Info.plist file and the reference is removed from the AppDelegate (in EntryPoint library).
The app target compiles, but when I run it, the SceneDelegate is not invoked. None of the methods from the SceneDelegate (scene(_:willConnectTo:options:), sceneDidDisconnect(_:), sceneDidEnterBackground(_:) etc.) are invoked. I only get the AppDelegate logs.
It seems like the Configuration is ignored because it was incorrect. Any thoughts? Is it possible to move the SceneDelegate in this situation?
UserNotifications framework helps the app to handle all notification related aspects. The userNotificationCenter(_:didReceive:withCompletionHandler:) delegate method is used to handle user's action (dismiss, selected button, tap, text input etc.). As evident from the documentation, this method is available in iOS and iPadOS but not tvOS.
The @available attribute is one way to exclude methods.
@available(iOS 10.0, *)
func userNotificationCenter (_ pNotificationCenter: UNUserNotificationCenter, didReceive pResponse: UNNotificationResponse, withCompletionHandler pCompletionHandler: @escaping () -> Void) -> Void {
// Handle user's action on a notification.
...
}
When the delegate method is declared as above, I expect it to be included only for iPadOS and iOS. When building for tvOS, I get the following error:
error: 'UNNotificationResponse' is unavailable in tvOS
error: cannot override 'userNotificationCenter' which has been marked unavailable
Clearly, it is included for tvOS also.
Another approach is using
#if os(iOS)
and it does work... I don't get the above errors, meaning the code is not included for tvOS. But I want to understand how to achieve this using @available attribute because I have other situations where I need to exclude methods for certain versions of the same OS.
How do I exclude userNotificationCenter(_:didReceive:withCompletionHandler:) for tvOS using @available attribute?
I have a SwiftUI app which supports a launch from a configured universal link. I'm following this documentation.
When the app is not running and I tap a universal link, app launches. This proves the association of the website and the app.
Now, when the app is already running in the background, and then I tap a universal link, things don't work as expected. Quoting from the documentation
If your app has opted into Scenes, and your app is not running, the system delivers the universal link to the scene(:willConnectTo:options:) delegate method after launch, and to scene(:continue:) when the universal link is tapped while your app is running or suspended in memory.
I've implemented scene(_:continue:) in my SceneDelegate but it never gets invoked. I'm pasting some relevant logs
AppDelegate.application(_:willFinishLaunchingWithOptions:)
AppDelegate.application(_:didFinishLaunchingWithOptions:)
AppDelegate.application(_:configurationForConnecting:options:)
SceneDelegate.scene(_:willConnectTo:options:)
SceneDelegate.sceneWillEnterForeground(_:)
NSNotificationName(_rawValue: UIApplicationWillEnterForegroundNotification)
SceneDelegate.sceneDidBecomeActive(_:)
NSNotificationName(_rawValue: UIApplicationDidBecomeActiveNotification)
Now, I background the app...
SceneDelegate.sceneWillResignActive(_:)
NSNotificationName(_rawValue: UIApplicationWillResignActiveNotification)
SceneDelegate.sceneDidEnterBackground(_:)
NSNotificationName(_rawValue: UIApplicationDidEnterBackgroundNotification)
App runs in the background... Now, I tap a Universal link
SceneDelegate.sceneWillEnterForeground(_:)
NSNotificationName(_rawValue: UIApplicationWillEnterForegroundNotification)
SceneDelegate.sceneDidBecomeActive(_:)
NSNotificationName(_rawValue: UIApplicationDidBecomeActiveNotification)
As shown in the logs above, there is no trace of scene(_:continue:).
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
Log("SceneDelegate.scene(_:continue:)")
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let universalLink = userActivity.webpageURL else {
Log("Not launched via universal links!")
return
}
Log(String(format: "userActivities = %@", String(describing: userActivity)))
Log(String(format: "universalLink = %@", universalLink.absoluteString))
StaticContext.dataFromMainApp = universalLink.absoluteString
StaticContext.viewController.updateLabelWithLink()
}
What am I missing here?
I have a watchOS app written in C++, Swift and SwiftUI. This app is meant only for 64-bit architecture. I know Apple uses the arm architecture, so I thought arm64 will be the arch of latest AppleWatches.
I tested my code in x64 simulator (Intel Mac) and arm64 simulator (silicon Mac) - no trouble. Next is to test on a device - AppleWatch Series 9, model: A2984. I set the arch to arm64 and my application failed to build, with Xcode showing a popup about arch mismatch... which is due to the app's arch begin different from device's arch. When I change Xcode arch setting to arm64_32, then I don't get this popup, but my builds fail. When I read about arm64_32, I realised that this is a version of arm64 with 32 bit pointers... not the arm64 with 64 bit pointers.
Looking at the specification of AppleWatch Series 9, Apple has confirmed that it has 64 bit CPU, but the instruction set is unknown. This wiki page about different AppleWatch CPUs is marked TBC for AppleWatch Series 9. From Xcode, I got to know that this unconfirmed arch is arm64_32. This completely breaks my code. Are there any 64-bit watches with 64-bit pointer sizes? What is Apple's future in this area? Do they plan to release AppleWatches that support 64-bit pointers or it's always going to be 32?
I'm looking to develop a very rich networking macOS app (like social media apps) operated by very large number of users, each user is able to create a number of windows, operate/view each of them, able to customize the app to his liking etc. The UI is expected to be very rich and dynamic.
The question is, should I choose AppKit or SwiftUI?
I have a basic understanding of SwiftUI, its declarative way of defining UI layouts and populating it with data. Not sure if SwiftUI can handle a very rich and dynamic UI customised by large number of users.
Any thoughts? What works best in this scenario? What is Apple's recommendation?
In an iPadOS SwiftUI app supporting multiple scenes, each Scene responds to a particular way in which the app was launched. If app was launched by tapping an associated file or a deep link (custom URL), then, the URLHandlerScene is invoked. If app was launched by QuickAction (long tap on the app icon), then another Scene is invoked etc. Each Scene has a purpose and responds to a particular launch.
But after defining handlesExternlEvents(matching:) scene modifier, the scene was not getting launched when user taps the associated file or the app's Deeplinks was invoked.
@main
struct IOSSwiftUIScenesApp: App {
var body: some Scene {
DefaultScene()
URLHandlerScene()
.handlesExternalEvents(matching: ["file://"]) // Launched by an associated file
.handlesExternalEvents(matching: ["Companion://"]) // Launched by Deeplink.
// Other scenes
}
}
struct URLHandlerScene: Scene {
@State private var inputURL: URL // Store the incoming URL
init() {
self.inputURL = URL(string: "Temp://")!
}
var body: some Scene {
WindowGroup {
URLhandlerView(inputURL: $inputURL)
.onOpenURL(perform: { (fileURL: URL) in
log(String(format: "URLhandlerView().onOpenURL | Thread.current = %@", String(describing: Thread.current)))
log("fileURL = " + String(describing: fileURL))
inputURL = fileURL
})
}
}
}
As shown above, I've attached handlesExternalEvents(matching:) modifier with "file://" for the associate file and "Companion" is my custom URL scheme. As per the scene matching rules documented here, my URLHandlerScene should get launched, but every time I launch the app using associated file or 'open' a Deeplink, the DefaultScene is always launched.
What is missing here? Can someone please help?
An app has some periodic light background work, which is expected to run even when app is suspended.
Ofc, if user has swiped up, nothing can be done. When swiped from app switcher, if app was in Suspended state, its not informed else, in every other state (including background), applicationWillTerminate(_:) is invoked
When application is not killed by user and is in suspended state, I want to run some small tasks at certain intervals.
According to this documentation, Background fetch is the way to go. This post by Apple DTS also suggests the same i.e., Background Fetch (BGAppRefreshTask) for periodic background execution.
Example:
The sample background task is to count 10s in multiple of 10s.
Launch handler is registered with the background task ID configured in info.plist file in application(_:didFinishLauchingWithOptions:).
I have the following code invoked from in applicationDidEnterBackground(_:),
func initiateBackgroundTask(id: String) {
let currentDate: Date = Date.now
guard let futureDate: Date = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate) else {
NSLog(AppDelegate.TAG + "Error in obtaining future date!")
return
}
let taskRequest: BGAppRefreshTaskRequest = BGAppRefreshTaskRequest(identifier: id)
// Schedule background task
taskRequest.earliestBeginDate = futureDate
do {
// Note: Background processing doesn't work in Simulator.
// Submitting in Simulator leads to BGTaskScheduler.Error.Code.unavailable error.
try BGTaskScheduler.shared.submit(taskRequest)
NSLog(AppDelegate.TAG + "Task submitted successfully!")
} catch {
NSLog(AppDelegate.TAG + "error = " + String(describing: error))
return
}
NSLog(AppDelegate.TAG + "Background task scheduled successfully!!")
NSLog(AppDelegate.TAG + "Scheduled date = %@ | Present date = %@", String(describing: taskRequest.earliestBeginDate), String(describing: Date.now))
}
The following method is invoked from launch handler:
func taskRefreshCount1Min(task: BGAppRefreshTask) {
// Set expiration handler
task.expirationHandler = {
NSLog(AppDelegate.TAG + "Background execution time about to expire!")
NSLog(AppDelegate.TAG + "Remaining time = %fsec | %@", AppDelegate.app.backgroundTimeRemaining, String(describing: Date.now))
NSLog(AppDelegate.TAG + "Unable to complete task!!")
task.setTaskCompleted(success: false)
}
for i in 1...6 {
let presentDate: Date = Date.now
NSLog(AppDelegate.TAG + "%d) %@", i, String(describing: presentDate))
Thread.sleep(forTimeInterval: 10)
}
NSLog(AppDelegate.TAG + "Task complete!")
task.setTaskCompleted(success: true)
}
My expectation is that iOS will execute the launch handler 1 min after scheduling the background task. But that never happens, even after hours.
Task did get executed within 20 mins (Sample output shown below), but every other time, I waited for more than an hour and task was never executed.
// Output
...
Task submitted successfully!
Background task scheduled successfully!!
Scheduled date = Optional(2023-02-06 09:19:46 +0000) | Present date = 2023-02-06 09:18:46 +0000
TaskRefreshCount1Min(task:)
1) 2023-02-06 09:35:12 +0000
2) 2023-02-06 09:35:22 +0000
3) 2023-02-06 09:35:32 +0000
The documentation does state,
However, the system doesn’t guarantee launching the task at the specified date, but only that it won’t begin sooner.
But I didn't expect the results to differ by such a huge margin.
Apparently others have also faced this 'inconsistent scheduling' in iOS.
Background fetch with BGTaskScheduler works perfectly with debug simulations but never works in practice
How make iOS app running on background Every one minute in Swift?
In links I have pasted above, despite Background Fetch being the most suitable for periodic light tasks, Silent Push Notifications were suggested. I'm currently checking out Silent Push Notifications, but iOS recommends a frequency of not more than 3 per hour.
Summarising my questions from this exercise:
Is there something wrong with the code?
What technique should I use? Background fetch, silent notifications or anything else?
In Background Fetch, how do you schedule background tasks periodically? There's an instance property called earliestBeginDate to denote the minimum time after which the task can happen.