A
A
Alexander Urich2018-06-15 17:10:00
JavaScript
Alexander Urich, 2018-06-15 17:10:00

How to pass coordinates from Webview to get them in JavaScript?

I am developing a mobile application based on Webview.
It uses a map on which you need to determine the user's coordinates to show the nearest stores.
Here is the code how I did it:

spoiler
MainActivity.java
package com.my.app;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.GeolocationPermissions;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    WebView webView;
    private Activity activity;
    private SwipeRefreshLayout swipe;

    public MainActivity()
    {
        activity = this;
    }

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = (WebView) findViewById(R.id.webView);
        webView.clearHistory();
        webView.clearMatches();

        // Свайп
        swipe = (SwipeRefreshLayout) findViewById(R.id.swipe);
        swipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            // Слушаем событие обновления свайпом
            @Override
            public void onRefresh() {
                // При событии обновлении свайпом обновляем вебвью
                webView.reload();
            }
        });
        WebSettings webSettings = webView.getSettings();
        // Включаем js
        webSettings.setJavaScriptEnabled(true);

        // Вроде должно передавать гео локацию
        webSettings.setGeolocationEnabled(true);

        webView.setWebChromeClient(new WebChromeClient() {

            @Override
            public boolean onConsoleMessage(ConsoleMessage cm)
            {
                Log.d("CONTENT", String.format("%s @ %d: %s",
                        cm.message(), cm.lineNumber(), cm.sourceId()));
                return true;
            }

            // Тоже что-то для геолокации
            @Override
            public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                callback.invoke(origin, true, false);
            }

            // Переопределяет JS функции
            @Override
            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                // Заменяет JS-овский alert на диалог андройда с одной кнопкой
                new AlertDialog.Builder(activity)
                    .setTitle(android.R.string.dialog_alert_title)
                    .setMessage(message)
                    .setPositiveButton(
                        android.R.string.ok,
                        new DialogInterface.OnClickListener()
                        {
                            public void onClick(DialogInterface dialog, int which)
                            {
                                result.cancel();
                            }
                        }
                    )
                    .create()
                    .show();
                return true;
            }
            @Override
            public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
                // Заменяет JS-овский диалог (confirm) на диалог андройда
                new AlertDialog.Builder(activity)
                    .setTitle(R.string.dialog_title)
                    .setMessage(message)
                    .setPositiveButton(
                        android.R.string.ok,
                        new DialogInterface.OnClickListener()
                        {
                            public void onClick(DialogInterface dialog, int which)
                            {
                                result.confirm();
                            }
                        }
                    )
                    .setNegativeButton(
                        android.R.string.cancel,
                        new DialogInterface.OnClickListener()
                        {
                            public void onClick(DialogInterface dialog, int which)
                            {
                                result.cancel();
                            }
                        }
                    )
                    .create()
                    .show();
                return true;
            }
        });
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                if (url.contains("/stores")) {
                    Log.d("CONTENT", "Access location");
                    ActivityCompat.requestPermissions(activity, new String[]{
                        android.Manifest.permission.ACCESS_FINE_LOCATION
                    }, 0);
                }
                swipe.setRefreshing(false);
                MainActivity.this.setTitle(view.getTitle());
                if (findViewById(R.id.splach_screen).getVisibility() == View.VISIBLE) {
                    // show webview
                    findViewById(R.id.main_view).setVisibility(View.VISIBLE);
                    // hide splash screen
                    findViewById(R.id.splach_screen).setVisibility(View.GONE);
                }
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView webView, String url) {
                // все ссылки, в которых содержится домен
                // будут открываться внутри приложения
                if (url.contains(getString(R.string.main_url_domain))) {
                    return false;
                }
                // все остальные ссылки будут спрашивать какой браузер открывать
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                activity.startActivity(intent);
                return true;
            }

            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                // При ошибке HTTP (не 5хх)
                // Очистим историю просмотров
                webView.clearHistory();
                // Покажем HTML заглушку
                webView.loadUrl("file:///android_asset/error.html");
            }
        });
        // Формируем УРЛ из схемы и домена
        String urlAddress = getString(R.string.main_url_schema) + "://" + getString(R.string.main_url_domain);
        webView.loadUrl(urlAddress);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && this.webView.canGoBack()) {
            this.webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.my.app">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.my.app.MainActivity"
            android:screenOrientation="portrait">
            <!--<intent-filter>-->
                <!--<action android:name="android.intent.action.MAIN" />-->
                <!--<category android:name="android.intent.category.LAUNCHER" />-->
            <!--</intent-filter>-->
        </activity>
        <activity
            android:name="com.my.app.SplashActivity"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


В JS получаю так (использую Vue2):
if ("geolocation" in window.navigator) {
    this.addMessage('Geo FIND!!');
    navigator.geolocation.getCurrentPosition(position => {
        this.addMessage('Success get geo: LAT: ' + position.coords.latitude + '; LON: ' + position.coords.longitude);
        this.centerLat = position.coords.latitude;
        this.centerLon = position.coords.longitude;
        this.getStores();
    }, error => {
        this.addMessage('GEO error: ' + error);
        console.log('Error', error);
    });
} else {
    this.addMessage('Eror get geo');
    this.initMap();
}

Условие if ("geolocation" in window.navigator) срабатывает. Но вот ни ошибки ни результата от navigator.geolocation.getCurrentPosition нет

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander Urich, 2018-06-21
@Urichalex

I don't know how it worked. Magic

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question