Skip to content

Fix default masking of SwiftUI views in iOS 26 Liquid Glass #6390

@philprime

Description

@philprime

Description

While rewriting our masking tests in #6292 I noticed that text and image masking is pretty badly broken on iOS 26 when using SwiftUI standard components Text, Label, Image and List.

It seems these views are not backed by the same drawing layers as before, therefore our SDK does not detect the views as sensitive and doesn't apply masking to them.

Example for SwiftUI.Image using an UIImage:

let image = UIGraphicsImageRenderer(size: CGSize(width: 40, height: 40)).image { context in
    UIColor.green.setFill()
    context.fill(CGRect(x: 0, y: 0, width: 20, height: 20))
    UIColor.purple.setFill()
    context.fill(CGRect(x: 20, y: 0, width: 20, height: 20))
    UIColor.blue.setFill()
    context.fill(CGRect(x: 0, y: 20, width: 20, height: 20))
    UIColor.orange.setFill()
    context.fill(CGRect(x: 20, y: 20, width: 20, height: 20))
}

let view = VStack {
    Image(uiImage: image)
}

Before masking - iOS 18.6:
Image

After masking - iOS 18.6:
Image

Before masking - iOS 26.0:
Image

After masking - iOS 26.0:
Image

Example of SwiftUI.Text:

let view = VStack {
    VStack {
        Text("Hello SwiftUI")
            .padding(20)
    }
    .background(Color.green)
    .font(.system(size: 20)) // Use a fixed font size as defaults could change frame
}

Before masking - iOS 18.6:

Image

After masking - iOS 18.6:

Image

Before masking - iOS 26.0:

Image

After masking - iOS 26.0:

Image

Example of SwiftUI.Label (which is basically a combination of Text and Image):

let view = VStack {
    Label("Hello SwiftUI", systemImage: "house")
        .labelStyle(.titleAndIcon)
}

Before masking - iOS 18.6:

Image

After masking - iOS 18.6:

Image

Before masking - iOS 26.0:

Image

After masking - iOS 26.0:

Image

Example of SwiftUI.List:

let view = VStack {
    List {
        Section("Section 1") {
            Text("Item 1")
        }
        Section {
            Text("Item 2")
        }
    }
}

Before masking - iOS 18.6:

Image

After masking - iOS 18.6:

Image

Before masking - iOS 26.0:

Image

After masking - iOS 26.0:

Image

Steps to reproduce

Run the sample project iOS-SwiftUI at version 8.56.2 using Xcode 26 and run it on iOS 26. Then take a look at the recorded session replay:

Before masking - iOS 18.6:

Image

After masking - iOS 18.6:

Image

Before masking - iOS 26.0:

Image

After masking - iOS 26.0:

Image

Details

This is from testing with Flinky:

Ignore the unmasked top area, that's due to a geometry error.

Additonal Context

Using the debug command (lldb) po view.value(forKey: "recursiveDescription")! it is possible to investigate the underlying view hierarchy. This can also be used to see how standard UIKit components like UISlider is implemented per iOS version:

Image

Next Steps

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions