lastminute.com logo

Technology

Widget iOS: how to fix the image bundling problem

fabrizio_duroni
fabrizio duroni
marco_de_lucchi
marco de lucchi

Discover how we had a long day debugging WidgetKit problems with images.


In the previous post, we presented our FriYaY project: an inspirational iOS widget. We were so excited to have our first widget in production that we forced asked all our colleagues to give it a try.
Unfortunately, for some people, the widget was loading in a broken state: as you can see from the image below, the assets were not loading.

Widget not loading
Widget not loading

We were heartbroken. We tested the widget carefully before going to production, on multiple iPhones and iPads with different iOS and iPadOS versions, even with the iOS 16 Developer Beta build, and we never had this behaviour.
Soon we found ourselves deep into the code, trying to catch the bug. There was not a single line in the Xcode log that was pointing us to the right solution.

We tried to:

  • debug the REST services, to understand if there was a bug in the API
  • debug the Network Client code, to understand if there were some errors in the deserialization of the JSON or in the image download
  • debug the UI, to understand if we were making mistakes with the Image display code.

During the investigation we noticed that both the images bundled inside the extension (e.g. the one shown in the widget picker before installing it) and the ones downloaded from the API were not working. We were able to replicate the issue only on iPhone 11 (A13 Bionic Chip) and older.

We finally checked the general system log using the Console.app, to better understand what was happening at system level. To avoid having noise in the logs, we created and empty app project with attached our widget extension. While running the test app on an iPhone 11, we finally found the problem.

Debugging the code with Console.app
Debugging the code with Console.app

As you can see from the screenshot, the widget was failing to archive because the image used as background (what we called inspiration image in the previous posts) was too big. This was causing a memory leak (see CGImageCopyResourceImageSource logs) that prevented the code from opening the images causing the “broken widget” state reported above.
After some searches we found this thread on the Apple Developer Forum, where they were suggesting to reduce images’ size using some UIImage extension code.

So how did we solve the problem? We simply sized our images in the right way emoji-laughing.
Using the WidgetKit Human Interface Guidelines from Apple, we gave to the images the size based on the width of the widgets on the various iPhones. If you can’t approach the problem in this way, you can still use the extension code for UIImage mentioned in the Apple Developer Forum above.

extension UIImage {
  func resized(toWidth width: CGFloat, isOpaque: Bool = true) -> UIImage? {
    let canvas = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
    let format = imageRendererFormat
    format.opaque = isOpaque
    return UIGraphicsImageRenderer(size: canvas, format: format).image {
      _ in draw(in: CGRect(origin: .zero, size: canvas))
    }
  }
}

Conclusion

The journey into WidgetKit is not finished yet, if you want to know more about it check the links below:


Read next

SwiftUI and the Text concatenations super powers

SwiftUI and the Text concatenations super powers

fabrizio_duroni
fabrizio duroni
marco_de_lucchi
marco de lucchi

Do you need a way to compose beautiful text with images and custom font like you are used with Attributed String. The Text component has everything we need to create some sort of 'attributed text' directly in SwiftUI. Let's go!!! [...]

A Monorepo Experiment: reuniting a JVM-based codebase

A Monorepo Experiment: reuniting a JVM-based codebase

luigi_noto
luigi noto

Continuing the Monorepo exploration series, we’ll see in action a real-life example of a monorepo for JVM-based languages, implemented with Maven, that runs in continuous integration. The experiment of reuniting a codebase of ~700K lines of code from many projects and shared libraries, into a single repository. [...]