🫧

iOS 26 の Liquid Glass 効果をランタイムで動的に切り替えるテクニック

に公開

iOS 26 で導入された Liquid Glass エフェクトは、システム全体のウィンドウ背景に半透明かつ物理ベースのブラーを自動適用する新しいビジュアルレイヤーです。既存 UI との整合性やパフォーマンス面で問題がある場合や開発リソースの問題から、無効化して一時しのぎしたいケースがあります。

動的な切り替えの必要性

我々のアプリでは、開発者のみがアクセスできるデバッグメニューに Liquid Glass の有効・無効を切り替えるトグルを設けることで、顧客向けには Info.plist の設定による互換モードでのリリースを維持しつつ、開発中は Liquid Glass の挙動を手軽に確認できるようにしています。

従来の Info.plist による設定

公式には、Info.plist にキー UIDesignRequiresCompatibility を追加し、互換モードを指定することで Liquid Glass の適用を制御します。これによりアプリ全体で効果を無効にすることが可能です。

<key>UIDesignRequiresCompatibility</key>
<true/>

動的に切り替えたい場合

Info.plist で互換モードを指定すると、開発中に Liquid Glass の挙動を確認できなくなります。iOS 26 対応を進めながらリリースでは互換モードを維持したい場合、Method Swizzling を使ったテクニックがあります。

import Foundation

extension Bundle {
  static func swizzleInfoDictionary() {
    guard #available(iOS 26.0, *) else { return }

    let originalSelector = #selector(getter: infoDictionary)
    let swizzledSelector = #selector(getter: swizzledInfoDictionary)

    guard let original = class_getInstanceMethod(Self.self, originalSelector),
          let swizzled = class_getInstanceMethod(Self.self, swizzledSelector) else { return }

    method_exchangeImplementations(original, swizzled)
  }

  @objc private var swizzledInfoDictionary: NSDictionary? {
    let dict = NSMutableDictionary(
      dictionary: self.swizzledInfoDictionary ?? [:]
    )

    // Liquid Glass をオフにする場合 (true)
    // dict["UIDesignRequiresCompatibility"] = true

    // Liquid Glass をオンにする場合 (false)
    // dict["UIDesignRequiresCompatibility"] = false

    // オン・オフを UserDefaults で管理する場合
    dict["UIDesignRequiresCompatibility"]
      = !UserDefaults.standard.bool(forKey: "isLiquidGlassEnabled")

    return dict
  }
}

これは何をしているかというと、Bundle クラスの infoDictionary プロパティのゲッターを差し替え、呼び出されるたびにクロージャで dictionary を修正できるようにしています。これにより、アプリ起動後に Info.plist の内容を動的に変更することができるわけです。

SwiftUI アプリでの呼び出し例

起動後にシステムが値を読み取る前に差し替える必要があるため、アプリ起動時のなるべく早い段階で swizzleInfoDictionary() を呼び出してください。

アプリが完全に起動したあとに値を変更した場合などは、リアルタイムで UI に反映されるわけではないため、アプリの再起動が必要です。

import SwiftUI

@main
struct MyApp: App {
  init() {
    // DEBUG ビルドまたは開発者向けにのみ有効化してください。
    // 本番環境では使用しないことを強く推奨します。
    #if DEBUG || DANGEROUSLY_ENABLE_SWIZZLING
      Bundle.swizzleInfoDictionary()
    #endif
  }
  /* ... */
}

まとめ

Liquid Glass の無効化は Info.plist での設定が推奨されますが、動的な切り替えが必要な場合は Method Swizzling の使用も検討してみると良いでしょう。
なお、Method Swizzling は使い方によっては予期せぬ副作用を引き起こす可能性があるため、十分にテストを行い、必要最小限の範囲で使用することをお勧めします。

Discussion