Android Webview:navigator.geolocation API 不起作用,抛出异常POSITION_



我正在尝试将Web应用程序嵌入到Android Webview中。我的 Web 应用程序使用 HTML5 地理位置 API 来获取用户的当前位置。现在我们正在尝试创建一个Android应用程序,该应用程序在Web视图中打开它,用户也可以从移动应用程序执行相同的操作。 在Webview中,我们无法看到任何类型的消息,其中用户要求允许或拒绝,正如我们在浏览器中看到的那样,它抛出错误POSITION_UNAVAILABLE.

与地理位置 API 相关的 Web 应用程序 JS 代码

// Geolocation fetch function for getting value 
function fetchGeoLocationFunction(result){
if(result ==  true){
// reset the search location to initiate with the new process
resetAddressSelection();
if (navigator.geolocation){            
navigator.geolocation.getCurrentPosition(showPosition,showError);
}
else {
var msgToDisplay = 'Geolocation is not supported by your browser or device, Please try with any latest popular browser';
CreatePopupMessage(false,msgToDisplay,'Not Supported',false);            
}
}
}
function showPosition(position){   
var attempt = 1;
convertGeoCordstoAddress(position.coords.latitude,position.coords.longitude,attempt);
}
function showError(error){
showProcessingBar(); // Show the Processing Bar
setTimeout(function(){
hideProcessingBar();
console.log('Its in failure',error.code);
var err_Msg = '';
switch(error.code){    
case error.PERMISSION_DENIED:
err_Msg = 'You have denied the Request for your Geo location, without that You can't proceed further. Please allow this operation from your browser settings'
break;
case error.POSITION_UNAVAILABLE:
err_Msg ='Location information is unavailable. please try after some time'
break;
case error.TIMEOUT:
err_Msg ='The request to get user location timed out.Please try again'
break;
case error.UNKNOWN_ERROR:
err_Msg ='An unknown error occurred. if the error is repetative, please contact to application provider'
break;
}   
if(err_Msg == ''){
err_Msg  = 'An Error Occured, Contact to Application provider';
}
//alert(err_Msg);
CreatePopupMessage(false,err_Msg,'',true);   
},500);  
}

这是我的安卓应用程序代码开始

安卓应用代码

主要活动.java

package com.example.timedin;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import android.provider.Settings;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.Manifest;
public class MainActivity extends AppCompatActivity {
private WebView webView;
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
private int webViewPreviousState;
private final int PAGE_STARTED = 0x1;
private final int PAGE_REDIRECTED = 0x2;
private CoordinatorLayout rootView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// webview initilization
webView = (WebView) findViewById(R.id.webview);
webView.setWebViewClient(new GeoWebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAppCacheEnabled(false);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setGeolocationEnabled(true);
/// Below required for geolocation
webView.setWebChromeClient(new GeoWebChromeClient());
webView.getSettings().setGeolocationDatabasePath(getFilesDir().getPath());
webView.loadUrl("<my_webapp_url>");
}
/**
* WebChromeClient subclass handles UI-related calls
* Note: think chrome as in decoration, not the Chrome browser
*/
public class GeoWebChromeClient extends android.webkit.WebChromeClient {
@Override
public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) {
// permission and the user has therefore already granted it
callback.invoke(origin, true, false);
}
}
/**
* WebViewClient subclass loads all hyperlinks in the existing WebView
*/
public class GeoWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// When user clicks a hyperlink, load in the existing WebView
view.loadUrl(url);
return true;
}
Dialog loadingDialog = new Dialog(MainActivity.this);
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewPreviousState = PAGE_STARTED;
//CookieManager.getInstance().removeAllCookies(null);
if (loadingDialog == null || !loadingDialog.isShowing())
loadingDialog = ProgressDialog.show(MainActivity.this, "",
"Loading Please Wait", true, true,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// do something
}
});
loadingDialog.setCancelable(false);
}

