{"id":28310432,"url":"https://github.com/agusibrahim/android-web-inspector","last_synced_at":"2025-08-03T06:03:47.975Z","repository":{"id":91762966,"uuid":"91931013","full_name":"agusibrahim/Android-Web-Inspector","owner":"agusibrahim","description":"How to Inspecting Android WebView, Network logs, XHR logs (including url request and parameter) and Element/DOM inspecting","archived":false,"fork":false,"pushed_at":"2018-07-19T16:12:45.000Z","size":2830,"stargazers_count":65,"open_issues_count":9,"forks_count":26,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-21T11:37:34.158Z","etag":null,"topics":["android","javascript","webview","webviewjavascriptbridge","xhr"],"latest_commit_sha":null,"homepage":"https://play.google.com/store/apps/details?id=ai.agusibrahim.xhrlog","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agusibrahim.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-05-21T03:34:07.000Z","updated_at":"2025-01-31T14:44:47.000Z","dependencies_parsed_at":"2023-03-07T04:00:40.443Z","dependency_job_id":null,"html_url":"https://github.com/agusibrahim/Android-Web-Inspector","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/agusibrahim/Android-Web-Inspector","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusibrahim%2FAndroid-Web-Inspector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusibrahim%2FAndroid-Web-Inspector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusibrahim%2FAndroid-Web-Inspector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusibrahim%2FAndroid-Web-Inspector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agusibrahim","download_url":"https://codeload.github.com/agusibrahim/Android-Web-Inspector/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusibrahim%2FAndroid-Web-Inspector/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268500607,"owners_count":24260162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-03T02:00:12.545Z","response_time":2577,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","javascript","webview","webviewjavascriptbridge","xhr"],"created_at":"2025-05-24T11:11:09.471Z","updated_at":"2025-08-03T06:03:47.933Z","avatar_url":"https://github.com/agusibrahim.png","language":"Java","readme":"## Android Web Inspector\n![image](https://github.com/agusibrahim/Android-Web-Inspector/blob/master/art/JointPics_20170521_104538.PNG?raw=true)\n\n[DOWNLOAD APK](https://github.com/agusibrahim/Android-Web-Inspector/blob/master/WebInspector_ai.apk)\n\n\u003ca href='https://play.google.com/store/apps/details?id=ai.agusibrahim.xhrlog\u0026pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'\u003e\u003cimg alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/\u003e\u003c/a\u003e\n\nTerinspirasi dari Google Chrome DevTool, banyak faselitas Uji untuk pengembang yang disediakan. Di Android sendiri bisa kita lakukan inspeksi halaman dengan cara Remote melalui Wi-Fi atau melalui USB dengan ADB Protokol.\nNamun inspeksi melalui remote tersebut tentu saja dilakukan di PC/Laptop, tidak bisa standalone.\nDisini dijelaskan bagiaimana cara inspeksi halaman seperti Inspecting Element/DOM, XHR logger dan Network logger di WebView Android.\n\nAndroid menyediakan fungsi Javascript Interface yang memungkinkan kita untuk membuat fungsi javascript melalui java, atau memanggil fungsi java dari javascript dan memanggil fungsi javascript melalui java. *ah ribet penjelasannya* 😂\n\nBaiklah, berikut langkah-langkahnya:\n\n### Membuat Callback\nPertama kita membuat Javascript Interface menggunakan Java, dimana saat fungsi JS itu dipanggil, maka akan mentrigger fungsi di Java, ini berguna untuk mewadahi data yang sudah didapat dari hasil intercept.\n```java\nclass MyJavaScriptInterface{\n\t\t@JavascriptInterface\n\t\t@SuppressWarnings(\"unused\")\n\t\tpublic void now(String content){\n\t\t\tandroid.util.Log.d(\"xhr\", content);\n\t\t}\n}\n``` \nTambahkan _MyJavaScriptInterface_ ke WebView\n```java\nwebView.addJavascriptInterface(new MyJavaScriptInterface(), \"callme\");\n``` \nPanggil dengan javascript\n```javascript\ncallme.now(\"Hello Bro\");\n``` \nAtau membuat fungsi JS seperti jQuery yaitu simbol dolar, tapi kita memakai double dolar\n```java\nwebView.addJavascriptInterface(new MyJavaScriptInterface(), \"$$\");\n``` \nPanggil dengan javascript\n```javascript\n$$.now(\"Hello Bro\");\n``` \n\n### Overriding XMLHttpRequest\nYap, dengan melakukan override pada fungsi XHR ini kita dapat melempar data yang kita inginkan ke JS Interface yang sudah kita buat. Bagaimana cara override request dan response dari XHR? Saya mendapatkan caranya disini\n* Add a \"hook\" to all AJAX requests on a page [[...]](http://stackoverflow.com/questions/5202296/add-a-hook-to-all-ajax-requests-on-a-page)\n http://stackoverflow.com/a/27363569\n\nInject JS untuk Override XHR setiap halaman selesai dimuat, seperti ini\n```java\n@Override\npublic void onPageFinished(WebView view, String url) {\n    // xhr override\n    view.loadUrl(\"javascript:function injek(){window.hasovrde=1;var e=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(ee,nn,aa){this.addEventListener('load',function(){$$.log(this.responseText, nn, JSON.stringify(arguments))}),e.apply(this,arguments)}};if(window.hasovrde!=1){injek();}\");\n    super.onPageFinished(view, url);\n}\n``` \nDiatas saya membuat fungsi *injek*, intinya agar script di inject sekali saja jika memang belum pernah melakukan inject JS diatas. Oya, script sengaja di Minify menggunakan layanan online http://refresh-sf.com/, atau kamu bisa meng-unminify disini http://unminify.com/\n## Inspect Element\n![image](https://developer.chrome.com/devtools/images/elements-panel.png)\n\u003e Google Chrome DevTools\n\nSelanjutnya adalah Inspect Element atau DOM, dalam Google Chrome DevTools faselitas ini ada di panel pertama. Disini kita bisa melihat source code dari setiap element, misalnya dengan cara klik Kanan di Chrome pada element yang dikehendaki, trus pilih Inspect. \n\nDi Android kita juga akan melakukannya, yaitu dengan cara men-Tap element yang dikehendaki (misal sebuah form), maka source code dari element tersebut akan muncul, dan kita juga bisa mengeditnya.\n```javascript\ndocument.addEventListener('click', function(e) {\n    e.preventDefault();\n    e.stopPropagation();\n    var elem = document.elementFromPoint(e.clientX, e.clientY);\n    alert(elem.parentElement.outerHTML)\n}, true);\n```\n\nFungsi JS diatas yaitu untuk mendapatkan Element dari setiap yang\nkita Klik/Tap dalam halaman web. Dengan *preventDefault* serta  *stopPropagation* membuat fungsi default klik di nonaktifkan, misalnya klik di sebuah link maka kita tidak diarahkan ke link tersebut.\nSeperti biasa, inject JS diatas saat laman selesai dimuat. Seperti ini:\n```javascript\n@Override\npublic void onPageFinished(WebView view, String url) {\n    // click to Element\n    view.loadUrl(\"javascript:function injek2(){window.touchblock=0,window.dummy1=1,document.addEventListener('click',function(n){if(1==window.touchblock){n.preventDefault();n.stopPropagation();var t=document.elementFromPoint(n.clientX,n.clientY);window.ganti=function(n){t.outerHTML=n},window.gantiparent=function(n){t.parentElement.outerHTML=n},$$.print(t.parentElement.outerHTML, t.outerHTML)}},!0)}1!=window.dummy1\u0026\u0026injek2();\");\n    // xhr override\n    view.loadUrl(\"javascript:function injek(){window.hasovrde=1;var e=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(ee,nn,aa){this.addEventListener('load',function(){$$.log(this.responseText, nn, JSON.stringify(arguments))}),e.apply(this,arguments)}};if(window.hasovrde!=1){injek();}\");\n    super.onPageFinished(view, url);\n}\n```\n\n#### Bahaimana mengedit Element dari hasil klik?\nJika JS diatas di Minify, terlihat ada fungsi global *ganti* dan *gantiparent*, jadi setiap Element dari hasil click bisa kita edit menggunakan kedua fungsi tersebut.\n\n## DOWNLOAD\nhttps://play.google.com/store/apps/details?id=ai.agusibrahim.xhrlog\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagusibrahim%2Fandroid-web-inspector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagusibrahim%2Fandroid-web-inspector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagusibrahim%2Fandroid-web-inspector/lists"}