How To Debug iOS Appex

While Debug, Profile, and Test Your App Extension explains how to debug an iOS application extension (an “appex”) using a host app, sometimes it much more convenient to not to rely on particular app. A good example of this is an appex built on top of Network Extension framework, such as custom tunnel provider — iOS launches this type of extension when user turns on VPN from the Settings app ⚙️.

Terminology

  • Containing app — an application that ships application extension within its bundle and allows to tune up it [appex].
  • Host app — any other app installed on a device, that benefits from using 3rd party appexes.
  • Appex — application extension (or simply, “extension”) shipped together with containing app, but launched by a host app.

Build & Run

First of all, an appex is a binary, so any changes made to code have to be compiled, and resulting binary has to be copied to a device. So, each time you have made changes to a containing app and/or its appex, hit “Build & Run” for containing app scheme. Wait till the app is installed and launched. At this point, you can be sure that updated appex binary is installed.

Know you process name

Launch your appex using whatever approach is suitable for the appex type, you develop. For example, Custom Tunnel Provider extensions can be launched directly from the containing app or from VPN Settings panel in the Settings app. On the other hand, Custom Keyboard extensions, have to be first installed into the system and granted some permissions, then user can launch the keyboard from almost any app with typing functionality.

Before launching the extension, go to Xcode menu Debug -> Attach to Process. Wait till the list is loaded and find the process name under Likely Targets. You will need it shortly.

Stop

By now, stop the containing app, the appex and the host app (if any).

Add a breakpoint

It is important to add a breakpoint somewhere into application extension’s principal class. Because, entry points (methods, being called first, when the appex process is launched) differ between application extension types, consult the documentation to figure out where to break during debugging.

Attach to a process

In Xcode go to Debug -> Attach to Process by PID or Name… and make sure the process name corresponds to the one you captured earlier. Hit Attach. Then, wait until Xcode is waiting to attach — press command+7 to find out the status.

Launch the appex

Do whatever is preferable for you to launch the extension. In other words, use it somehow. Xcode will conveniently attach to your appex process, whenever it detects iOS has launched it. It also will break the execution at the first breakpoint it hits.

⚠️ NOTE: At the time of writing, latest Xcode 9.4.1’s lldb often is unable to spot the process and attach to it. Hence, starting from scratch is needed.

Logs

Debugging is never amazing enough without logging you carefully put throughout your code during development. Unfortunately, using approach explained above, lldb does not forward output to Xcode. You have two options here:

  1. Use Windows -> Devices and Simulators menu and see loggins from that window.

2. Use Apple Configurator 2 and find logs under Console side menu.

3. [preferable] Use Console.app to look for logs.

First two approaches, unfortunately, leave you to deal with “logging diarrhea”: you should sort through tons of logs to find the one logged by your appex. While, some established format for logging statements is a great help, Console.app allows to filter the device’s output, and hence, simplifies the analysis.

Console.app side note: Some application extensions are ran along with system demons. These processes might also log some useful information. However, knowing the name of those processes could be tricky.


UPDATE Aug, 20, 2018: Note about failures to attach to a process is added. “Logs” section is updated with Console.app usage.