@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onReceivedError(WebView view, WebResourceRequest request,
WebResourceError error) {

if (isConnected()) {
final Snackbar snackBar = Snackbar.make(rootView, "onReceivedError : " + error.getDescription(), Snackbar.LENGTH_INDEFINITE);
snackBar.setAction("Reload", new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.loadUrl("javascript:window.location.reload( true )");
}
});
snackBar.show();
} else {
final Snackbar snackBar = Snackbar.make(rootView, "No Internet Connection ", Snackbar.LENGTH_INDEFINITE);
snackBar.setAction("Enable Data", new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivityForResult(new Intent(Settings.ACTION_WIRELESS_SETTINGS), 0);
webView.loadUrl("javascript:window.location.reload( true )");
snackBar.dismiss();
}
});
snackBar.show();
}
super.onReceivedError(view, request, error);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onReceivedHttpError(WebView view,
WebResourceRequest request, WebResourceResponse errorResponse) {
if (isConnected()) {
final Snackbar snackBar = Snackbar.make(rootView, "HttpError : " + errorResponse.getReasonPhrase(), Snackbar.LENGTH_INDEFINITE);
snackBar.setAction("Reload", new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.loadUrl("javascript:window.location.reload( true )");
}
});
snackBar.show();
} else {
final Snackbar snackBar = Snackbar.make(rootView, "No Internet Connection ", Snackbar.LENGTH_INDEFINITE);
snackBar.setAction("Enable Data", new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivityForResult(new Intent(Settings.ACTION_WIRELESS_SETTINGS), 0);
webView.loadUrl("javascript:window.location.reload( true )");
snackBar.dismiss();
}
});
snackBar.show();
}
super.onReceivedHttpError(view, request, errorResponse);
}
@Override
public void onPageFinished(WebView view, String url) {
if (webViewPreviousState == PAGE_STARTED) {
if (null != loadingDialog) {
loadingDialog.dismiss();
loadingDialog = null;
}
}
}
}

/**
* Check if there is any connectivity
*
* @return is Device Connected
*/
public boolean isConnected() {
ConnectivityManager cm = (ConnectivityManager)
this.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null != cm) {
NetworkInfo info = cm.getActiveNetworkInfo();
return (info != null && info.isConnected());
}
return false;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<String, Integer>();
// Initial
perms.put(android.Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);

// Fill with results
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for ACCESS_FINE_LOCATION
if (perms.get(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED

) {
// All Permissions Granted
// Permission Denied
Toast.makeText(MainActivity.this, "All Permission GRANTED !! Thank You :)", Toast.LENGTH_SHORT)
.show();
} else {
// Permission Denied
Toast.makeText(MainActivity.this, "One or More Permissions are DENIED Exiting App :(", Toast.LENGTH_SHORT)
.show();
finish();
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@TargetApi(Build.VERSION_CODES.M)
private void fuckMarshMallow() {
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
if (!addPermission(permissionsList, android.Manifest.permission.ACCESS_FINE_LOCATION))
permissionsNeeded.add("Show Location");
if (permissionsList.size() > 0) {
if (permissionsNeeded.size() > 0) {
// Need Rationale
String message = "App need access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
}
});
return;
}
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
return;
}
Toast.makeText(MainActivity.this, "No new Permission Required- Launching App .You are Awesome!!", Toast.LENGTH_SHORT)
.show();
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(MainActivity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
@TargetApi(Build.VERSION_CODES.M)
private boolean addPermission(List<String> permissionsList, String permission) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

安卓清单.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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" />

因此,每次我在android Webview中运行该应用程序时,它都没有问任何事情,它只是向我显示带有错误的弹出消息,POSITION_UNAVAILABLEJS代码中的错误,这给出了错误Location information is unavailable. please try after some time

我尝试了其他代码逻辑并阅读了其他各种答案,但没有一个有效。我目前正在使用android pie版本进行测试,但也尝试了其他版本,但它不起作用。

让我们检查调用它时问题的权限代码。 我不知道你为什么以这种方式调用许可,因为我们有很多媒介,你可以很容易地调用它。让我们使用 nabinbhandari/Android-Permissions,它很容易使用。

以这种方式调用:

@Override
protected void onCreate(Bundle savedInstanceState) {
.....................

String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, 
Manifest.permission.ACCESS_COARSE_LOCATION};
Permissions.check(this/*context*/, permissions, null/*rationale*/, null/*options*/, new 
PermissionHandler() {
@Override
public void onGranted() {
// call your task
// webview initilization
webView = (WebView) findViewById(R.id.webview);
webView.setWebViewClient(new GeoWebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAppCacheEnabled(false);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setGeolocationEnabled(true);
/// Below required for geolocation
webView.setWebChromeClient(new GeoWebChromeClient());
webView.getSettings().setGeolocationDatabasePath(getFilesDir().getPath());
webView.loadUrl("<my_webapp_url>");

}
@Override
public void onDenied(Context context, ArrayList<String> deniedPermissions) {
// permission denied, block the feature.
Toast.makeText(this,"Permission denied",Toast.LENGTH_SHORT);
}
});

或者根据您的需要实现这些权限覆盖功能。

您似乎没有请求运行时权限。使用类似这样的东西:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
// MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
}

有关详细信息,请查看 https://developer.android.com/training/permissions/usage-notes.html。

最新更新