【Android】WebViewに表示中のHTMLソースを取得する【最終版】
POSTED BY
2023-04-28
2023-04-28
ネットに落ちてる情報1つではダメで、いくつか組み合わせないと実現しなかった。
プロジェクト一式はこちら GetWebViewHtml
オリジナルのWebViewClientクラスを作ってviewSource関数で受信するのが定番だが、
@JavascriptInterfaceプロトコルをつけなくては動作しない。
さらに明示的なimport文が必要なのがハマりどころ。Auto Importの機能は重要。
import android.webkit.JavascriptInterface; @JavascriptInterface public void viewSource(final String src) {
作ったサンプルがこちら。
Java | MainActivity.java | GitHub Source |
// アクティビティ package net.servernote.getwebviewhtml; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.webkit.JavascriptInterface; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.EditText; import android.widget.TextView; import java.io.FileInputStream; import java.io.FileOutputStream; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; public class MainActivity extends Activity implements View.OnClickListener, TextView.OnEditorActionListener, View.OnFocusChangeListener { public HashMap<String, Integer> N; public HashMap<String, String> S; private WebView WEBVIEW; private EditText KEYWORD; private Handler HANDLER = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //プリファレンスのロード N = new HashMap<String, Integer>(); S = new HashMap<String, String>(); N.put("FILE_COUNTER", 0); S.put("KEYWORD", ""); S.put("LAST_WEB_URL", "https://www.google.co.jp/"); SharedPreferences pref = getSharedPreferences("Preferences", MODE_PRIVATE); for (Map.Entry<String, Integer> entry : N.entrySet()) { entry.setValue(Integer.parseInt(pref.getString(entry.getKey(), entry.getValue() + ""))); } for (Map.Entry<String, String> entry : S.entrySet()) { entry.setValue(pref.getString(entry.getKey(), entry.getValue())); } //レイアウト setContentView(R.layout.main); KEYWORD = findViewById(R.id.keyword); KEYWORD.setText(S.get("KEYWORD")); KEYWORD.setOnEditorActionListener(this); KEYWORD.setOnFocusChangeListener(this); findViewById(R.id.search).setOnClickListener(this); WEBVIEW = findViewById(R.id.webview); WEBVIEW.getSettings().setJavaScriptEnabled(true); WEBVIEW.setWebViewClient(new ViewSourceClient()); WEBVIEW.addJavascriptInterface(this, "activity"); WEBVIEW.loadUrl(S.get("LAST_WEB_URL")); } @Override protected void onDestroy() { //プリファレンスのセーブ SharedPreferences pref = getSharedPreferences("Preferences", MODE_PRIVATE); SharedPreferences.Editor editor = pref.edit(); for (Map.Entry<String, Integer> entry : N.entrySet()) { editor.putString(entry.getKey(), entry.getValue() + ""); } for (Map.Entry<String, String> entry : S.entrySet()) { editor.putString(entry.getKey(), entry.getValue()); } editor.commit(); super.onDestroy(); } @Override public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.search: doSearch(); break; default: break; } } public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEARCH) { doSearch(); } return true; // falseを返すと, IMEがSearch→Doneへと切り替わる } public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(); } } public void hideKeyboard() { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(KEYWORD.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } public void doSearch() { hideKeyboard(); String str = KEYWORD.getText().toString(); S.put("KEYWORD", str); if (str.length() <= 0) return; try { String enc = URLEncoder.encode(str, "UTF-8"); String url = "https://www.google.co.jp/search?q=" + enc; S.put("LAST_WEB_URL", url); WEBVIEW.loadUrl(url); } catch (Exception e) { Log.e("doSearch", e.toString()); } } @JavascriptInterface public void viewSource(final String src) { HANDLER.post(new Runnable() { @Override public void run() { int counter = N.get("FILE_COUNTER"); counter++; String file = "output." + counter + ".html"; N.put("FILE_COUNTER", counter); try { writeTextFile(file, src); Log.d("viewSource", "saved to " + file); } catch (Exception e) { Log.e("viewSource", e.toString()); } } }); } public String readTextFile(String file) throws Exception { String ret = ""; FileInputStream in = openFileInput(file); byte[] buf = new byte[in.available()]; in.read(buf); ret = new String(buf).trim(); in.close(); return ret; } public void writeTextFile(String file, String text) throws Exception { FileOutputStream out = openFileOutput(file, Context.MODE_PRIVATE); out.write(text.getBytes()); out.close(); } private static class ViewSourceClient extends WebViewClient { @Override public void onPageFinished(WebView view, String url) { view.loadUrl("javascript:window.activity.viewSource(document.documentElement.outerHTML);"); } } } //end of class
・MainViewのエディットフィールドにキーワードを入力して「検索」すると、WebViewに渡してGoogleの検索結果を表示します。
・WebViewにはViewSourceClientサブクラスを設定してあるのでJavaScriptでviewSource関数にページソースが渡ります。
・渡ってきたソースは連番をつけてローカルファイルに保存します。output.1.html,output.2.htmlなどと増えていきます。
・adb shellなどで確認してください。
adb shell run-as net.servernote.getwebviewhtml ls adb shell run-as net.servernote.getwebviewhtml ls files adb shell run-as net.servernote.getwebviewhtml cat files/output.1.html > output.1.html
↑ローカルにファイルが保存され、中が確認できます。
Android 8以上の場合、shell を exec-out に置き換えます。
その他リソースファイル等はこちらGetWebViewHtml
・ソース連番、入力値、WebViewの検索URLをそれぞれPreferencesに保存し、onDestroyで書き込みしている。
次回のonCreateでそれらをロードし、Viewとフィールドの初期値としている。Preferencesは数値と文字列を分けたHashMapを使うと便利。
・検索アクションや失フォーカスのタイミングでソフトキーボードを閉じている。
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ
※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!ご連絡は以下アドレスまでお願いします★
【キーワード検索】
【最近の記事】【全部の記事】
Intel Macbook2020にBootCampで入れたWindows11 Pro 23H2のBluetoothを復活させるWindowsのデスクトップ画面をそのまま配信するための下準備
WindowsでGPUの状態を確認するには(ASUS系監視ソフトの自動起動を停止する)
CORESERVER v1プランからさくらインターネットスタンダートプランへ引っ越しメモ
さくらインターネットでPython MecabをCGIから使う
さくらインターネットのPHPでAnalytics-G4 APIを使う
インクルードパスの調べ方
【Git】特定ファイルを除外する.gitignore
【Ubuntu/Debian】NVIDIA関係のドライバを自動アップデートさせない
【Python】Spacyを使用して文章から出発地と目的地を抜き出す
【人気の記事】【全部の記事】
【Windows10】リモートデスクトップ間のコピー&ペーストができなくなった場合の対処法Windows版Google Driveが使用中と言われアンインストールできない場合
進研ゼミチャレンジタッチをAndroid端末化する
【Apache】サーバーに同時接続可能なクライアント数を調整する
VirtualBoxの仮想マシンをWindows起動時に自動起動し終了時に自動サスペンドする
Windows11+WSL2でUbuntuを使う【2】ブリッジ接続+固定IPの設定
【C/C++】小数点以下の切り捨て・切り上げ・四捨五入
Googleファミリーリンクで子供の端末の現在地がエラーで取得できない場合
【Linux】iconv/libiconvをソースコードからインストール
Ubuntu Server 21.10でイーサリアムブロックチェーン【その5】
【カテゴリーリンク】
Android
iPhone/iPad
Flutter
MacOS
Windows
Debian
Ubuntu
CentOS
FreeBSD
RaspberryPI
HTML/CSS
C/C++
PHP
Java
JavaScript
Node.js
Swift
Python
MatLab
Amazon/AWS
CORESERVER
Google
仮想通貨
LINE
OpenAI/ChatGPT
IBM Watson
Microsoft Azure
Xcode
VMware
MySQL
PostgreSQL
Redis
Groonga
Git/GitHub
Apache
nginx
Postfix
SendGrid
Hackintosh
Hardware
Fate/Grand Order
ウマ娘
将棋
ドラレコ