[{"data":1,"prerenderedAt":36},["ShallowReactive",2],{"case-h5-debug-console-mock-en":3,"blog-list-en":13},{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11,"html":12},"h5-debug-console-mock","H5 Debug in Practice (2): Android WebView White Screen—From Console Remote Debug to Mock Validation","A campaign H5 white-screened on some Android devices after a button tap—all requests returned 200, but the page showed nothing. Using DevPeek Console to capture WebView runtime logs, remote eval to confirm a polyfill override, then Mock to verify the fallback UI under error conditions.","2026-07-13",true,"DevPeek H5 debug practice part 2: troubleshoot Android WebView white screen via Console remote debug to locate a JavaScript polyfill conflict, then use Mock to verify page fallback behavior under abnormal API responses.","h5-debug",2,"\u003Ch2>White screen\u003C\u002Fh2>\n\u003Cp>It happened during a campaign H5 stress test.\u003C\u002Fp>\n\u003Cp>QA posted a screen recording in the group:\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>&quot;Samsung S23, Android 14, opened the campaign page in WeChat, tapped \u003Cstrong>Join Now\u003C\u002Fstrong>—screen goes white.&quot;\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>What made it tricky was that the page wasn&#39;t completely broken.\u003C\u002Fp>\n\u003Cp>It loaded fine:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Home content displayed normally;\u003C\u002Fli>\n\u003Cli>The button was tappable;\u003C\u002Fli>\n\u003Cli>Loading appeared after tapping;\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>But then the screen went white.\u003C\u002Fp>\n\u003Cp>iOS was fine. Other Android devices were fine too.\u003C\u002Fp>\n\u003Cp>First suspects:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>JavaScript runtime error?\u003C\u002Fli>\n\u003Cli>API response breaking the render?\u003C\u002Fli>\n\u003Cli>Android WebView compatibility issue?\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Started with the network layer.\u003C\u002Fp>\n\u003Ch2>Capture looked normal, page still crashed\u003C\u002Fh2>\n\u003Cp>First, the API request.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>POST \u002Fapi\u002Fcampaign\u002Fjoin\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Returned:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>200 OK\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Request params checked out. Response structure was as expected.\u003C\u002Fp>\n\u003Cp>At least the API wasn&#39;t the problem.\u003C\u002Fp>\n\u003Cp>But the page was still white.\u003C\u002Fp>\n\u003Cp>This is the tricky kind of issue: the request succeeded, the page loaded, but something failed mid-execution.\u003C\u002Fp>\n\u003Cp>Without runtime logs, you&#39;re guessing.\u003C\u002Fp>\n\u003Ch2>vConsole and Remote Debug weren&#39;t a good fit here\u003C\u002Fh2>\n\u003Cp>For H5 debugging, vConsole is usually the first thought.\u003C\u002Fp>\n\u003Cp>But this campaign page was already live. We couldn&#39;t repack it with vConsole injected.\u003C\u002Fp>\n\u003Cp>And the issue only happened on specific Android devices.\u003C\u002Fp>\n\u003Cp>Chrome Remote Debug was tried too:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>chrome:\u002F\u002Finspect\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>It could connect to the WebView.\u003C\u002Fp>\n\u003Cp>But the error happened \u003Cem>after\u003C\u002Fem> the button tap. By the time the page refreshed, the error was gone.\u003C\u002Fp>\n\u003Cp>On top of that:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>WebView debug flag requires client-side support;\u003C\u002Fli>\n\u003Cli>USB connection has environment dependencies;\u003C\u002Fli>\n\u003Cli>The live version couldn&#39;t be repeatedly adjusted.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The problem was: the WeChat WebView on the phone had already hit an error, and I needed to see what it saw at runtime.\u003C\u002Fp>\n\u003Ch2>Get the WebView Console first\u003C\u002Fh2>\n\u003Cp>The test device connected to DevPeek through the proxy.\u003C\u002Fp>\n\u003Cp>Steps completed:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Install the HTTPS certificate;\u003C\u002Fli>\n\u003Cli>Configure the proxy;\u003C\u002Fli>\n\u003Cli>Enable SSL decryption for the target domain.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Full checklist: \u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">mobile web debugging\u003C\u002Fa>; if the preview stays on &quot;Waiting for device connection&quot;, check the \u003Ca href=\"\u002Fen\u002Fdocs\u002Ffaq\u002F\">FAQ\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>In the DevPeek \u003Cstrong>Debug\u003C\u002Fstrong> tab, select the device. QA reopened the campaign page.\u003C\u002Fp>\n\u003Cp>A red line appeared immediately in the Console:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Uncaught TypeError:\ne.isIntersecting is not a function\n\nat IntersectionObserver polyfill\n(chunk-vendors.js:1847)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fdebug_console_eval.png\" alt=\"DevPeek Debug Console: errors and remote eval\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Real device console output streams to the debug panel.\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>The direction was clear.\u003C\u002Fp>\n\u003Ch2>Root cause: polyfill overrode the native implementation\u003C\u002Fh2>\n\u003Cp>This involves \u003Ccode>IntersectionObserver\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Android 14&#39;s WebView natively supports this API.\u003C\u002Fp>\n\u003Cp>But the project still loaded an old polyfill, which overrode the native implementation.\u003C\u002Fp>\n\u003Cp>So the page wasn&#39;t running the native \u003Ccode>IntersectionObserver\u003C\u002Fcode>—it was running the polyfill. The two implementations had compatibility differences.\u003C\u002Fp>\n\u003Cp>A quick remote eval in Console confirmed it:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-javascript\">navigator.userAgent.match(\u002FAndroid\\s([\\d.]+)\u002F)?.[1];\n\u002F\u002F &quot;14&quot;  ——confirmed Android version\n\ntypeof IntersectionObserver;\n\u002F\u002F &quot;function&quot;  ——confirmed API exists\n\nIntersectionObserver.toString().includes(&quot;native code&quot;);\n\u002F\u002F false  ——confirmed not running native implementation\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Root cause confirmed.\u003C\u002Fp>\n\u003Ch2>Issue located, but testing wasn&#39;t done\u003C\u002Fh2>\n\u003Cp>The frontend team started fixing the polyfill.\u003C\u002Fp>\n\u003Cp>But the stress test window was still open.\u003C\u002Fp>\n\u003Cp>QA needed to confirm: if the API returns error states, does the page fall back correctly?\u003C\u002Fp>\n\u003Cp>For example:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Campaign ended;\u003C\u002Fli>\n\u003Cli>User not authorized;\u003C\u002Fli>\n\u003Cli>Insufficient inventory.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>These scenarios can&#39;t wait for backend cooperation every time. We needed to simulate API responses.\u003C\u002Fp>\n\u003Ch2>Using Mock to verify error scenarios\u003C\u002Fh2>\n\u003Cp>In the DevPeek capture list, find \u003Ccode>POST \u002Fapi\u002Fcampaign\u002Fjoin\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Create a Mock rule.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Match conditions:\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>URL contains \u003Ccode>campaign\u002Fjoin\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Method is POST\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>\u003Cstrong>Response modification:\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;code&quot;: 10086,\n  &quot;message&quot;: &quot;Campaign ended&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Save and enable.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fmock_wizard_auto_response.png\" alt=\"DevPeek Mock rule editor: match conditions and response modification\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Mock rules take effect immediately, no proxy restart.\u003C\u002Fem>\u003C\u002Fp>\n\u003Cp>QA tapped the button again.\u003C\u002Fp>\n\u003Cp>This time, no white screen. The page showed &quot;Campaign ended&quot; as expected.\u003C\u002Fp>\n\u003Cp>Fallback logic verified.\u003C\u002Fp>\n\u003Cp>To test other error scenarios, for example:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-json\">{\n  &quot;code&quot;: 10010,\n  &quot;message&quot;: &quot;Campaign not available&quot;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Just update the Mock response and quickly verify different error states.\u003C\u002Fp>\n\u003Cp>No need to:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Modify the backend API;\u003C\u002Fli>\n\u003Cli>Wait for API deployment;\u003C\u002Fli>\n\u003Cli>Repack the H5.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Mock rules are persistent—they survive closing and reopening DevPeek. Remember to disable or delete temporary rules after the session.\u003C\u002Fp>\n\u003Ch2>The full investigation flow\u003C\u002Fh2>\n\u003Cp>The complete debug chain for this case:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Button tap\n    ↓\nCapture confirms API returned 200\n    ↓\nConsole captures WebView runtime error\n    ↓\nRemote eval confirms polyfill override\n    ↓\nFix confirmed\n    ↓\nMock simulates error API responses\n    ↓\nFallback UI verified\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Throughout the entire process, no H5 repack was needed, and no client-side debug mode was required.\u003C\u002Fp>\n\u003Ch2>Why this went smoothly\u003C\u002Fh2>\n\u003Cp>In similar past situations, multiple tools were usually needed:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Capture tool to confirm requests;\u003C\u002Fli>\n\u003Cli>vConsole to check runtime logs;\u003C\u002Fli>\n\u003Cli>Another tool to modify API responses.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Each tool solved part of the problem.\u003C\u002Fp>\n\u003Cp>But during investigation, you&#39;d often wonder:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Where was that error log again?\u003C\u002Fli>\n\u003Cli>What did that API return?\u003C\u002Fli>\n\u003Cli>Did the phone re-trigger the request after the Mock change?\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Information was scattered across different tools.\u003C\u002Fp>\n\u003Cp>This time, everything was on the same debug chain:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Network\n   ↓\nConsole\n   ↓\nMock\n   ↓\nReal device page\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>For mobile H5 debugging, fewer tool switches means less context loss—and that alone reduces investigation cost.\u003C\u002Fp>\n\u003Ch2>Limitations\u003C\u002Fh2>\n\u003Cp>Console and Mock aren&#39;t silver bullets. Full boundaries: \u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">mobile web debugging\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>1. Page completely crashed\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Infinite loops, stack overflow, main thread blocking—the injected debug script may not connect either. Fall back to resource loading and network checks.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>2. iframe pages\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Console runs in the current page context by default. If the issue is inside an iframe, open that URL separately.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>3. Mock may not intercept all requests\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Mock depends on the proxy chain. Service Worker cache, native network interception, or certain WebView kernel behaviors may bypass it. Verify the request goes through the proxy.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>4. Remote eval context\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Remote scripts share the page&#39;s execution context. Quick checks are fine, but avoid heavy IndexedDB iteration or long synchronous tasks—use async patterns instead.\u003C\u002Fp>\n\u003Ch2>Next\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>H5 Debug in Practice (3): TBD\u003C\u002Fstrong>—more real-world mobile H5 joint-debug cases.\u003C\u002Fp>\n\u003Chr>\n\u003Cp>If you often run into &quot;API OK, page broken&quot; scenarios, Android WebView compatibility issues, or can&#39;t directly debug production H5, \u003Ca href=\"\u002F\">try DevPeek\u003C\u002Fa> or discuss on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FGYPengDev\u002Fdevpeek\u002Fdiscussions\">GitHub Discussions\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2>Related docs\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">Mobile web debugging\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fdocs\u002Fmock\u002F\">Mock rules\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fdocs\u002Fcapture\u002F\">Capture and request details\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fdocs\u002Fproxy-ssl\u002F\">Proxy &amp; SSL certificates\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fdocs\u002Ffaq\u002F\">FAQ\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Series\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Fen\u002Fblog\u002Fwechat-h5-storage-debug\u002F\">H5 Debug in Practice (1): WeChat H5 Local Cache—Debug It on Desktop\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n",{"items":14},[15,16,23,30],{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"series":10,"seriesOrder":11},{"slug":17,"title":18,"summary":19,"date":20,"featured":8,"seoDescription":21,"series":10,"seriesOrder":22},"wechat-h5-storage-debug","H5 Debug in Practice (1): WeChat H5 Local Cache—Debug It on Desktop","After switching test accounts in a WeChat official-account H5, the avatar still showed the old user—capture had the new token, stale data stayed in localStorage. This post walks through a real joint-debug case and how to view and edit localStorage, sessionStorage, and IndexedDB in WeChat WebView from your PC.","2026-07-11","DevPeek H5 debug: locate localStorage, sessionStorage, and IndexedDB cache issues in WeChat H5—compared with vConsole and remote debug, with real WebView debugging workflow.",1,{"slug":24,"title":25,"summary":26,"date":27,"featured":8,"seoDescription":28,"series":29,"seriesOrder":11},"why-we-built-devpeek-h5-debug","Why We Built DevPeek (2): That H5 Page in the App—Debug It on Your PC","Param transform fixed login, but the activity H5 only broke inside the App WebView. Remote debug and capture lived in different windows—so we folded mirroring and our own debug panels into DevPeek.","2026-07-10","DevPeek origin series, part 2: in-app H5 bugs that only show on real devices, the split between remote debug and capture, and how the Debug tab mirrors pages with built-in DOM, Console, and Network panels.","origin",{"slug":31,"title":32,"summary":33,"date":34,"featured":8,"seoDescription":35,"series":29,"seriesOrder":22},"why-we-built-devpeek","Why We Built DevPeek (1): HTTPS Decrypted, Body Still Gibberish","The night before a release, TLS was already open—but changing one request field still meant digging up encrypt\u002Fdecrypt scripts. That pushed us toward a proxy tool with business-layer crypto built in—and DevPeek started there.","2026-07-09","DevPeek origin series, part 1: the manual request-body encrypt\u002Fdecrypt grind—and why we set out to build a proxy tool that owns business-layer crypto.",1783946168583]