navigator.geolocation.getCurrentPosition()永远不会在Android的WebView中返回 [英] navigator.geolocation.getCurrentPosition() never returns in WebView on Android

查看:299
本文介绍了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进行注释(

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中返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