アプリケーション開発ポータルサイト
ServerNote.NET
Amazon.co.jpでPC関連商品タイムセール開催中!
カテゴリー【AndroidJava
【Android】WebViewに表示中のHTMLソースを取得する【最終版】
POSTED BY
2023-04-28

ネットに落ちてる情報1つではダメで、いくつか組み合わせないと実現しなかった。
プロジェクト一式はこちら GetWebViewHtml

オリジナルのWebViewClientクラスを作ってviewSource関数で受信するのが定番だが、
@JavascriptInterfaceプロトコルをつけなくては動作しない。
さらに明示的なimport文が必要なのがハマりどころ。Auto Importの機能は重要。

import android.webkit.JavascriptInterface;

    @JavascriptInterface
    public void viewSource(final String src) {

作ったサンプルがこちら。

JavaMainActivity.javaGitHub 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を使うと便利。

・検索アクションや失フォーカスのタイミングでソフトキーボードを閉じている。

※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!
ご連絡は以下アドレスまでお願いします★

☆ServerNote.NETショッピング↓
ShoppingNote / Amazon.co.jp
☆お仲間ブログ↓
一人社長の不動産業務日誌
【キーワード検索】