2012年7月28日土曜日

AndroidのWebViewのリファレンスを流し読み

とりあえずAndroid DevelopersのWebViewの項目を見ながら思いついたことを適当に書いていこうと思います。
というかそろそろWebView2出してくれないと世界中のブラウザ作者のみなさんが過労死すると思うんだ僕は。

せっかくだし一行目から訳していくことにしよう!
えー、このViewはWebページを表示するためのものです。えー、このクラスは… うむ、英語よくわかんないです。
英語はパラグラフリーティングでどうこうって英語の偉い先生が言ってたから、一行目さえわかればいいんだよ、グリーンだよ。
というわけでダーッと残りの英語の羅列は無視して、Constantsってところ。たぶん「定数」って意味だろう。調べてないけど。
SCHEME_GEO…ふむふむ、これは位置情報を表すURIのスキームですな←適当に言ってる
URIはURLのtypo…ではなくなんだかそうい規格らしい。未だにURIとURLの違いがよくわからない。
で、URIのスキームというのはhttp://とかの「:」(コロン)の前の文字列(この場合だとhttp)のことではないかと。知らないけど。
位置情報だと「geo」かな。「geo:なんとか」ってURIをIntentに乗せてあげるとマップアプリあたりが起動してくれるはず。
SCHEME_MAILTO、SCHEME_TELも同様。
あんまりWebViewに関係ない話だけどせっかく書いたしまあいいや。

というわけでMethodsから僕が知ってるのだけだらだら書く。あと有名なのは省く。
続きは追記



・public void addJavascriptInterface (Object object, String name)
・public void removeJavascriptInterface (String name)
これはねーうふふ、使ったことないのでググってくださいm(_ _)m
HTML上のJavaScriptと、アプリ上の(?)Javaを連帯させたりできます。できるらしい。
当たり前ですがセキュリティ的に悲惨なので使うときはローカル限定が好ましいです。

・public Picture capturePicture ()
WebViewのスクリーンショットが撮れます。しかも全体像です。欲しいところだけお好きに切り取ってくださいな。
Picture→Bitmapに変換したら簡単に保存できるね!!

・public void clearHistory ()
Historyと言っても端末の標準ブラウザとかの履歴が消えるわけじゃなくて、WebViewの戻る/進むの履歴が消えるだけです。

・public void clearMatches ()
・public int findAll (String find)
・public void findNext (boolean forward)
この辺はページ内検索のAPIですねー。ちなみにもうひとつ隠しAPIとしてvoid setFindIsUp(boolean isUp)というのもあります。めんどくさいのでまとめて説明。
まず、Android 3.0以降は深いことを考えずに、検索開始時にshowFindDialogMethod("".true)を呼んであげましょう。勝手に検索バーが出てきてAndroid側が処理してくれます。
Android 3.0未満の場合は以下のようにします。
ページ内検索を行いたいときにはfindAllを呼びます。引数はもちろん検索ワード。戻り値は検索結果の数。
ここで、findAllをしただけでは検索結果にハイライトがかかりません。ハイライトをつけるためには、setFindIsUp(true)を呼び出します。これは隠しAPIなので、リフレクションを駆使して気合で呼び出しましょう。
さて、findAllでは、次の検索ワードの位置に移動…ということができません。WebViewのスクロールを次の検索ワードの位置に移動させるにはfindNextを使います。forwardがtrueだと次、falseだと前の検索結果の位置に移動します。
やることをやったらclearMatchesで検索のハイライトなどを消してあげましょう。
ただし、まだ注意があります。clearMatchesだけでは正常に検索処理を終了できません。フォーカスあたりが変になっていたと思います。覚えてませんけど。正常に終了させるには、隠しAPIのvoid notifyFindDialogDismissed()を呼んであげましょう。もちろんリフレクションで。
これで検索処理が正常に終了します。

・public void destroy ()
タブブラウザであればタブを閉じた時、その他onDestroyが呼ばれたときはdestroy()を呼んであげましょう。じゃないとメモリリークで強制終了します。

・public static void disablePlatformNotifications ()
・public static void enablePlatformNotifications ()
 APNに設定されたProxyを有効にするかどうかは全てこいつらにかかっています。APNに設定されたProxyってなんだー!!って思いますが要はFilterProxyが使えるか否かはこいつらにかかっているということです。エロ広告が全て悪い。
ActivityのonResumeでenablePlatformNotificationsを、onPauseでdisablePlatformNotificationsを呼んであげればいいみたいです。標準ブラウザはそうしてた!!

・public void emulateShiftHeld ()
テキスト選択を司るAPIです。これを呼んであげるとWebViewがテキスト選択モードになります。
ただし、HoneycombかICSかからは関数自体は残っているもののこれを呼ぶと内部でバグが発生して落ちます。
よってHoneycombかICSかからは(←ちゃんと調べてない)リフレクションからboolean selectText()を呼んであげます。これでテキスト選択モードになります。良かったね。でもAndroid 4.1というかJellyBeanだとこの方法も使えなくなります(/_;)
実機確認どころかエミュ確認もしてないですが、Android 4.1 JellyBeanではWebView.mProvider.selectText()を呼んであげればなんとかなるかもしれません。

・public void flingScroll (int vx, int vy)
調べてないけど初速度を指定して、スクロール量を調節してスクロール、なるものができるみたいです。調べてないけど。

