Android WebView(SDKバージョン24を使用))で利用可能なHTML Geolocation APIにアクセスしようとしています。
主な問題は、JavaScriptでのnavigator.geolocation.getCurrentPosition()
の呼び出しが(エラーも位置データもない)を返さないことです。アプリケーション側では、権限を確認し、_Android.webkit.GeolocationPermissions.Callback
_クラスを使用してWebViewに適切に渡します。
UPDATE:ここで明確にするために、「決して戻らない」とは、あまりにも提供されたコールバックnavigator.geolocation.getCurrentPosition(success, error)
が呼び出されないことを意味します。
これをテストするために作成したサンプルアプリ(WebViewをホストする1つの小さなアクティビティのみ)で、マニフェストで権限を宣言し、アプリの起動時に適切にリクエストします。プロンプトが表示され、位置情報へのアクセスを許可または拒否できます。
マニフェスト:
_<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
コントロールでWebページを開こうとします。設定で必要なすべてのオプションを有効にします。
_ mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setAppCacheEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setGeolocationEnabled(true);
mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebSettings.setSupportZoom(true);
_
JavaScriptからの位置情報要求を処理するために、次のWebChromeClient
オーバーロードを使用します。
_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);
}
_
JavaScriptのtonavigator.geolocation.getCurrentPosition(success, error)
の呼び出しがを返さないことがわかります。 JavaのonGeolocationPermissionsShowPrompt()
メソッドが適切に呼び出され、そこでアクセス許可を確認すると、常に結果0、つまり_PackageManager.PERMISSION_GRANTED
_が得られるので、callback.invoke(Origin, true, true)
はすべての呼び出しで実行されます。数回試行すると、my Javaコードへの呼び出しがいくつか表示されます。それでも、invoke()
。
記述されているように、GeolocationPermissions
クラスのgetOrigins(ValueCallback<Set<String>> callback)
の呼び出しを使用して、許可されている権限を確認するコードを追加しました ここではドキュメント 。コールバックで、オリジンが場所をリクエストできることを確認しました(これらはセットにリストされています)。
ここで何が間違っているのでしょうか?
タイムアウトを設定するオプションを試してください( ソース ):
var options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.getCurrentPosition(success, error, options);
失敗した場合は、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);
}
}
})();
3番目のオプションとして、EmbeddedChromeClientで@JavascriptInterface( source )で注釈を付けます。
また、コードの適切な場所に追加します。
mWebSettings.setJavaScriptEnabled(true);
//...
mWebSettings.setSupportZoom(true);
webView.addJavascriptInterface(new EmbeddedChromeClient(webView), "injectedObject");
webView.loadData("html here", "text/html", null);
最後のオプションは、htmlでタグを使用し、ディスクストレージからhtmlをロードし、呼び出し元の関数でタグを置き換え、html/stringをwebViewにロードすることです。 Androidでこのアプローチを以前に使用したことがあるので、ポジショニングが私を苛立たせすぎた場合。httpsについても心配する必要はありません。
あなたの場合には2つの異なる問題があるようです:
getCurrentPosition
失敗しないgetCurrentPosition
成功しない最初のポイントは、 method に無限の timeout があるためである可能性があります
デフォルト値はInfinityです。つまり、getCurrentPosition()は、位置が利用可能になるまで戻りません。
2番目の点は注意が必要です。param maximumAge があり、これは
PositionOptions.maximumAgeプロパティは正のlong値であり、返されることが許容されるキャッシュ可能な位置の最大経過時間(ミリ秒)を示します。 0に設定されている場合、デバイスはキャッシュされた位置を使用できず、実際の現在位置を取得する必要があることを意味します。 Infinityに設定した場合、デバイスは経過時間に関係なく、キャッシュされた位置を返す必要があります。
0
デフォルトでは、デバイスはキャッシュされた位置を使用せず、実際の位置をフェッチしようとします。これは、長い応答の問題になる可能性があります。
また、このAPIがAndroidではうまく機能しないことを意味する可能性があるこのレポートを確認することもできます: https://github.com/ionic-team/ionic-native/issues/1958https://issues.Apache.org/jira/browse/CB-13241
* Cordovaは地理位置情報をブラウザに残します。
実際、navigator
はブラウザのグローバルオブジェクトwindow
の子です。最初に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以降SDK(APIレベル> Build.VERSION_CODES.M)をターゲットとするアプリケーションの場合、メソッド onGeolocationPermissionsShowPrompt (String Origin, GeolocationPermissions.Callback callback)
は、HTTPSなどの安全なオリジンから発信されたリクエストに対してのみ呼び出されます。安全でないオリジンでは、ジオロケーション要求は自動的に拒否されます。
メソッド内にブレークポイントまたはログを配置しようとした場合は、自分で問題を絞り込むことができます。
このような許可のリクエストを変更し、
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},0);
これは動作するようです。
このテーマに関する広範な投稿があります:
navigator.geolocation.getCurrentPositionが機能する場合もあれば機能しない場合もあります
どうやら解決策はnavigator.geolocation
次に呼び出しを行います:
if(navigator.geolocation) { // dummy call
navigator.geolocation.getCurrentPosition(success, error)
}