Android WebViewと携帯電話の後退ボタンの話


writen by Tony@tokyo
 
[物語の概要]
今日はオンラインBugを調べます.
製品自体はAndroidアプリです.AndroidデバイスにAPKでインストールおよび実行.全体的なアーキテクチャはnaive開発フレームワークであり,WebViewが中間的に埋め込まれている.これらは何も言うことはありません.
このオンラインBugの問題は、特定の画面の移行中にAndroidデバイスの後退ボタンが無効になることです.ほとんどの画面は可能です.
たとえば、次のようなCaseの画面遷移があります.
A一覧画面->B登録画面->C登録確認画面->D登録終了画面->A一覧画面
各段階に対応する画面URLは、
          /list      ->  /xxxregiest?id=12 ->/xxxregiest->  /xxxregiest  ->   /list     
現象は、移行したチェーン全体が歩き終わった後、A一覧画面に戻った後、Androidデバイスの後退ボタンをクリックしても、何の反応もありません...
 
 
[調査と分析]
まず、Androidデバイスが持っているブラウザで操作したいと思います.
Androidが持参したブラウザで、完全な移行チェーンを歩いた後、この時点で戻るボタンを押すと、「post送信重複送信」の情報が表示されます...
画面遷移の間にformが提出されていたので、WebViewがロールバックしたとき、失敗したに違いないと思いきった.
 
そこでタブレットテストを変えてみると、Bログイン画面->Cログイン確認画面の遷移で、フォールバックボタンが有効であることがわかりました.
しかしBログイン画面->Cログイン確認画面の遷移もform提出で完了しているのではないでしょうか.
問題はいったいどこにあるのだろうか.
あああ!!!私は見ました.その瞬間です.
ロールバック・ボタンが無効な根本的な理由は、次のとおりです.
xxcregiestというページにはステータスがあります.同じバックグラウンドコード、同じurl、全く異なるフロントviewに対応します.
xxcregiestはRestではありません.つまりloadというurlの場合、バックグラウンドプログラムはpost送信に基づいてforwardがどこへ行くかを決定します.
Bログイン画面->Cログイン確認画面->Dログイン終了画面で、postデータの提出を2回行いました.また、システムはtokenを使用して重複コミットを回避します.
すなわち,2回のpostデータコミットの過程は不可逆的である.最後に、ロールバックボタンをクリックすると、単純にデータチェーン全体の最後のpostを繰り返し提出するだけで、必ず失敗します.
 
[対応]
最初に私が考えた方法は、formが提出したjsの中で、バックグラウンドJsInterfaceのコードを呼び出して、webViewをすることです.clearHistory().
これにより、戻りたくない画面を前画面に提出する前にwebViewの履歴をすべてクリアします.
しかし、clearHistoryは現在の画面の初期化が完了してからしか有効ではないことが分かった.
       
最後に,簡単に有効なのは,現在のkeydownイベントを捉え,その中で現在のURLに基づいて画面の遷移を死判することである.
簡単に言えば、Web画面全体のバックフローを書き換える.
コードの例:
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (webViewUrl == null) {
            return super.onKeyDown(keyCode, event);
        }

        try {
            switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:

                 //    url            	
            	String currentUrl = webView.getUrl();
                 //          
            	if (currentUrl.indexOf("xxx_regist") != -1) {
            		return true;
            	} else if (currentUrl.indexOf("list") != -1) {
            		webView.clearHistory();
            		webView.loadUrl(this.getResources().getString(R.string.top_page));
                    return true;
            	}
                //     ,  webView    
                if (webView.canGoBack()) {
                    webView.goBack();
                    return true;
                } else {
                   //      back url,     ,         
                   if (webViewUrl.equals(this.getResources().getString(R.string.top_page))) {
                        DialogFactory.exitApplicationDialog(this).show();
                        return false;
                    }                 
                   }
        } catch (Exception e) {
        }
        return super.onKeyDown(keyCode, event);
    }

 
#以上#