I am looking for a way to hide sensitive information on my Complication, basically whenever the user does not actively look at it. That includes
- Always-On state
- Locked State (e.g. Watch not on wrist)
I could observe differences in behavior between Preview, Simulator and Real Device. In general it looks like the .privacySensitive() modifier does not do anything for my purpose (except if the user enables redaction in settings).
For the always-on state I could use @Environment(\.isLuminanceReduced) to conditionally apply .redacted(reason: .placeholder). This works most of the time.
@ViewBuilder func preservePrivacy(_ isLuminanceReduced: Bool) -> some View {
if isLuminanceReduced {
self
.redacted(reason: .placeholder)
} else {
self
}
}
However I still cannot hide the information when the Watch is locked completely (via PIN-Code). I still believe that .privacySensitive() should take care of it, but apparently it doesn't. So the question is: How can I hide sensitive information when the Watch is locked?
This is my widget:
Text("1234")
.privacySensitive()
.preservePrivacy(isLuminanceReduced)
.widgetCurvesContent()
.widgetLabel {
Text("PIN")
.widgetAccentable()
.foregroundStyle(.secondary)
}
.containerBackground(.teal.gradient, for: .widget)
(I included the whole story, because possibly my whole approach is wrong.)
It's a user's preference whether they want privacy-sensitive information to be redacted. This is similar to the preference that allows a user to decide if iMessage notifications on their iOS Lock Screen should show the actual message.
On watchOS, a user can set their preference at Settings -> Clock -> Show Data When Locked for Lock Screen, and at Settings -> Display & Brightness -> Always On > Show Complication Data for Always On.
The settings are on by default, and I guess that is why you don't see privacySensitive() working. Please confirm if that is your case, if you don't mind.
For Always On, you can overwrite the user's preference by providing a different appearance based on the isLuminanceReduced environment variable. That explains why your code works when the device is in that state.
If you'd really like to overwrite the user's preference for Lock Screen, you can add the Data Protection entitlement to your widget extension, and set it to NSFileProtectionComplete or NSFileProtectionCompleteUnlessOpen, as documented in WidgetKit security. By doing that, your widget won't get any runtime while the device is locked. If the data is truly sensitive and shouldn't be shown when locked regardless of user preference, that's probably appropriate.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.