Question

I have a webpage with a WatchPosition call which works fine in regular browsers. However, the dialog for requesting GPS Permission never shows when the webpage is loaded from a WebView with WebChromeClient and onGeolocationPermissionsShowPrompt is never called.

public class GeoWebChromeClient extends WebChromeClient {
     public void onGeolocationPermissionsShowPrompt(String origin, android.webkit.GeolocationPermissions.Callback callback) {
         Log.d("geolocation permission", "permission >>>"+origin);
         callback.invoke(origin, true, false);
     }
}

 public class GeoWebViewClient extends WebViewClient {

    @Override
    public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
        handler.proceed();
    }

    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // When user clicks a hyperlink, load in the existing WebView
        view.loadUrl(url);
        return true;
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView Browser = (WebView) findViewById(R.id.Browser);

    WebSettings webSettings = Browser.getSettings();

    webSettings.setJavaScriptEnabled(true);
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    webSettings.setAppCacheEnabled(true);
    webSettings.setDomStorageEnabled(true);
    webSettings.setGeolocationEnabled(true);

    Browser.setWebViewClient(new GeoWebViewClient());
    Browser.setWebChromeClient(new GeoWebChromeClient());

    Browser.loadUrl("http://192.168.1.102/");


}

<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"/>
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Was it helpful?

Solution

onGeolocationShowPrompt doesn't actually show a prompt itself, it is just a method that gets called when the page requests your Geolocation. You'll need to create your own prompt for the user like shown below (placed inside the onGeolocatioonShowPrompt method):

final boolean remember = true;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Locations");
builder.setMessage(origin + " Would like to use your Current Location").setCancelable(true).setPositiveButton("Allow",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    // origin, allow, remember
                                    callback.invoke(origin, true, remember);
                                }
                            })
                    .setNegativeButton("Don't Allow",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    // origin, allow, remember
                                    callback.invoke(origin, false, remember);
                                }
                            });
AlertDialog alert = builder.create();
alert.show();

OTHER TIPS

For anyone who is looking for how to fix the "onGeolocationPermissionsShowPrompt is never used" message like I was, this should help. If this is your issue it doesn't matter what's put in the method if it's never called.

In your onCreate:

webView = findViewById(R.id.webView);
webView.setWebViewClient(new customWebView());
webView.setWebChromeClient(new customChromeClient());

Custom classes:

private class customChromeClient extends WebChromeClient {
    public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
        callback.invoke(origin, true, false);

        //check for permissions or show your dialog etc
    }
}

//other methods you may want to override
private class customWebView extends WebViewClient {
    @Override
    public void onPageFinished(WebView view, String url) {

    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
        return true;
    }
}

Hopefully this helps someone in future.

Example and where I found the answer: https://gist.github.com/Cheesebaron/ad84740c9bffa7e255c8

Well in case when location is turned off and if website request location then webview call onGeolocationPermissionsShowPrompt but only one time. To make that work, means call onGeolocationPermissionsShowPrompt every time when website request location I did this:

inner class MyChromeClient: WebChromeClient()
    {

        override fun onGeolocationPermissionsShowPrompt(origin: String?, callback: GeolocationPermissions.Callback?) {
            // Geolocation permissions coming from this app's Manifest will only be valid for devices with API_VERSION < 23.
            // On API 23 and above, we must check for permission, and possibly ask for it.
            //callback?.invoke(origin,true,false)

            val permission=Manifest.permission.ACCESS_FINE_LOCATION

            if (Build.VERSION.SDK_INT<Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(applicationContext,permission)==PackageManager.PERMISSION_GRANTED)
            {
                // we're on SDK < 23 OR user has already granted permission
                callback?.invoke(origin,true,false)
            }
            else{

                if (!ActivityCompat.shouldShowRequestPermissionRationale(this@WebViewActivity,permission))
                {
                    // user clicked on don't asked again
                    alert("Allow location permission to access this feature"){
                        yesButton {
                            val intent=Intent()
                            intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                            intent.data= Uri.fromParts("package",packageName,null)
                            startActivity(intent)
                            callback?.invoke(origin,false,false)
                        }
                        noButton {
                            callback?.invoke(origin,false,false)
                        }
                    }.show()
                }
                else{
                    // permission not granted yet
                    this@WebViewActivity.callback=callback
                    this@WebViewActivity.origin=origin
                    ActivityCompat.requestPermissions(this@WebViewActivity, arrayOf(permission),100)
                }
            }
        }
    }

Add onRequestPermissionsResult Code:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (grantResults.isNotEmpty() && requestCode==100)
        {
            if (grantResults[0]==PackageManager.PERMISSION_GRANTED)
            {
                if (callback!=null)
                    callback?.invoke(origin,true,false)
                return
            }
            else{
                callback?.invoke(origin,false,false)
            }
        }
        callback?.invoke(origin,false,false)
    }

The point is, if you want that onGeolocationPermissionsShowPrompt should call again you need to call callback?.invoke(origin,false,false), with these exact value in parameter inside onGeolocationPermissionsShowPrompt

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top