BS
BleepingSwift
Published on
3 min read

> Why Your Image Isn't Showing in a Live Activity

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

You've got a Live Activity running and everything looks great with SF Symbols. Then you swap in a custom image from your asset catalog and instead of your icon, you get a grey box. No error, no crash, just silence and a placeholder where your image should be.

This is one of those problems that's frustrating because there's nothing obviously wrong. The image exists in your asset catalog, the code compiles, and SF Symbols work fine in the same spot. The issue comes down to how ActivityKit handles image data, and there are two constraints that trip people up.

The 4KB Data Limit

ActivityKit imposes a strict size limit on the data you send with updates. From Apple's documentation:

The updated dynamic data for both ActivityKit updates and ActivityKit push notifications can't exceed 4KB in size.

This means everything in your ContentState needs to fit within 4KB when encoded. If you're trying to pass image data as part of your activity update, you'll blow through that limit quickly. Images should live in the widget extension's asset catalog, not get passed through the content state.

Here's a common pattern that works. Define your content state with only lightweight data:

import ActivityKit

struct DeliveryAttributes: ActivityAttributes {
    var orderNumber: String

    struct ContentState: Codable, Hashable {
        var status: String
        var estimatedArrival: Date
    }
}

Then reference images directly in your widget view by name, pulling them from the widget extension's asset catalog:

import SwiftUI
import WidgetKit

struct DeliveryActivityView: View {
    let context: ActivityViewContext<DeliveryAttributes>

    var body: some View {
        HStack {
            Image("delivery-icon")
                .resizable()
                .frame(width: 36, height: 36)
            VStack(alignment: .leading) {
                Text(context.state.status)
                    .font(.headline)
                Text(context.state.estimatedArrival, style: .timer)
                    .font(.caption)
            }
        }
        .padding()
    }
}

One thing to watch out for: the image needs to be in the widget extension's asset catalog, not the main app's. Widget extensions are separate targets and don't automatically inherit the main app's assets.

Image Resolution Matters

Even with the image in the right place, you can still end up with a grey box if the image is too large. The system requires that image assets for a Live Activity use a resolution smaller than or equal to the size of the presentation on the device. If the image exceeds those dimensions, the system may fail to render the Live Activity entirely.

For example, an image in the minimal Dynamic Island presentation shouldn't exceed about 45 x 36.67 points. The Lock Screen presentation gives you more room, but you still need to be mindful of the size. Check Apple's Human Interface Guidelines for exact dimensions for each presentation type.

The fix is to provide properly sized image assets in your widget extension's asset catalog. Use the 1x, 2x, and 3x slots to supply appropriately scaled versions, and keep the point size within the bounds of your layout. If you're using resizable() to scale an image down in your view, the original asset still needs to be within the system's size limits.

Quick Checklist

If your Live Activity image is showing a grey box, check these things:

  • Is the image in the widget extension's asset catalog, not the main app's?
  • Is your ContentState under the 4KB limit?
  • Is the image resolution within the size limits for the presentation type you're targeting?
  • Are you providing the correct scale variants (1x, 2x, 3x)?

Getting any one of these wrong produces the same symptom: a silent grey box with no error to guide you. Once you've got the asset in the right catalog at the right size, the image should appear without any fuss.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.