Insidious Bugs

šŸž Insidious Bugs #1: Today Extensions

This app could not be installed at thisĀ time.

Today Lickability is relaunching Insidious Bugs on our blog. Insidious Bugs is an occasional series in which we share stories of overcoming obscure issues in iOS development with the goal of saving you the time we lost, should you encounter the issues yourself.

The Bug

In this first entry, we conquer an instance of Xcodeā€™s friendly ā€œThis app could not be installed at this timeā€ message. We encountered this when attempting to run our project that includes a Today Extension, or widget, in the iOS Simulator.

A screenshot of Xcode displaying an error saying, "This app could not be installed at this time." Uhhhhhhhā€¦ okay?

The Solution

Wait, what?

Would you believe that all it took to solve this issue was this seemingly useless file? Well, that and many, many hours of failed attempts.

How We GotĀ Here

ā€œThis app could not be installed at this timeā€ doesnā€™t give us a lot to work with, but letā€™s explore the somewhat unique setup that got us here.

We recently added Today Extensions to multiple projects, which all share the same layout. We tend to keep things DRY (donā€™t repeat yourself), so we made our approach generic and reusable across multiple projects via a shared framework. In our framework, the Today Extension displays an arbitrary number of cells that have a thumbnail image and two labels. The framework doesnā€™t care what type of content is to be displayed, whether itā€™s social media posts, news, reminders, etc.ā€”it simply formats and displays the data written to the shared container by the host app in the exact same way. Hereā€™s an example:

A screenshot of an app displaying tweets from Lickability team members in a widget. Youā€™d buy this app,Ā right?

Hooray! This will save us time and tedious boilerplate as we add our Today Extensions to our projects. We simply need to add the framework and associate the view controller in MainInterface.storyboard (part of the Today Extensionā€™s target) with the one found in the framework. At least thatā€™s what we thought. Everything compiled just fine, but we couldnā€™t debug our app. ā€œThis app could not be installed at this time.ā€ šŸ¤” Since Xcodeā€™s message didnā€™t point us in any particular direction on how to resolve the bug, we searched log files for anything that was amiss. Every time weā€™d attempt to build and run, a message similar to the following was printed to mobile\_installation.log.0 within the simulatorā€™s logs folder:

<err> (0x700008983000) -[MIExecutableBundle makeExecutableWithError:]: 1162: Failed to chmod /Users/Michael/Library/Developer/CoreSimulator/Devices/51417E58-232D-45D5-9DAB-EB4C6F0AA301/data/Library/Caches/com.apple.containermanagerd/Bundle/Application/0D7DF887-D2D6-45F7-86DB-AACE8F2AE875/LickabilityTweets.app/PlugIns/TodayExtension.appex/TodayExtension : No such file or directory (NSPOSIXErrorDomain:2 (null))

This error was more descriptive, but still didnā€™t lead us to a solution. ā€œWhy wouldnā€™t the app extension exist on disk after a build succeeded?ā€ we asked, before making dozens of trial and error attempts across several hours to no avail.

Eventually, we found that moving the view controller back to the Today Extension target would resolve the issue, but we werenā€™t satisfied with duplicating that file across multiple projects. In a stroke of genius (read: luck) we asked each other, ā€œWaitā€¦ is it the fact that the view controller needs to be a part of the extension target, or is it just that we linked something to the target that made the difference?ā€ After all, our ā€œCompile Sourcesā€ build phase required nothing, since by design, any executable code used by the widget would live in our shared framework.

A screenshot of the Compile Sources Build Phase in Xcode. What a lonely targetĀ šŸ˜¢

So we just added something to our target to see if it made any difference. A single Swift file without any code.

Build Succeeded! Installing! Success! It workedā€¦ that was it?!

The widget, unable to load content. šŸ˜ šŸ˜”šŸ˜­

We thought we had it. But at least we could build and run now. On launch of the Today Extension target, Xcodeā€™s console would display the following:

Unknown class \_TtC19SharedExtensionCode19TodayViewController in Interface Builder file.

It seemed as though despite the fact that we were selecting the appropriate view controller class from the appropriate framework within MainInterface.storyboard, our class was still nowhere to be found at run time. After much more trial and error, we added a bit more code to FixEmptyTarget.swift. We wanted to make sure everything was properly linked. We imported our shared framework into the file to see if it built (it did) and wrote some test code to see if we could actually make reference to the view controller class (we could). šŸ§ ā€œHow come we can reference this view controller from a different framework in code, but not in a storyboard?ā€ we pondered. We tried running this, just to see if anything more helpful would print to the console with our reference to the disappearing view controller in code, andā€¦

The widget, working again. Whaaaaaaaaaaaaaaaaaaaaat šŸ¤Æ

Michael: Thatā€¦ did it?
Andrew: Itā€™s time to relaunch Insidious Bugs.

Simply referencing our view controller in code and adding an otherwise useless file to our target solved this mysterious series of problems, and now we finally have our Today Extension framework. The full, documented version of FixEmptyTarget.swift looks like the following:

Bananas, right? We sincerely hope you donā€™t encounter an issue like this in your travels. And if you do, we hope this post helped you get back up and running quickly!

Radars

Here are the bugs weā€™ve filed for Apple about these issues: