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

Impacts of contract tests in our microservice architecture

Impacts of contract tests in our microservice architecture

ivan_delloro
ivan delloro

We learned how to implement contract test for any kind of messages exchanged in a microservices' architecture, now let's see the impacts and why it sped up our development process [...]

Use SwiftUI Path and Shape to render your svg files: a practical example

Use SwiftUI Path and Shape to render your svg files: a practical example

fabrizio_duroni
fabrizio duroni
marco_de_lucchi
marco de lucchi

Let's have some fun with SwiftUI by drawing an inspiration title component leveraging Path and Shape. [...]