質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

Android WebView <a>タグ内のURLが変動してしまう

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 564
退会済みユーザー

退会済みユーザー

いつもお世話になってます。

Google Mapsを使用した地図アプリを作成しているのですが、
WebViewで原因がわからないところがあり、質問させていただきます。

期待動作は、以下の通りです。
① HTMLのaタグより 「http://XXXXX/latlng/緯度/経度/タイトル」 のリンクをタップ
② MapsActivityへ遷移してマーカーを表示

上記、一度目は成功しますが、以下の手順を踏むとアプリが最終的に落ちてしまいます。
① Markerをタップし、タイトルを表示させる
② 端末の戻るボタンを押下
③ 再度WebView内のリンクを押下
④ Markerがどこかの海に置かれ、タイトルが表示されない 
⑤ 端末の戻るボタンを押下
⑥ 再度WebView内のリンクを押下
⑦ アプリが落ちる

各々のタイミングでのログは以下です。

//① Markerをタップし、タイトルを表示させる
$adb logcat | grep URLCHECKER
--------------------------------
07-03 09:48:26.316 31516 31516 D URLCHECKER: 41.40360905003219/2.174338884964473/サクラダファミリア
07-03 09:48:26.316 31516 31516 D URLCHECKER: 41.40360905003219
07-03 09:48:26.316 31516 31516 D URLCHECKER: 2.174338884964473
07-03 09:48:26.316 31516 31516 D URLCHECKER: サクラダファミリア
--------------------------------
//④ Markerがどこかの海に置かれ、タイトルが表示されない 
$adb logcat | grep URLCHECKER
--------------------------------
07-03 09:48:32.317 31516 31516 D URLCHECKER: 452/2.174338884964473/サクラダファミリア
07-03 09:48:32.317 31516 31516 D URLCHECKER: 452
07-03 09:48:32.317 31516 31516 D URLCHECKER: 2.174338884964473
07-03 09:48:32.317 31516 31516 D URLCHECKER: サクラダファミリア
--------------------------------
//⑦ アプリが落ちる
$adb logcat | grep URLCHECKER
--------------------------------
07-03 09:48:38.149 31516 31516 D URLCHECKER: .174338884964473/サクラダファミリア
07-03 09:48:38.150 31516 31516 D URLCHECKER: .174338884964473
07-03 09:48:38.150 31516 31516 D URLCHECKER: サクラダファミリア
--------------------------------

このように 
log1 では正常に値の取得ができています。
log2 では緯度が「452」になってしまいます。
log3 では経度の小数点以降のみ取得されます。

予測としては、タイトル(サクラダファミリア)は変動していないので、
URLに小数点が入っているからこの現象がおこるのかなとも思いますが、
仕様としてURLのは変更することが許されません。

どうすれば良いでしょうか。。。

ちなみに、以下がコードになります。

//test.html
<a href="http://XXXXX/latlng/41.40360905003219/2.174338884964473/サクラダファミリア">地図上で確認</a>
//TestActivity
public class Test1Activity extends AppCompatActivity {

    private WebView webView;
    private int urlIndex;
    String[] map_info;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_column1);

        showWebView();

        intent_maps();

    }




    /**
     * 端末の戻るボタンでブラウザバック
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);

    }





    /**
     * webviewを表示
     */
    void showWebView() {

        webView = findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());

        /*----------
         WEB_URL => どこに向けるか
         ------------*/
        String WEB_URL = "http://XXXX/YYYYY/ZZZZ";

        //URLをlat,lng,titleにseparateするのに必要
        urlIndex = WEB_URL.length();

        webView.loadUrl(WEB_URL);
        webView.getSettings().setJavaScriptEnabled(true);

    }





    /**
     * 1. WebViewから、aタグのURL(文字列)を取得
     * 2. 遷移させるか否かはboolで判定
     *    => trueで遷移させない
     *    => falseで遷移させる
     * 3. separate_url() でURLをlat,lng,titleに分割
     *    separate_url() でmap_infoに情報を格納
     * 4. map_infoをMapsActivityに渡してMarkerを表示
     *    -----------------------
     *   map_info[0] => lat
     *   map_info[1] => lng
     *   map_info[2] => title
     *    -----------------------
     */
    private void intent_maps() {

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if(separate_url(url)){


                    Log.d("CHECKURL",map_info[0]);
                    Log.d("CHECKURL",map_info[1]);
                    Log.d("CHECKURL",map_info[2]);

                    Intent intent = new Intent(TestActivity.this, MapsActivity.class);

                    /*----------
                     flag 「2」を渡すことでTestActivityから遷移していることを識別する
                     ------------*/
                    intent.putExtra("flag",2);
                    intent.putExtra("fromColumn",map_info);
                    startActivity(intent);

                    return true;
                }else{
                    return false;
                }
            }
        });

    }




    /**
     * 1. urlに/latlng/ が含まれているか確認。
     * 2. latlang/ より前の文字列を削除
     *
     * @param url 
     * @return bool
     */
    private boolean separate_url(String url) {

        /*-----------
          URLに/latlng/があれば「map_info」にlat,lng,titleを配列で保持
          返り値はtrue
         -------------*/
        if(url.contains("/latlng/")) {

            String decodedUrl = decodeUrl(url);

            String url_ltlg = "latlng/";
            urlIndex += url_ltlg.length();

            String substrUrl = decodedUrl.substring(urlIndex);
            map_info = substrUrl.split("/");

            return true;
        }

        return false;

    }




    /**
     * URLをデコード
     * @param url
     * @return
     */
    private String decodeUrl(String url) {

        try {
            String decodedUrl = URLDecoder.decode(url, "UTF-8");

            return decodedUrl;
        }catch (UnsupportedEncodingException e) {

            return "Cannot decode";
        }

    }

}

