本文介绍了navigator.geolocation.getCurrentPosition()永远不会在Android的WebView中返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试访问Android WebView中提供的HTML Geolocation API(使用SDK版本24).

I am trying to access the HTML Geolocation API available in Android WebView (using SDK version 24).

主要问题是在JavaScript中对navigator.geolocation.getCurrentPosition()的调用永远不会返回(既不包含错误,也不包含位置数据),而在应用程序端,我检查权限并将其正确传递给使用android.webkit.GeolocationPermissions.Callback类的WebView.

The main problem is that the call to navigator.geolocation.getCurrentPosition() in JavaScript never returns (neither with an error, nor with position data), while on application side I check for permissions and properly pass them to WebView using android.webkit.GeolocationPermissions.Callback class.

更新:在这里要澄清一下,永不返回"表示没有调用过任何提供过的回调navigator.geolocation.getCurrentPosition(success, error).

UPDATE: Just to clarify here, by "never returns" I mean that none of the too supplied callbacks navigator.geolocation.getCurrentPosition(success, error) are ever called.

在构建的示例应用程序中,我对此进行了测试(只有一个托管WebView的小活动),我在清单中声明了权限,并在App启动时正确地请求了这些权限.我看到提示,可以授予或拒绝位置信息的权限.

In a sample app I built to test this (with just one small activity hosting WebView) I declare the permissions in manifest and request them properly on App start. I see the prompt and can grant or deny permission to location information.

清单:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

主要形式的代码:

public boolean checkFineLocationPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {

        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION) && !mIsPermissionDialogShown) {
            showPermissionDialog(R.string.dialog_permission_location);
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSION_ACCESS_FINE_LOCATION);
        }
        return false;
    } else {
        return true;
    }
}

我可以使用Context.checkSelfPermission()在运行时检查权限,并且看到相应的权限已授予我的应用.

I can check for permissions during runtime using Context.checkSelfPermission() and I see that the respective permissions are granted to my app.

然后,我尝试在WebView控件中打开网页.我在设置中启用了所有必需的选项:

Then I try to open a web page in a WebView control.I enable all required options in the settings:

    mWebSettings.setJavaScriptEnabled(true);
    mWebSettings.setAppCacheEnabled(true);
    mWebSettings.setDatabaseEnabled(true);
    mWebSettings.setDomStorageEnabled(true);
    mWebSettings.setGeolocationEnabled(true);
    mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    mWebSettings.setSupportZoom(true);

我使用以下WebChromeClient重载来处理来自JavaScript的地理位置请求:

I use the following WebChromeClient overload for handling geolocation requests from JavaScript:

protected class EmbeddedChromeClient extends android.webkit.WebChromeClient {
    @Override
    public void onGeolocationPermissionsShowPrompt(String origin,
                                                   android.webkit.GeolocationPermissions.Callback callback) {

        // do we need to request permissions ?
        if (ContextCompat.checkSelfPermission(EmbeddedBrowserActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // this should never happen, it means user revoked permissions
            // need to warn and quit?
            callback.invoke(origin, false, false);
        }
        else {
            callback.invoke(origin, true, true);
        }
    }
}

要对此进行测试,我使用以下代码(摘自 Mozilla API帮助页,此处缩短):

To test this I use the following code (taken from Mozilla API help page, shortened here):

function geoFindMe() {
  function success(position) {}
  function error() {}
  navigator.geolocation.getCurrentPosition(success, error);
}

我看到的是在JavaScript中对navigator.geolocation.getCurrentPosition(success, error)的调用永不返回.我看到Java中的onGeolocationPermissionsShowPrompt()方法被正确调用,并且当我在其中检查权限时,我总是得到结果0,即PackageManager.PERMISSION_GRANTED,因此callback.invoke(origin, true, true)在每次调用时都会执行.如果尝试几次,则会看到对Java代码的多次调用.不过,在我调用invoke()之后,JavaScript方面什么也没发生.

What I see is that the call tonavigator.geolocation.getCurrentPosition(success, error) in JavaScript never returns. I see that onGeolocationPermissionsShowPrompt() method in Java gets properly called and as I check for permissions there I always get the result 0, i.e. PackageManager.PERMISSION_GRANTED, so callback.invoke(origin, true, true) is executed on every call. If I try several times, I see several calls to my Java code. Still, nothing happens on the JavaScript side here after I call invoke().

我添加了代码,以使用GeolocationPermissions类中的getOrigins(ValueCallback<Set<String>> callback)调用来检查授予的权限,如文档中的.我在回调函数中看到允许我的来源请求位置(它们在列表中列出).

I added the code to check for granted permissions using the invocation of getOrigins(ValueCallback<Set<String>> callback) in GeolocationPermissions class, as described here in the documentation. I see in the callback that my origins are allowed to request locations (they are listed in the set).

任何想法在这里可能出什么问题吗?

Any ideas what might be wrong here?

推荐答案

尝试使用设置超时的选项():

Try with options to set timeout (source):

var options = {
    enableHighAccuracy: true,
    timeout: 10000,
    maximumAge: 0
};

navigator.geolocation.getCurrentPosition(success, error, options);

如果失败,则尝试覆盖getCurrentPosition():

If it fails then try to override getCurrentPosition (source):

(function() {

if (navigator.geolocation) {
    function PositionError(code, message) {
        this.code = code;
        this.message = message;
    }

    PositionError.PERMISSION_DENIED = 1;
    PositionError.POSITION_UNAVAILABLE = 2;
    PositionError.TIMEOUT = 3;
    PositionError.prototype = new Error();

    navigator.geolocation._getCurrentPosition = navigator.geolocation.getCurrentPosition;

    navigator.geolocation.getCurrentPosition = function(success, failure, options) {
        var successHandler = function(position) {
            if ((position.coords.latitude == 0 && position.coords.longitude == 0) ||
                (position.coords.latitude == 37.38600158691406 && position.coords.longitude == -122.08200073242188))
                return failureHandler(new PositionError(PositionError.POSITION_UNAVAILABLE, 'Position unavailable'));

            failureHandler = function() {};
            success(position);
        }

        var failureHandler = function(error) {
            failureHandler = function() {};
            failure(error);
        }

        navigator.geolocation._getCurrentPosition(successHandler, failureHandler, options);

        window.setTimeout(function() { failureHandler(new PositionError(PositionError.TIMEOUT, 'Timed out')) }, 10000);
    }
}
})();

作为第三个选项,使用@JavascriptInterface进行注释()在EmbeddedChromeClient中

As a third option annotate with @JavascriptInterface (source) in EmbeddedChromeClient

还要在代码中的适当位置添加

Also add at the proper place in your code:

mWebSettings.setJavaScriptEnabled(true);
//...
mWebSettings.setSupportZoom(true);
webView.addJavascriptInterface(new EmbeddedChromeClient(webView), "injectedObject");
webView.loadData("html here", "text/html", null);

最后一个选择就是使用html中的标签,从磁盘存储中加载html,替换调用函数中的标签,在webView中加载html/string.以前,我在Android上使用这种方法时对我的定位感到非常沮丧.然后,您也不必担心https.

The last option is just to use tags in html, load the html from disk storage, replace tags in the calling function, load the html/string in the webView. I have used this approach before in Android when positioning frustrated me too much. Then you don't have to worry about https either.

这篇关于navigator.geolocation.getCurrentPosition()永远不会在Android的WebView中返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 11:49