iOS 26.4 — How to return from main app to host app after a keyboard-extension dictation round-trip, without private APIs?

I'm building a custom keyboard extension that offers voice dictation. Because keyboard extensions are constrained (memory cap ~30–48 MB, restricted audio session access), I delegate recording to my container app:

  1. User in a host app (e.g., Safari) taps the mic in my keyboard extension.
  2. The keyboard calls extensionContext.open(URL("myapp://dictation")) to launch the container app.
  3. The container app records audio via AVAudioEngine + SFSpeechRecognizer, writes the final transcript to the App Group, and signals

completion via a Darwin notification. 4. The user is expected to be returned to the original host app (Safari) automatically so they can keep typing.

The problem (step 4): On iOS 26.4 I can no longer identify which app was the host. Every previously-known path returns nil for the keyboard extension's host:

  • parent.value(forKey: "_hostBundleID") → returns the literal string <null>
  • parent.value(forKey: "_hostApplicationBundleIdentifier") → returns NSNull
  • xpc_connection_copy_bundle_id on the underlying XPC connection (via PKService.defaultService.personalities[…]) → returns NULL
  • NSXPCConnection.processBundleIdentifier on extensionContext._extensionHostProxy._connection → returns nil
  • proc_pidpath(hostPID, …) → EPERM from the keyboard sandbox
  • LSApplicationWorkspace.frontmostApplication → selector unavailable from the extension
  • RBSProcessHandle.handleForIdentifier:error: → returns an RBSServiceErrorDomain error

Without the host's bundle ID, the container app has no way to call LSApplicationWorkspace.openApplicationWithBundleID: (the technique that worked on iOS 25 and earlier). UIApplication.suspend() correctly sends the container to background, but iOS treats us as a "fresh launch" — it returns the user to the Home Screen instead of Safari, because the container app was launched by an extension, not directly by Safari.

KeyboardKit's maintainer reached the same conclusion (issue #1014) and shipped 10.4 without the feature.

My questions:

  1. Is there a public, App-Store-safe API in iOS 26+ for a custom keyboard extension to identify its host application, or for the

container app (launched via the extension's openURL) to identify which app initially hosted the extension that opened it? UIOpenURLContext.options.sourceApplication reports the extension's own container, not the actual host. 2. Is there a public mechanism for "return to source app" when the container app was launched by an extension's openURL? Equivalent to the ← Source affordance iOS shows for normal inter-app openURL, but triggered programmatically by the launched app. 3. Some popular keyboards (e.g., 微信输入法 / WeChat Keyboard) still appear to round-trip through their container app on iOS 26.4 and return the user to the original host — including the iOS ← WeChat back affordance in the host's status bar afterward. What's the recommended approach to achieve this? If it requires a specific scene-activation flow, NSUserActivity pattern, or extension-context configuration, please point at the relevant docs. 4. If there is no public path today, is FB22247647 (or a related radar) the right place to track this? Should developers in this position migrate to in-extension audio capture (which has its own significant constraints in keyboard extensions)?

I'd much rather not rely on private APIs. Concrete guidance — or even an acknowledgment of which direction Apple intends — would help thousands of custom-keyboard developers who currently have a degraded voice-input experience on iOS 26.4+.

Tested on iPhone 12 Pro Max running iOS 26.4.2 (build 23E261), Xcode 26.x, Swift 5.

Thanks!

Answered by DTS Engineer in 895738022
Is there a public, App-Store-safe API … for a custom keyboard extension to identify its host application … ?

No.

or for container app … to identify which app initially hosted the extension that opened it?

No.

If there is no public path today, is FB22247647 … the right place to track this?

Yes.

That bug is stil open and has been looked at by the right folks.

I don’t have any info to share as to when, or indeed if, this will be addressed.

I will note that FB22247647 is written as “provide a way for the the extension to identify the host application”, which may be hurting its chances of getting traction. I recommend that you file a separate bug that describes the high-level goal that you’re trying to achieve, that is, perform a round trip from your keyboard, running on behalf of the host application, to the container application, and then back to the host application. I can imagine ways that we might provide that functionality without revealing the identity of the host application, which is an obvious privacy concern.


This thread, and some related threads, have contained a lot of comments about “private APIs” and I want to address that head on. There’s no such thing as a “private API”. An API, by definition, is something that Apple publishes with the intent of maintaining in the long term [1]. Everything else is an implementation detail, so:

  • If you build your app on top of implementation details, it’s likely that you’ll run into compatibility problems down the line.
  • If you take that risk, it’s important to file an enhancement request for the functionality you need. Do that at the time that you ship you app.
  • If the implementation changes in a way that breaks your shipping app, you can of course file a bug about that. However, you need have realistic expectations here. Apple needs the freedom to change our implementations in order to attain our overall platforms goals.

Finally, if anyone else is in the same boat as haoranyu, I recommend one of two things:

  • If you specifically want to identify the host application from your keyboard extension, file a bug requesting that it be marked as a duplicate of FB22247647. That’ll allow you to track the state of that request.
  • If what you really need is a way to complete the round trip, as I’ve described above, then you can either file your own ER about that or wait for haoranyu to post their bug number and then file a dup of that.

Share and Enjoy

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

[1] Sometimes we don’t achieve that goal, but that’s a different story.

There is no Answer from Apple, apps like letterly and typeless are doing it, but how?

Hi! Thanks for the detailed investigation.

I’m currently working on the exact same problem and wanted to ask: have you received any response from Apple, either through the Developer Forums or Feedback Assistant?

If you’ve learned anything new or found a supported approach, I’d really appreciate it if you could share an update. This issue affects many custom keyboard developers on iOS 26.4+.

Thanks!

Is there a public, App-Store-safe API … for a custom keyboard extension to identify its host application … ?

No.

or for container app … to identify which app initially hosted the extension that opened it?

No.

If there is no public path today, is FB22247647 … the right place to track this?

Yes.

That bug is stil open and has been looked at by the right folks.

I don’t have any info to share as to when, or indeed if, this will be addressed.

I will note that FB22247647 is written as “provide a way for the the extension to identify the host application”, which may be hurting its chances of getting traction. I recommend that you file a separate bug that describes the high-level goal that you’re trying to achieve, that is, perform a round trip from your keyboard, running on behalf of the host application, to the container application, and then back to the host application. I can imagine ways that we might provide that functionality without revealing the identity of the host application, which is an obvious privacy concern.


This thread, and some related threads, have contained a lot of comments about “private APIs” and I want to address that head on. There’s no such thing as a “private API”. An API, by definition, is something that Apple publishes with the intent of maintaining in the long term [1]. Everything else is an implementation detail, so:

  • If you build your app on top of implementation details, it’s likely that you’ll run into compatibility problems down the line.
  • If you take that risk, it’s important to file an enhancement request for the functionality you need. Do that at the time that you ship you app.
  • If the implementation changes in a way that breaks your shipping app, you can of course file a bug about that. However, you need have realistic expectations here. Apple needs the freedom to change our implementations in order to attain our overall platforms goals.

Finally, if anyone else is in the same boat as haoranyu, I recommend one of two things:

  • If you specifically want to identify the host application from your keyboard extension, file a bug requesting that it be marked as a duplicate of FB22247647. That’ll allow you to track the state of that request.
  • If what you really need is a way to complete the round trip, as I’ve described above, then you can either file your own ER about that or wait for haoranyu to post their bug number and then file a dup of that.

Share and Enjoy

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

[1] Sometimes we don’t achieve that goal, but that’s a different story.

iOS 26.4 — How to return from main app to host app after a keyboard-extension dictation round-trip, without private APIs?
 
 
Q