feat(ui): embedded explorer WebView for block-height lookup (#139)#271
Conversation
The explorer-deeplink-lookup flow (#85, #128) opens the user's address page on the public CKB explorer so non-technical users can scroll to their first transaction and copy the block number for the CUSTOM sync mode. Custom Tabs (#138) is the current launcher; on aggressive OEM memory managers (Tecno / Infinix / MIUI) the Custom Tab tab can be killed mid-read, forcing a full restart and reopen. For a fire-and-forget link this is annoying. For a round-trip critical flow like block-height lookup it is a usability cliff. What ships - New `ExplorerWebViewSheet` Composable wrapping a sandboxed `WebView` in a `ModalBottomSheet`. Stays inside Pocket Node's process and task, so the lookup round-trip survives backgrounding. - HomeScreen + SettingsScreen sync-options paths now route the lookup through the WebView sheet instead of `openInBrowser`. - Tx-detail explorer links elsewhere in the app (ActivityScreen, SendScreen, etc) remain on Custom Tabs because they are fire-and-forget and do not benefit from in-process containment. Security posture The acceptance criteria from #139 are baked into the Composable itself, not split across the call site, so the next contributor extending this WebView inherits the constraints automatically: - Host whitelist enforced in `shouldOverrideUrlLoading`. Only explorer.nervos.org / testnet.explorer.nervos.org / pudge.explorer.nervos.org (and their `www.` aliases) load inside the WebView. Off-host navigation escapes to `openInBrowser` (Custom Tabs), so this never serves as a general-purpose in-app browser. - No `addJavascriptInterface`. There is no JS-to-native bridge. Documented inline so a future PR cannot add one silently. - Third-party cookies refused via `CookieManager.setAcceptThirdPartyCookies(view, false)`. - `allowFileAccess = false`, `allowContentAccess = false` to close off file:// / content:// URIs. - `mixedContentMode = MIXED_CONTENT_NEVER_ALLOW`: the explorer is HTTPS-only and any downgrade is a sign of a hostile redirect. - `WebView.destroy()` on AndroidView.onRelease so the JS context does not pin the process past dismissal. UX - Top bar shows the current host text (no full URL bar by design) plus a close button and an "Open in browser" escape hatch that punts the same URL to Custom Tabs. - Linear progress indicator while pages load. - Sheet uses skipPartiallyExpanded so the WebView lands near full-height immediately (block lookup wants real estate). Out of scope for this PR - Settings toggle to swap WebView for Custom Tabs as the lookup primitive. The issue suggests waiting for field data before making the choice flip configurable; for now the WebView is the default for the lookup flow only and Custom Tabs remains the default for all other links. - Manual smoke on Tecno / Infinix / stock-Android — flagged in the issue acceptance criteria but requires real devices. - Memory profile of WebView under sync load — flagged similarly. Build verified locally: ./gradlew :app:compileDebugKotlin -x cargoBuild BUILD SUCCESSFUL ./gradlew :app:testDebugUnitTest -x cargoBuild BUILD SUCCESSFUL
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79f7f313ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| val host = request.url.host | ||
| if (host == null || host !in allowedHosts) { | ||
| // Off-host navigation: punt to Custom Tabs so this | ||
| // WebView never serves as a general-purpose browser. | ||
| onOffHost(request.url.toString()) | ||
| return true |
There was a problem hiding this comment.
Restrict off-host handling to main-frame HTTP(S) requests
shouldOverrideUrlLoading can be invoked for subframes and non-HTTP(S) schemes, but this implementation sends every non-allowlisted host to onOffHost(...). In practice, an embedded frame or script-initiated non-main-frame navigation from the explorer page can unexpectedly launch Custom Tabs/external apps and interrupt the block-height lookup flow even when the user did not intentionally leave the page. Gate this branch with request.isForMainFrame (and ideally an HTTP(S) scheme check) before calling onOffHost.
Useful? React with 👍 / 👎.
Summary
Adds an in-process WebView sheet for the explorer-deeplink-lookup flow (#85, #128). Custom Tabs (#138) remains the launcher for fire-and-forget tx-detail links, but the block-height lookup is round-trip critical and an OEM memory manager killing a Custom Tab mid-read forces a full restart. An embedded WebView eliminates that failure mode.
What ships
ExplorerWebViewSheet— new Composable wrapping a sandboxedWebViewin aModalBottomSheet.openInBrowser.Security posture
Baked into the Composable so the next contributor inherits the constraints:
shouldOverrideUrlLoading— only{www.,}explorer.nervos.org,testnet.explorer.nervos.org,pudge.explorer.nervos.org. Off-host nav escapes toopenInBrowserso this never serves as a general-purpose in-app browser.addJavascriptInterface— no JS-to-native bridge. Documented inline so a future PR cannot add one silently.CookieManager.setAcceptThirdPartyCookies(view, false).allowFileAccess = false,allowContentAccess = false— closes offfile:///content://URIs.mixedContentMode = MIXED_CONTENT_NEVER_ALLOW— explorer is HTTPS-only.WebView.destroy()onAndroidView.onRelease— JS context doesn't pin the process past dismissal.UX
skipPartiallyExpandedso the WebView lands near full-height immediately.Out of scope (flagged in the issue acceptance criteria)
Test plan
./gradlew :app:compileDebugKotlin -x cargoBuildBUILD SUCCESSFUL./gradlew :app:testDebugUnitTest -x cargoBuildBUILD SUCCESSFULRefs #139, #138, #85, #128