Add offline page caching, fix Google login, reduce UI latency#4
Add offline page caching, fix Google login, reduce UI latency#4
Conversation
1. Page caching: Added enableOfflineCache config option and toggle in HomeScreen UI. Template WebView uses LOAD_NO_CACHE when online (fresh content) and LOAD_CACHE_ELSE_NETWORK when offline. 2. Google login: Remove "wv" token from WebView user agent string to prevent Google from blocking sign-in as embedded browser. 3. Performance: Remove expensive blur effect from TopAppBar, reduce animation durations (300ms→150ms for state transitions, 200ms→150ms for navigation), add hardwareAccelerated flag to template manifest. Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
…fline use Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
|
@copilot Making good progress, nice. Google sign-in works. But there are some more issues:
|
Performance: Remove expensive window reconfiguration calls (decorView.setBackgroundColor, repeated enableEdgeToEdge) from updateStatusBarAppearance that blocked frame rendering and delayed predictive-back gesture animations. Only lightweight system bars appearance flag updates remain. Offline caching: Register ConnectivityManager.NetworkCallback to dynamically switch WebView cache modes when network state changes (LOAD_DEFAULT online, LOAD_CACHE_ELSE_NETWORK offline) instead of checking once at startup. This fixes caching not working when network drops mid-session. Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
Since minSdk=26 > API 24, registerDefaultNetworkCallback is always available. This avoids spurious callbacks from secondary networks that could incorrectly switch to offline mode. Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
Fixed both issues in d03ed81: 1. Animation FPS / predictive-back delay: The root cause was 2. Offline caching: The previous implementation checked network state once at startup and set the cache mode statically. If the network dropped mid-session, the WebView was still using |
|
Predictive-back: Restore window background via setBackgroundDrawable() (lightweight alternative to decorView.setBackgroundColor()) so the predictive-back gesture reveal matches the current dark/light theme. Use proper Material 3 animation durations (300ms with FastOutSlowIn easing) for smoother navigation transitions. Offline caching: Use saveWebArchive() to save full page snapshot as MHTML after each page load when online. When reopening offline, load from the saved archive file which contains all CSS, images, and embedded resources regardless of server cache headers. Keep HTTP cache fallback via LOAD_CACHE_ELSE_NETWORK as secondary strategy. Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
Fixed both issues in 0e5b3c7: 1. Predictive-back dark theme: The previous commit stripped 2. Offline caching: The HTTP cache approach ( |
|
@copilot Alright great, now caching works!... Sorta though. Please make it so inside of Appy, it is clarified that caching is an experimental feature, and in the README.md in the repository please add to the known issues that caching can be a bit glitchy on some more advanced websites. Just do this and then I'll merge the pull request into the main branch. |
- Add 'Experimental' badge next to the Offline Cache toggle label - Update description to note it may not work on all websites - Add known issue to README about caching on advanced websites Co-authored-by: dynodevv <85120286+dynodevv@users.noreply.github.com>
Done in 432b5c2. Added an "Experimental" badge next to the Offline Cache toggle in the UI and updated the description text to say "May not work on all websites." Also added a known issue entry to README.md. |
There was a problem hiding this comment.
Pull request overview
This PR extends the generated WebView template and the Appy UI to support an experimental offline-page snapshot feature, improve Google OAuth compatibility in WebView, and reduce perceived UI latency in the Compose app.
Changes:
- Adds an
enableOfflineCachetoggle to the app UI/config pipeline and implements MHTML snapshot save/load in the template WebView. - Adjusts WebView user-agent to avoid Google OAuth blocking in embedded WebViews.
- Tweaks UI performance/animations (removes blur TopAppBar effect, updates transitions) and optimizes predictive-back theming behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| template/src/main/java/com/webtemplate/MainActivity.java | Implements offline archive save/load, dynamic cache-mode switching, and user-agent adjustment for Google login. |
| template/src/main/AndroidManifest.xml | Enables hardware acceleration at the application level. |
| app/src/main/java/com/appy/ui/screens/HomeScreen.kt | Adds offline-cache toggle to the APK config form and removes TopAppBar blur; updates animation timings. |
| app/src/main/java/com/appy/processor/ApkProcessor.kt | Plumbs enableOfflineCache into injected config.json. |
| app/src/main/java/com/appy/MainActivity.kt | Updates transitions and refactors status bar/predictive-back theming to reduce window reconfiguration work. |
| README.md | Documents offline caching as experimental in known issues. |
Comments suppressed due to low confidence (1)
app/src/main/java/com/appy/MainActivity.kt:249
- For API levels < 30 (R),
updateStatusBarAppearance()only togglesSYSTEM_UI_FLAG_LIGHT_STATUS_BAR. SinceminSdk=26, this leaves navigation bar icon appearance unmanaged on Android 8–10, which can lead to low-contrast nav bar icons in light theme. Consider also setting/clearingView.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR(API 26+) in this branch.
} else {
if (isDarkTheme) {
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
} else {
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
| // Offline: try loading saved web archive first | ||
| File archive = getArchiveFile(); | ||
| if (archive.exists()) { | ||
| webView.loadUrl("file://" + archive.getAbsolutePath()); |
There was a problem hiding this comment.
webView.loadUrl("file://" + archive.getAbsolutePath()) produces a non-canonical file URL (absolute paths start with '/', so the final URL becomes file:////...). This can break loading the saved MHTML on some WebView/URI parsers. Build the file URL via Uri.fromFile(archive).toString() (or otherwise ensure file:///...).
| webView.loadUrl("file://" + archive.getAbsolutePath()); | |
| webView.loadUrl(Uri.fromFile(archive).toString()); |
| return caps != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) | ||
| || caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) | ||
| || caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)); |
There was a problem hiding this comment.
isNetworkAvailable() returns true only for WIFI/CELLULAR/ETHERNET transports. If the active network is VPN (common) or another transport, this will incorrectly report “offline”, causing the app to load the archive and switch cache modes even though Internet is available. Consider checking NET_CAPABILITY_INTERNET (and optionally NET_CAPABILITY_VALIDATED) instead of hard-coding transports.
| return caps != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) | |
| || caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) | |
| || caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)); | |
| if (caps == null) return false; | |
| boolean hasInternetCapability = caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); | |
| boolean isValidated = caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); | |
| return hasInternetCapability && isValidated; |
Three template/app improvements: toggleable offline caching for generated APKs, Google sign-in unblocked in WebView, and UI performance fixes for perceived latency.
Offline page caching (template app)
enableOfflineCachetoggle in APK config form, plumbed throughApkConfig→ApkProcessor→config.json→ templateMainActivity.javaWebView.saveWebArchive()to save the full rendered page as an MHTML snapshot after each page load — captures CSS, images, and embedded resources regardless of serverCache-Controlheaders.mhtarchive file instead of the URLConnectivityManager.NetworkCallbackviaregisterDefaultNetworkCallback()switches cache modes in real time as a secondary fallback (LOAD_DEFAULTonline,LOAD_CACHE_ELSE_NETWORKoffline)onDestroy()to prevent leaksGoogle login fix (template app)
Google blocks OAuth from WebViews identified by the
; wv)user-agent token. Stripped it so Google treats the WebView as a regular browser, allowing sign-in.Performance optimizations
Modifier.blur(16.dp)on TopAppBar — primary source of frame drops. Replaced withsurface.copy(alpha = 0.95f)android:hardwareAccelerated="true"to template manifestwindow.setBackgroundDrawable(ColorDrawable(...))to set the predictive-back gesture reveal color — lighter weight thandecorView.setBackgroundColor()(avoids full DecorView layout pass). Removed expensive repeatedenableEdgeToEdge()andsetNavigationBarColor()calls from theme updatesFastOutSlowInEasing; build state transitions use 250ms withEaseInOutCubicfor smooth, non-choppy motion✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.