Skip to content

Webview caching enhancements#1066

Merged
digitaldan merged 2 commits intoopenhab:developfrom
digitaldan:webview-cache-issues
Feb 10, 2026
Merged

Webview caching enhancements#1066
digitaldan merged 2 commits intoopenhab:developfrom
digitaldan:webview-cache-issues

Conversation

@digitaldan
Copy link
Copy Markdown
Contributor

Agressively clears the cache when reloading
uses Etag headers to determine if a new version of the web app is needed when the view becomes active Adds the "reload" icon back to the Drawer menu when the webview is active

Fixes #1063

Agressively clears the cache when reloading
uses Etag headers to determine if a new version of the web app is needed when the view becomes active
Adds the "reload" icon back to the Drawer menu when the webview is active

Fixes openhab#1063

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves how the iOS app’s embedded Main UI webview refreshes and invalidates cached content, aiming to ensure the latest UI is shown after reloads/app re-activation (Fixes #1063).

Changes:

  • Add ETag-based change detection (HEAD requests + persisted ETag cache) to decide when to reload web content.
  • Make “reload app” perform a more aggressive webview cache bypass/clear during forced loads.
  • Reintroduce a reload indicator in the drawer’s “Home” item when the webview is the active view.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
openHAB/OpenHABWebViewController.swift Adds app-active reload checks, ETag-driven reload decisions, and forced cache bypass/clearing behavior.
openHAB/OpenHABRootViewController.swift Tracks whether the webview is the current view and exposes that state to SwiftUI.
openHAB/DrawerView.swift Adds CurrentViewState env object and shows a reload icon when webview is active.
OpenHABCore/Sources/OpenHABCore/Util/LoggerExtension.swift Adds dedicated logging categories for ETag cache/checker.
OpenHABCore/Sources/OpenHABCore/Util/HTTPClient.swift Extends requests to support non-GET methods (needed for HEAD).
OpenHABCore/Sources/OpenHABCore/Util/ETagChecker.swift New actor to perform HEAD requests and compare/persist ETags.
OpenHABCore/Sources/OpenHABCore/Util/ETagCache.swift New actor implementing persisted ETag storage.

Comment thread openHAB/DrawerView.swift
Comment thread OpenHABCore/Sources/OpenHABCore/Util/ETagChecker.swift
Comment thread openHAB/OpenHABWebViewController.swift
Comment thread openHAB/OpenHABWebViewController.swift
Comment thread OpenHABCore/Sources/OpenHABCore/Util/ETagChecker.swift
Comment thread OpenHABCore/Sources/OpenHABCore/Util/ETagCache.swift
Comment thread OpenHABCore/Sources/OpenHABCore/Util/ETagCache.swift Outdated
@digitaldan digitaldan force-pushed the webview-cache-issues branch from 1fb88cd to cbd388e Compare February 9, 2026 15:00
Signed-off-by: Dan Cunningham <dan@digitaldan.com>
@digitaldan digitaldan force-pushed the webview-cache-issues branch from cbd388e to 75b8490 Compare February 9, 2026 15:14
@digitaldan
Copy link
Copy Markdown
Contributor Author

Oof, i should know better then to click on the "suggested" edit button, i somehow could not update my local branch nor push new changes (b/c i couldn't update my local branch!) , hence the force pushed updates here.

@digitaldan
Copy link
Copy Markdown
Contributor Author

@timbms @TAKeanice let me know if this looks 👍 👎 to merge, thanks!

@timbms
Copy link
Copy Markdown
Contributor

timbms commented Feb 10, 2026

@digitaldan I am only using WebView marginally. I will not be able to test it myself. I delegated it to Claude: (:-)

What it does

When the app returns from background or the user navigates to the webview, instead of always reloading (slow, flicker) or never reloading
(stale content), it does a lightweight HEAD request to check if the server's ETag has changed. Only reloads if content actually changed.

Additionally, the drawer menu shows a refresh icon next to "Home" when the webview is active, and force-reload clears WKWebView's disk/memory
cache.

What's good

  • ETag-based change detection is the right approach for this problem. MainUI bundles assets with ETags, so this leverages existing server
    behavior.
  • Well-structured code — ETagCache (actor, persistent, testable), ETagChecker (actor, injectable dependencies), clean separation.
  • Comprehensive tests — 8 test cases with MockURLProtocol, covering first run, unchanged, changed, failure, normalization, weak ETags,
    case-insensitive headers.
  • HEAD request with 5s timeout — minimal overhead, won't delay the UI if the server is slow.
  • Testable init on both ETagCache and ETagChecker — in-memory cache for tests, mock HTTP client.

Concerns

  1. CurrentViewState as ObservableObject — this is a single boolean. It works, but it's a new @EnvironmentObject threaded through the view
    hierarchy just for a refresh icon. A simpler approach might be passing it as a binding or using NotificationCenter.
  2. normalizeURLForComparison with includeBasePath: false — comparing only the origin (scheme+host+port) means if the user navigates to a
    completely different path on the same server, it won't reload. The comment says "paths are handled by client-side routing" which is true for
    MainUI's SPA, but could be surprising for other webview content.
  3. applicationDidBecomeActive triggers loadWebView(force: false) — this fires every time the app becomes active (even from Control Center,
    notification shade, etc.). The ETag check keeps it cheap, but it's still a HEAD request on every activation. Consider debouncing or only
    checking after significant background time.
  4. Force reload clears all WKWebView cache — removeData(ofTypes:modifiedSince: Date(0)) nukes everything including cookies, localStorage, etc.
    You might want to limit this to just DiskCache + MemoryCache (which the code does with websiteDataTypes). Looks correct as-is.
  5. ETagCache persists on every write — storeETag calls saveETags() which encodes and writes the entire plist. For a handful of URLs this is
    fine, but if many URLs accumulate it could add up. Not a real concern for this use case.
  6. nonisolated(unsafe) on MockURLProtocol statics — the .serialized trait makes this safe, but it's worth noting this pattern doesn't scale to
    parallel test suites.

Verdict

Solid feature, well-tested, solves a real UX problem. The ETag infrastructure is reusable. The CurrentViewState feels a bit heavy for what it
does, and the didBecomeActive frequency is worth watching, but neither is a blocker. Ready for review/merge.

@digitaldan digitaldan merged commit 53c9cd0 into openhab:develop Feb 10, 2026
2 checks passed
@florian-h05
Copy link
Copy Markdown
Contributor

I think this introduced a regression where the iOS app reloads Main UI every time it goes into the foreground, and not just on app start, which is super annoying as you be back at the root of the UI.

@timbms
Copy link
Copy Markdown
Contributor

timbms commented Mar 4, 2026

I think this introduced a regression where the iOS app reloads Main UI every time it goes into the foreground, and not just on app start, which is super annoying as you be back at the root of the UI.

Could be related to this concern:

applicationDidBecomeActive triggers loadWebView(force: false) — this fires every time the app becomes active (even from Control Center,
notification shade, etc.). The ETag check keeps it cheap, but it's still a HEAD request on every activation. Consider debouncing or only
checking after significant background time.

@florian-h05
Copy link
Copy Markdown
Contributor

florian-h05 commented Mar 31, 2026

I think this thoughts is right.
@digitaldan Can you please have a look at this regression? That behaviour is super annoying because you lose your current navigation every time the app goes into background, shows control center etc.

@digitaldan
Copy link
Copy Markdown
Contributor Author

Sorry for the late follow up, did this ever get resolved? Its not happening for me, so i'm curious if someone fixed this in another PR (that i can't find)/

@florian-h05
Copy link
Copy Markdown
Contributor

florian-h05 commented Apr 13, 2026

No, this is still an issue. I'll PM you a screen capture over Slack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Version of UI Commit on reload not the latest

4 participants