・public WebView.HitTestResult getHitTestResult ()
まず、WebViewのsetOnCreateContextMenuListenerからコンテクストメニュー、まあ俗にいう長押しメニューを設定します。長押しをすると、onCreateContextMenuが呼び出され、このとき引数にはViewが入っています(中身はもちろんWebView)。
このViewをWebViewにキャストしてWebView.HitTestResult result = webview.getHitTestResult()みたいな感じで呼んであげると、長押ししている部分の情報がいっぱいおっぱい取れます。
result.getType()で、長押しした部分がEditTextなのかImageなのかなんなのかを知ることができます。
getType()がWebView.HitTestResult.SRC_ANCHOR_TYPEだとリンクです。
result.getExtra()でリンクのURLを取得することができます。
getType()がWebView.HitTestResult.IMAGE_TYPEだと画像です。
これも同様に、result.getExtra()で画像のURLを取得することができます。
WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPEだと画像リンクです。
このとき、result.getExtra()の戻り値は、画像のURLです。
リンクのURLを取る方法は少し厄介で、
webview.requestFocusNodeHref(new Handler(){
    @Override
    public void handleMessage(Message msg) {
        String url = msg.getData().getString("url");
    }
}.obtainMessage());
のようにする必要があります。
WebView.HitTestResult.EDIT_TEXT_TYPEだとEditTextです。Googleの検索ボックスとかがそう。
通常は無視します。
WebView.HitTestResult.PHONE_TYPEはお電話番号です。
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_TEL + result.getExtra())));
みたいにすると電話がかけられたりします。
WebView.HitTestResult.EMAIL_TYPEはメールアドレスです。
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_MAILTO + result.getExtra())))
みたいにしてメール送ります。
WebView.HitTestResult.GEO_TYPEはなんか位置情報みたいなものです。あんまりというか全く見たこと無いので知りません。
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_GEO + URLEncoder.encode(result.getExtra()))))
みたいにすると地図が開けたりするんじゃないですか知りませんけど。
WebView.HitTestResult.UNKNOWN_TYPEはそれ以外です。
要するになにもないところ長押しするとこいつになります。about:blankなんかはびっくりするほど何も無いのでこいつばっかり呼ばれます。関係無いですけどabout:blankの画面見てるとThe BeatlesのYellow SubmarineのDVDのワンシーン思い出しませんか?

・public void onPause ()
・public void onResume ()
タブブラウザなんかは別のタブに変わるときに、変更前のタブのWebViewのonPause、変更後のタブのWebViewのonResumeを呼んであげると、Flashなどで流れてる音楽がいい感じに止まるんじゃないでしょうか。

・public void pauseTimers ()
・public void resumeTimers ()
Activity自体のonPause、onResumeが呼ばれた時にこれを呼んであげるといいかもしれません。
これを呼んであげるとFlash内で流れてる音楽が止まって、電池の節約にもなります。地球にも優しい。
ちなみにこれらはWebView#onPause、WebView#onResumeのグローバル版(?)です。
タブブラウザなどではこれをカレントタブのWebViewの一個について呼ぶだけで、WebView全部にonPause、onResumeが適用された状態になります。

・public void setOverScrollMode (int mode)
この関数はAndroid 2.3からなので2.3未満では呼ばれないように気をつけようね!
WebViewをスクロールして端っこにぶち当たったときに端がピカピカ光るのがうざいときはOVER_SCROLL_NEVERを設定してあげよう!

・public void setScrollBarStyle (int style)
好みの問題だけどSCROLLBARS_INSIDE_OVERLAYが一番いいと自負している。終わり。

・protected int computeHorizontalScrollExtent ()
・protected int computeHorizontalScrollOffset ()
・protected int computeHorizontalScrollRange ()
・protected int computeVerticalScrollExtent ()
・protected int computeVerticalScrollOffset ()
・protected int computeVerticalScrollRange ()
WebViewのスクロール位置などが分かる。
ExtentやOffsetの意味は…まあこのへんを見ていただければいいかと。
要するに、Offsetは原点から表示部分の上端(左端)までの距離、Extentは表示部分の上端(左端)から下端(右端)までの距離、Rangeはスクロール可能な全体の長さを表す。


最後にその他の非公開APIについて。
・public void setEmbeddedTitleBar(View v)
ページをスクロールすると一緒にスクロールされる標準ブラウザのようなタイトルバーを作りたい!というときには、引数にタイトルバーのViewを入れて彼を呼んであげます。もちろん引数にnullを入れてあげると、ちゃんとリセットされます。 Jelly Beanでは見事にまるまる消え去ってしまいました。絶対にゆるさない。今のところJelly Beanでは気合で実装するしかないようです。

以上です。
気が向いたらWebSettingとWebViewClient、WebChromeClientについても書いていこうと思いました。思っただけ

1 件のコメント:

  1. えすぺりあ2013年4月5日 17:19

    参考になりました、ありがとうございます!

    WebView#emulateShiftHeld() ですが、
    ・HoneyComb
    #emulateShiftHeld() も #selectText() も動きます。
    が、#selectText()の方が動きが良いです。前者は選択範囲のカーソルが、WebViewをタッチしないと表示されませんでした。
    ・ICS
    おっしゃるとおりでした。
    ・JB
    おっしゃるとおり、mProvider#selectText()で動きました。

    時間経っていますが、ご参考までに。

    返信削除