Повышение конфиденциальности пользователей имеет решающее значение при разработке приложений. В этом руководстве рассказывается о том, как создать приложение SwiftUI, которое автоматически размывает экран, когда переходит в многозадачный или фоновый режим, — полезная функция защиты конфиденциального контента.
Мы рассмотрим, как реализовать эту концепцию на шутливом примере с «секретами» разработчика, которые размываются, когда приложение не активно. Следуя этому краткому пошаговому руководству, вы узнаете, как применить эту технику защиты конфиденциальности в своих приложениях SwiftUI.
Прежде чем начать
Прежде чем начать, убедитесь, что вы обладаете базовыми знаниями о Swift и SwiftUI, особенно об управлении сценами и фазами сцен. Если вы не знакомы с этими понятиями, рекомендуем вам ознакомиться с документацией Apple по SwiftUI.
Настройка проекта
Чтобы продемонстрировать размытие экрана, мы воспользуемся простым приложением под названием My Secrets, которое скрывает конфиденциальную информацию, когда приложение переходит в фоновый режим.
В качестве отправной точки создайте список секретов, хранящихся локально, чтобы заполнить наш пользовательский интерфейс.
class SecretsStore { static var secrets: [String] = [ "I still have a soft spot for **UIKit**.", "I cringe at the sight of hamburger menus.", "In **Human Interface Guidelines**, I trust.", "I secretly enjoy writing documentation.", "I believe every bug is just a misunderstood feature", "I'm always looking for a better way to do things.", "I have a favorite Xcode theme, and it's not dark..." ] }
Затем обновите ContentView
, чтобы отобразить простой стилизованный список элементов массива секретов из SecretsStore
.
struct ContentView: View { var body: some View { List(SecretsStore.secrets, id: \.self) { secret in Text(.init(secret)) .listRowSeparator(.hidden) .fontDesign(.monospaced) } .listStyle(.inset) .navigationTitle("My Secrets") } }
Задача приложения — автоматически размывать содержимое при переходе в режим многозадачности или при бездействии. Вот как мы можем это реализовать.
Размытие представления
В ContentView
.swift приложение будет отслеживать состояние сцены с помощью @Environment(\.scenePhase)
, чтобы определить, когда оно становится неактивным или переходит в фоновый режим. В зависимости от текущего состояния сцены будет меняться значение радиуса размытия, применяемого к содержимому представления.
struct ContentView: View { // Monitoring the value of the scenePhase from the app environment @Environment(\.scenePhase) private var scenePhase // Value of the radius of the blur effect @State private var blurRadius: CGFloat = 0 var body: some View { NavigationStack { List(SecretsStore.secrets, id: \.self) { secret in Text(.init(secret)) .listRowSeparator(.hidden) .fontDesign(.monospaced) } .listStyle(.inset) .navigationTitle("My Secrets") } // Changes the blurRadius value when the scene phase changes .onChange(of: scenePhase) { oldPhase, newPhase in if newPhase == .inactive || newPhase == .background { withAnimation { blurRadius = 20} } else { withAnimation { blurRadius = 0} } } } }
Затем с помощью модификатора blur(radius:opaque:)
мы применим эффект размытия к содержимому View.
struct ContentView: View { // Monitoring the value of the scenePhase from the app environment @Environment(\.scenePhase) private var scenePhase // Value of the radius of the blur effect @State private var blurRadius: CGFloat = 0 var body: some View { NavigationStack { List(SecretsStore.secrets, id: \.self) { secret in Text(.init(secret)) .listRowSeparator(.hidden) .fontDesign(.monospaced) } .listStyle(.inset) .navigationTitle("My Secrets") // The blur modifier .blur(radius: blurRadius) } // Changes the blurRadius value when the scene phase changes .onChange(of: scenePhase) { oldPhase, newPhase in if newPhase == .inactive || newPhase == .background { withAnimation { blurRadius = 20} } else { withAnimation { blurRadius = 0} } } } }
Если пользователь переключается на другое приложение или возвращается на главный экран, конфиденциальный контент в вашем приложении становится размытым, скрывая его от глаз. Таким образом, отображаемая информация остается защищенной, когда приложение неактивно.
Когда пользователь возвращается к вашему приложению, эффект размытия плавно исчезает, делая содержимое снова видимым без резких переходов.
Расширяем функцию
Хотя в предыдущем примере речь шла об одном представлении, вы можете расширить функциональность размытия на все приложение, интегрировав аналогичную логику в делегат главной сцены вашего приложения или выше в иерархии представлений. Это гарантирует, что весь конфиденциальный контент останется защищенным при переходе приложения из одного состояния в другое.
import SwiftUI @main struct MySecretsApp: App { @Environment(\.scenePhase) private var scenePhase @State private var blurRadius: CGFloat = 0 var body: some Scene { WindowGroup { ZStack { ContentView() .blur(radius: blurRadius) if blurRadius > 0 { Image("logo") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 200) } } .onChange(of: scenePhase) { oldValue, newValue in if newValue == .inactive || newValue == .background { withAnimation { blurRadius = 20 } } else { withAnimation { blurRadius = 0 } } } } } }
Создание контейнера
Другим подходом может быть создание контейнера представлений, который будет отвечать за отслеживание текущего состояния приложения и применение эффекта размытия к его содержимому. Это может быть полезно, если вы хотите поместить изображение поверх содержимого, например логотип приложения, или если есть только определенные View, которые вы хотите размыть.
struct SensitiveContentView<Content: View>: View { @Environment(\.scenePhase) private var scenePhase @State private var blurRadius: CGFloat = 0 private var content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } var body: some View { ZStack { content .blur(radius: blurRadius) // Shows the app logo on top of the blurred content if blurRadius != 0 { Image(systemName: "swift") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 200) } } .onChange(of: scenePhase) { oldPhase, newPhase in if newPhase == .inactive || newPhase == .background { withAnimation { blurRadius = 20 } } else { withAnimation { blurRadius = 0 } } } } }
Та же логика может быть использована для создания пользовательского модификатора.