swift posts

Subscribe to just swift posts via RSS.

Live Activities (and Bad Apple)

I recently got nerd sniped by this tweet from Zhuowei Zhang about playing the Bad Apple video in the Dynamic Island on the iPhone 14 Pro. His original implementation used a webpage and the media session API, and this worked, but the system plays an animation when the artwork changes, so the framerate was limited to 2 FPS. Not ideal for watching a video. So, I wanted to see how much closer to watchable I could get.

This post isn’t going to be a detailed guide or anything, just a collection of some mildly interesting things I learned.

LiveView Native

I’m very excited for the project I’ve been working on all year to finally be public. LiveView Native is a library that lets you build native apps backed by Phoenix LiveView. I’ve been developing the iOS client which is backed by SwiftUI.

Using LiveView Native lets avoid duplicating business logic on the frontend and save time on implementing dedicated APIs for native apps. The iOS client can be integrated into any existing app by using a single SwiftUI view, so it’s easy to adopt it for just a single screen at a time.

You can find the documentation[1] for the Swift package here, including a step-by-step tutorial which walks you through building a complete app with LiveView Native.

We’ve also developed a simple chat app which was used by the attendees of ElixirConf this year, and serves as a complete example of a LiveView Native app.

I’m very excited to see what people build with it.


This is the first time I’ve used DocC and it has been largely excellent. It’s made it very easy to produce nice-looking and well-organized documentation. And the tutorial mechanism has been very useful.

Adopting TextKit 2

With iOS 16, Apple switched on TextKit 2 for UITextViews. But, if you access any of the TextKit 1 objects on the text view, it will automatically fall back to a compatibility mode. All of the work I did to mimic Safari’s link context menu animation was, of course, using the TextKit 1 APIs, so it was blocking me from fully adopting TextKit 2. So, here’s how to update that code.

Update: Swift Packages and Frameworks

A while ago I wrote about some trouble I had getting Xcode to cooperate with my efforts to bring my app file size back under control after adding a new Swift Package dependency. Well, I’m happy to say I finally have: the most recent TestFlight build of Tusker has a 6.7MB install size, down from 25MB.

Ultimately I did take the route of turning my framework into a Swift Package. I revisited it because I noticed in another project that local packages inside the same folder as the main project worked perfectly fine. The only difference I found was that the project where it worked used only an .xcodeproj, whereas Tusker used an .xcworkspace. So, I deleted the (for unrelated reasons, no longer necessary) workspace and found that, after quitting and relaunching Xcode, the local package worked perfectly fine.

I briefly started writing a feedback report, but upon further testing I found that xcworkspaces in general weren’t the problem—a new project and workspace worked fine. So, I gave up trying to reproduce it and assumed there was just something weird about the 3.5 year old workspace.

Swift Packages and Frameworks

Tusker is divided up into two main parts: the app target itself and a separate framework which encapsulates everything that deals with the Mastodon API. I recently added a Swift Package to the app for uninteresting reasons. But, because the package is used both by the framework as well as the app itself, this caused a surprising number of problems.