OSLog is not working when launching the app with Siri.

I am implementing AppIntent into my application as follows:

// MARK: - SceneDelegate

    var window: UIWindow?
    private var observer: NSObjectProtocol?
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        
        // Setup window
        window = UIWindow(windowScene: windowScene)
        let viewController = ViewController()
        window?.rootViewController = viewController
        window?.makeKeyAndVisible()
        
        setupUserDefaultsObserver()
        
        checkShortcutLaunch()
    }
    
    private func setupUserDefaultsObserver() {
        // use NotificationCenter to receive notifications.
        NotificationCenter.default.addObserver(
            forName: NSNotification.Name("ShortcutTriggered"),
            object: nil,
            queue: .main
        ) { notification in
            if let userInfo = notification.userInfo,
               let appName = userInfo["appName"] as? String {
                print("📱 Notification received - app is launched: \(appName)")
            }
        }
    }
    
    private func checkShortcutLaunch() {
        if let appName = UserDefaults.standard.string(forKey: "shortcutAppName") {
            print("🚀 App is opened from a Shortcut with the app name: \(appName)")
        }
    }
    
    func sceneDidDisconnect(_ scene: UIScene) {
        if let observer = observer {
            NotificationCenter.default.removeObserver(observer)
        }
    }
}

// MARK: - App Intent

struct StartAppIntent: AppIntent {
    static var title: LocalizedStringResource = "Start App"
    
    static var description = IntentDescription("Launch the application with the command")
    
    static var openAppWhenRun: Bool = true

    @MainActor
    func perform() async throws -> some IntentResult {
        UserDefaults.standard.set("appName", forKey: "shortcutAppName")
        UserDefaults.standard.set(Date(), forKey: "shortcutTimestamp")
        return .result()
    }
}

// MARK: - App Shortcuts Provider

struct AppShortcutsProvider: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: StartAppIntent(),
            phrases: [
                "let start \(.applicationName)",
            ],
            shortTitle: "Start App",
            systemImageName: "play.circle.fill"
        )
    }
}

the app works fine when starting with shortcut. but when starting with siri it seems like the log is not printed out, i tried adding a code that shows a dialog when receiving a notification from userdefault but it still shows the dialog, it seems like the problem here is when starting with siri there is a problem with printing the log.

I tried sleep 0.5s in the perform function and the log was printed out normally

try? await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds

I have consulted some topics and they said that when using Siri, Intent is running completely separately and only returns the result to Siri, never entering the Main App. But when set openAppWhenRun to true, it must enter the main app, right? Is there any way to find the cause and completely fix this problem?

An App Intent can run in the background without any UI, which means it is common for the system to launch the app without creating a scene. In your code here, you won't always see the print statements log because your app will sometimes run without a scene.

Setting openAppWhenRun is true asks the system to display the app on screen, and create a scene in the process, which is why you see the logs in that scenario instead. However, there's a discrete order to how things proceed during the launch of the app, and the creation of a scene. Your sleep approach works because it's changing the order of when things happen during this launch and scene creation process. Rather than setting and then reading a value in the user defaults, you could directly log from the intent's perform method, as well as the app delegate and scene delegate methods, to see the order of launching your app, creating the scene (when openAppWhenRun is true), and the running of your intent.

— Ed Ford,  DTS Engineer

Thank for your response, I tried to place a log in the perform method as follows:

    @MainActor
    func perform() async throws -> some IntentResult {
        for item in 0...10000 {
            os_log(.debug, "perform boot: \(item)")
        }
        return .result()
    }

Each time I initiate from Siri and fetch logs, the logs appear to be uneven. Most of the time, I can only log from 400 onwards, and after that, the logs are not printed fully. Then I tried using async await when logging:

@MainActor
    func perform() async throws -> some IntentResult {
        for item in 0...10000 {
            await printLog(item)
        }
       
        return .result()
    }

and this time the print seems to work more reliably, but it still doesn't print all the numbers within the for loop (Only able to print around 9500 to 9990 numbers).I understand that app intents run in the extension process and it does not operate reliably for handling heavy and sequential tasks, is that correct?

I wanted to wade in to the logging side of this. You wrote:

print("…")

When debugging code that might run in the background, I recommend that you use the system log rather than print(…). The print(…) routine prints to stdout, which you’ll only see if you ran your app from Xcode. OTOH, the system log lets you monitor your logging regardless of how your app was launched.

I have a lot more info about the system log in Your Friend the System Log. I also have general info about debugging code that runs in the background in Testing and Debugging Code Running in the Background. Not all of that applies to your case, but it’s a good place to start.

os_log(.debug, "perform boot: \(item)")

Is there a reason you’re not using the new Logger API? It’s much nicer.

the logs appear to be uneven

Right. The system log is a limited resource. If you log to it too quickly, you will run into problems. In your specific example, logging 10,001 log entries in a tight loop is not a pattern that the system log was designed for.

await printLog(item)

What is this printLog(_:) function? It doesn’t look like an Apple thing. Is that something you created?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank for your response, we tried changing all log statements to os_log, but the issue we are facing is that even if nothing is processed in func perform() async throws -> some IntentResult, when launching with Siri, the logs in func scene(_ scene: UIScene, willConnectTo:) and the functions before sceneDidBecomeActive(_ scene: UIScene) are not being printed fully on certain iPhones (I experience this most on iPhone SE2 running iOS 16.4). This makes it difficult for me to test using logs. Is there any way to resolve this issue?

One thing that may be happening here is that your app is launching without the debugger attached, which is where Quinn's points about the system log come in. You can use the macOS Console app to look for your logs once you're using OSLog.

Something I like to do in addition to that is configure LLDB to wait to attach until your process is launched. That way, when you use Siri to launch the app, the logs you're expecting will be picked up in the LLDB console. You can configure this in your Xcode scheme, under the Run options. With that configuration set, if you press the Run button in Xcode, the system starts LLDB, but not your app like usual when you press the Run button. You can then launch your app through Shortcuts or Siri, LLDB will now attach automatically, and record all of your OSLog statements inside of Xcode for that launch sequence.

— Ed Ford,  DTS Engineer

This logging issue seems to require more testing to better understand where the problem lies. Additionally, I have a questions:

  1. if the phrase for the app shortcut does not include the default commands of Siri to open the app, such as 'open + appname' or 'launch + appname', will the perform function still be called when using these default commands?
  2. My app is named: appname(debug), but when I call the command with Siri as 'open + appname', the app still opens, while the phrase for my app shortcut is implemented as 'open + appname(debug)'. Could it be that my app shortcut is being cached, or is Siri automatically understanding and opening my app?
OSLog is not working when launching the app with Siri.
 
 
Q