Skip to content

[BUG] Presenting UIWindow resets app tintColor to system blue (tab bar / AccentColor) #493

Description

@akinoavx13

Summary

Calling Superwall.configure(...) can cause the host app’s tint / AccentColor to reset to the default system blue — most noticeable on UITabBar / SwiftUI TabView selected items.

This does not appear to be caused by shouldBypassAppTransactionCheck itself (that flag only skips AppTransaction.shared). The more likely cause is Superwall creating a presenting UIWindow without copying the app window’s tintColor, then calling makeKeyAndVisible().

Environment

  • SuperwallKit 4.16.1
  • iOS (UIKit / SwiftUI app with custom AccentColor / tab bar tint)
  • Reproduced when configuring with a custom PurchaseController and options, e.g.:
let options = SuperwallOptions()
options.shouldBypassAppTransactionCheck = true
Superwall.configure(
  apiKey: apiKey,
  purchaseController: purchaseController,
  options: options
)

Expected behavior

Configuring Superwall (and presenting paywalls) should not change the host app’s window / tab bar tint color.

Actual behavior

After configure (and especially around paywall preload / presentation), the tab bar selected tint falls back to the default system blue instead of the app’s AccentColor / custom tint.

Suspected cause in the SDK

1. Presenting window created without inheriting tint

In GetPresenter.swift, Superwall creates a new UIWindow for presentation but never copies tintColor from the app’s active window:

if let windowScene = activeWindow?.windowScene {
  presentingWindow = UIWindow(windowScene: windowScene)
}

presentingWindow?.rootViewController = UIViewController()
presentationItems.window = presentingWindow

Later, during presentation (PaywallViewController.present):

Superwall.shared.presentationItems.window?.makeKeyAndVisible()

A freshly created UIWindow defaults to system blue tint. Making it key can cause the host UI (tab bar, buttons, SwiftUI .tint) to inherit / bake that default.

2. Paywall preload creates WKWebViews at launch

After config fetch, Superwall preloads paywalls by default (PaywallOptions.shouldPreload = true), which instantiates SWWebView / PaywallViewController via loadViewIfNeeded(). That can race with AccentColor / tint resolution at app launch.

Suggested fix

When creating the presenting window, copy tint from the active app window (and ideally restore key window ownership cleanly on dismiss):

if let windowScene = activeWindow?.windowScene {
  presentingWindow = UIWindow(windowScene: windowScene)
  presentingWindow?.tintColor = activeWindow?.tintColor
}

Also consider:

  • Preserving / restoring the previous key window after paywall dismissal
  • Avoiding makeKeyAndVisible() unless strictly necessary, or documenting the side effect
  • Optionally delaying preload until after the host window’s tint is established

Workarounds for host apps

  1. Re-apply tint after configure completes:
Superwall.configure(...) {
  DispatchQueue.main.async {
    UIApplication.shared.connectedScenes
      .compactMap { $0 as? UIWindowScene }
      .flatMap(\.windows)
      .forEach { $0.tintColor = UIColor(named: "AccentColor") }
  }
}
  1. In SwiftUI, set tint explicitly on the root / tab UI:
TabView { ... }
  .tint(Color("AccentColor"))
  1. Temporarily disable preload to confirm:
options.paywalls.shouldPreload = false

Notes

  • Searching the SDK, there is no direct use of UITabBar.appearance() / global UIView.appearance().tintColor during configure.
  • shouldBypassAppTransactionCheck is unrelated to tint; it only gates AppTransaction.shared in ReceiptManager.

Happy to provide a sample project or PR if helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions