NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

【Swift】アプリでbackgroundを検知した時に画面をマスクする方法

概要

金融系のアプリなどでよくある実装かと思いますが、アプリでbackgroundを検知した時に画面をマスクする方法について紹介したいと思います。

作ったもの

環境

この記事は以下のバージョン環境のもと作成されたものです。
【Xcode】14.3
【iOS】16.4
【macOS】Ventuta

SwiftUIでの実装

SwiftUIではscenePhaseを使用する事でアプリのシーン状態を検知することができます。
iOS 14〜利用可能で公式ドキュメントのリンクは以下の通りです。

developer.apple.com

検知できる状態は以下の通りです。

case 状態
inactive スイッチャーが表示されている状態
active foregroundの状態
background backgroundの状態

余談ですがinactiveに関して、アプリを切り替えるシーンって何ていうのか調べていたら公式にありました。
スイッチャーって言葉に馴染みがなかったので少し驚きましたw

https://support.apple.com/ja-jp/HT202070

以下サンプルコードです。

  1. struct ContentView: View {
  2. @Environment(\.scenePhase) private var scenePhase
  3.  var body: some View {
  4. SomeView()
  5. .onChange(of: scenePhase) { newScenePhase in
  6. switch newScenePhase {
  7. case .active:
  8. print("Active")
  9. case .inactive:
  10. print("Inactive")
  11. case .background:
  12. print("Background")
  13. @unknown default:
  14. print("Unknown")
  15. }
  16. }
  17. }
  18. }
  19. }

コンソールで状態変化を確認することができます。
もう少し実践的なコードはこんな感じです。

  1. struct ContentView: View {
  2. @State private var isSecretMode = false
  3. @Environment(\.scenePhase) private var scenePhase
  4. var body: some View {
  5. ZStack {
  6. if isSecretMode {
  7. Color.white
  8. .frame(maxWidth: .infinity, maxHeight: .infinity)
  9. .clipShape(RoundedRectangle(cornerRadius: 40))
  10. .padding()
  11. .background(Color.green)
  12. VStack {
  13. Text("Secret View")
  14. .foregroundColor(.black)
  15. .font(.system(size: 40, weight: .black))
  16. .padding(.bottom, 40)
  17. Button {
  18. isSecretMode = false
  19. } label: {
  20. Text("Open")
  21. .foregroundColor(.yellow)
  22. .font(.title)
  23. .bold()
  24. }
  25. }
  26. } else {
  27. Color.white
  28. .frame(maxWidth: .infinity, maxHeight: .infinity)
  29. .clipShape(RoundedRectangle(cornerRadius: 40))
  30. .padding()
  31. .background(Color.yellow)
  32. VStack {
  33. Text("Hello!!")
  34. .foregroundColor(.black)
  35. .font(.system(size: 40, weight: .black))
  36. }
  37. }
  38. }
  39. .onChange(of: scenePhase) { newValue in
  40. print(newValue)
  41. if newValue == .background {
  42. isSecretMode = true
  43. }
  44. }
  45. .ignoresSafeArea()
  46. }
  47. }

ただこれだとスイッチャーの状態では画面が見えてしまうので、もっとセキュリティを高めたければforegroundの状態から離れた時(Inactive)の状態を検知して実装するのが良さそうです。

UIKit

UIKitではバックグラウンドを検知する方法はいくつかあります。
例えばライフサイクルを管理するためのデリゲートクラスでSceneDelegateがあり、それを利用するとbackgroundの状態やforegroundの状態を知ることができます。

developer.apple.com

またNotificationCenterを使用して検知することができます。

  1. class ViewController: UIViewController {
  2. override func viewDidLoad() {
  3. super.viewDidLoad()
  4. NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
  5. NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
  6. }
  7. @objc func didEnterBackground() {
  8. print("View Controller: アプリがバックグラウンドに入りました。")
  9. }
  10. @objc func willEnterForeground() {
  11. print("View Controller: アプリがフォアグラウンドになりました。")
  12. }
  13. deinit {
  14. NotificationCenter.default.removeObserver(self)
  15. }
  16. }

LocalAuthenticationと組み合わせてみる

生体認証とくみあわせて実装するとより実践的な動作になります。

生体認証については以下参考にしてください。

tech.nri-net.com

まとめ

以上アプリでbackgroundを検知した時に画面をマスクする方法についてでした!

執筆者岡優志

iOSエンジニア
iOSを専門とし、モバイルアプリの開発を行なっています。

Twitter