навигатор.геолокация.getCurrentPosition () никогда не возвращается в WebView на Android
я пытаюсь получить доступ к API геолокации HTML, доступному в Android WebView (используя SDK версии 24).
главная проблема в том, что вызов navigator.geolocation.getCurrentPosition()
в JavaScript никогда не возвращает (ни с ошибкой, ни с данными о положении), в то время как на стороне приложения я проверяю разрешения и правильно передаю их в WebView, используя android.webkit.GeolocationPermissions.Callback
класса.
обновление: просто чтобы уточнить здесь, под "никогда не возвращается" я имею в виду, что ни один из поставляемые обратные вызовы navigator.geolocation.getCurrentPosition(success, error)
когда-нибудь.
в примере приложения, которое я построил, чтобы проверить это (только с одним небольшим хостингом активности WebView), я объявляю разрешения в манифесте и запрашиваю их должным образом при запуске приложения. Я вижу приглашение и могу предоставить или запретить разрешение на информацию о местоположении.
Манифест:
<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()
и я вижу, что соответствующие разрешения для моего приложения.
затем я пытаюсь открыть веб-страницы WebView
управление.
Я включаю все необходимые параметры в настройках:
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setAppCacheEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setGeolocationEnabled(true);
mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebSettings.setSupportZoom(true);
я использую следующие WebChromeClient
перегрузка для обработки запросов геолокации из 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, укорачиваются здесь):
function geoFindMe() {
function success(position) {}
function error() {}
navigator.geolocation.getCurrentPosition(success, error);
}
я вижу, что вызовnavigator.geolocation.getCurrentPosition(success, error)
в JavaScript никогда не возвращает. Я вижу это onGeolocationPermissionsShowPrompt()
метод в Java правильно вызывается, и когда я проверяю разрешения, я всегда получаю результат 0, т. е. PackageManager.PERMISSION_GRANTED
, так что callback.invoke(origin, true, true)
выполняется при каждом вызове. Если я попробую несколько раз, я вижу несколько вызовов моего кода Java. Тем не менее, ничего не происходит на стороне JavaScript здесь после вызова invoke()
.
я добавил код для проверки предоставленных разрешений с помощью вызова getOrigins(ValueCallback<Set<String>> callback)
на GeolocationPermissions
класс, как описано здесь в документации. Я вижу в обратном вызове, что моим источникам разрешено запрашивать местоположения (они перечислены в наборе).
есть идеи, что здесь может быть не так?
6 ответов
попробуйте с параметрами, чтобы установить тайм-аут (источник):
var options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.getCurrentPosition(success, error, options);
Если это не удается, попробуйте переопределить getCurrentPosition (источник):
(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
добавить в нужное место в коде:
mWebSettings.setJavaScriptEnabled(true);
//...
mWebSettings.setSupportZoom(true);
webView.addJavascriptInterface(new EmbeddedChromeClient(webView), "injectedObject");
webView.loadData("html here", "text/html", null);
последний вариант - просто использовать теги в html, загружать html из дискового хранилища, заменять теги в вызове функция, загрузите html / строку в webView. Я использовал этот подход раньше в Android, когда позиционирование расстраивало меня слишком много. Тогда вам не придется беспокоиться ни о https.
похоже, что в вашем случае есть 2 разных проблемы:
-
getCurrentPosition
никогда не -
getCurrentPosition
никогда не удастся
первый пункт может быть просто потому, что метод бесконечно автоотключение
значение по умолчанию-Infinity, что означает, что getCurrentPosition () не вернется, пока позиция не будет доступна.
второй пункт может быть сложным, есть парам maximumAge что означает
PositionOptions.свойство maximumAge-положительное длинное значение, указывающее максимальный возраст в миллисекундах возможной кэшированной позиции, приемлемой для возврата. Если задано значение 0, это означает, что устройство не может использовать кэшированную позицию и должно попытаться получить реальную текущую позицию. Если задано значение Infinity, устройство должно возвращать кэшированную позицию независимо от ее возраста.
0
по умолчанию означает это устройство не будет использовать кэшированную позицию и попытается получить реальную, и это может быть проблемой для длительного ответа.
также вы можете проверить эту сообщению, которое может означать, что этот API не работает очень хорошо на Андроид: https://github.com/ionic-team/ionic-native/issues/1958 https://issues.apache.org/jira/browse/CB-13241
*Кордова оставляет геолокации материал для браузера.
измените запрос на разрешение следующим образом,
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},0);
Это, кажется, работает.
на самом деле navigator
является дочерним глобальным объектом браузера,window
. вы должны сначала получить доступ к вызов navigator
. В некоторых современных браузерах, помимо window
некоторые дочерний объект представлен как глобальный объект, например: location
, navigator
и т. д.
на WebView
не имеет глобального объекта window
. Так что вы можете добавить его вручную, для этого действия, пожалуйста, прочитайте эта среда статьи.
возможно, ваш код будет похож ниже:
my_web_view.evaluateJavascript("javascript: " + "updateFromAndroid(\"" + edit_text_to_web.text + "\")", null);
а затем добавить JavaScript
интерфейс, как window
объект, к этой оценке:
my_web_view.addJavascriptInterface(JavaScriptInterface(), JAVASCRIPT_OBJ); //JAVASCRIPT_OBJ: like window, like navigator, like location and etc.
для приложения Android N и более поздние версии SDKs (уровень API > сборка.VERSION_CODES.М), метод onGeolocationPermissionsShowPrompt (String origin, GeolocationPermissions.Callback callback)
вызывается только для запросов, исходящих из безопасных источников, таких как HTTPS. В незащищенных источниках запросы геолокации автоматически отклоняются.
вы могли бы сузить свою проблему самостоятельно, если бы вы попытались поместить точку останова или журнал внутри метода.
у вас есть два опции:
- цель API более низкого уровня, что, очевидно, намного проще, но не очень ценится.
- настройка SSL на вашем веб-сайте.
есть обширный пост на эту тему:
навигатор.геолокация.getCurrentPosition иногда работает иногда не
очевидно, решением является проверка на navigator.geolocation
затем звоните:
if(navigator.geolocation) { // dummy call
navigator.geolocation.getCurrentPosition(success, error)
}