お力をお貸ししていただけますと幸いです。
何卒、よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

URLが変動するのではなく、URLをsplitする際の文字列のカウント方法が不具合を引き起こす原因でした。

Androidでは、Activityを被せていくようなので
端末の戻るボタンを押下した時に、Activityが初期化されるわけではなく、
前の状態を引き継いでいたので、private int urlIndex; が値を保持していたことにより
「latlng/(7文字)」分が2回め、3回めとプラスされていたので
String[] map_infoの緯度経度の値が変わっていたためでした。

お騒がせいたしました。

//TestActivity
public class Test1Activity extends AppCompatActivity {

    private WebView webView;
    private String web_url; //<------------変更
    String[] map_info;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_column1);

        showWebView();

        intent_maps();

    }




    /**
     * 端末の戻るボタンでブラウザバック
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);

    }





    /**
     * webviewを表示
     */
    void showWebView() {

        webView = findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());

        /*----------
         WEB_URL => どこに向けるか
         ------------*/
        web_url = "http://XXXX/YYYYY/ZZZZ"; // <------------変更

        webView.loadUrl(WEB_URL);
        webView.getSettings().setJavaScriptEnabled(true);

    }





    /**
     * 1. WebViewから、aタグのURL(文字列)を取得
     * 2. 遷移させるか否かはboolで判定
     *    => trueで遷移させない
     *    => falseで遷移させる
     * 3. separate_url() でURLをlat,lng,titleに分割
     *    separate_url() でmap_infoに情報を格納
     * 4. map_infoをMapsActivityに渡してMarkerを表示
     *    -----------------------
     *   map_info[0] => lat
     *   map_info[1] => lng
     *   map_info[2] => title
     *    -----------------------
     */
    private void intent_maps() {

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if(separate_url(url)){


                    Log.d("CHECKURL",map_info[0]);
                    Log.d("CHECKURL",map_info[1]);
                    Log.d("CHECKURL",map_info[2]);

                    Intent intent = new Intent(TestActivity.this, MapsActivity.class);

                    /*----------
                     flag 「2」を渡すことでTestActivityから遷移していることを識別する
                     ------------*/
                    intent.putExtra("flag",2);
                    intent.putExtra("fromColumn",map_info);
                    startActivity(intent);

                    return true;
                }else{
                    return false;
                }
            }
        });

    }




    /**
     * 1. urlに/latlng/ が含まれているか確認。
     * 2. latlang/ より前の文字列を削除
     *
     * @param url 
     * @return bool
     */
    private boolean separate_url(String url) {

        /*-----------
          URLに/latlng/があれば「map_info」にlat,lng,titleを配列で保持
          返り値はtrue
         -------------*/
        if(url.contains("/latlng/")) {

            String decodedUrl = decodeUrl(url);

            String url_ltlg = "latlng/";
            int urlNum = web_url.length() + url_ltlg.length(); //<------------変更

            String substrUrl = decodedUrl.substring(urlIndex); //<------------変更
            map_info = substrUrl.split("/");

            return true;
        }

        return false;

    }




    /**
     * URLをデコード
     * @param url
     * @return
     */
    private String decodeUrl(String url) {

        try {
            String decodedUrl = URLDecoder.decode(url, "UTF-8");

            return decodedUrl;
        }catch (UnsupportedEncodingException e) {

            return "Cannot decode";
        }

    }

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る