android webview geolocation android webview geolocation android android

android webview geolocation


  • JavaScript must be enabled in the WebView, using WebSettings.setJavaScriptEnabled(true);
  • The app needs permission ACCESS_FINE_LOCATION
  • The WebView must use a custom WebChromeClient which implements WebChromeClient.onGeolocationPermissionsShowPrompt(). This method is called by the WebView to obtain permission to disclose the user's location to JavaScript. (In the case of the browser, we show a prompt to the user.) The default implementation does nothing, so permission is never obtained and the location is never passed to JavaScript. A simple implementation which always grants permission is ...

    webView.setWebChromeClient(new WebChromeClient() { public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {    callback.invoke(origin, true, false); }});

Geolocation uses databases to persist cached positions and permissions between sessions. The location of the database is set using WebSettings.setGeolocationDatabasePath(...). If the location of the database is not set, the persistent storage will not be available, but Geolocation will continue to function correctly otherwise. To set the location of the databases, use ...

webView.getSettings().setGeolocationDatabasePath( context.getFilesDir().getPath() );


Dialog to accept or decline user location is design by programmer :D. As Chris Cashwell said, you just use a callback like this:

webview.setWebChromeClient(new WebChromeClient(){  public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {    // callback.invoke(String origin, boolean allow, boolean remember);    callback.invoke(origin, true, false);  }});

In some cases, HTML5 requires the use of storage, therefore you must enable some properties so that webview has full access to run normal.

    // HTML5 API flags    webView.getSettings().setAppCacheEnabled(true);    webView.getSettings().setDatabaseEnabled(true);    webView.getSettings().setDomStorageEnabled(true);


Sharing my Working activity class, this is a complete solution which can demonstrate

  • Showing loading dialog while the web page is loading
  • Ask for permission in marshmallow and above
  • Handle webpage error
  • Check for the internet connection and open setting page
  • Handling Geolocation permission with and without dialog

Hope, it saves someone's time

    /**     * Created by Hitesh.Sahu on 3/24/2017.     */        public class WebViewActivity extends AppCompatActivity {            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;        private WebView webView;                @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_webview);            webView = (WebView) findViewById(R.id.webView);            rootView = (CoordinatorLayout) findViewById(R.id.root_view);                if (Build.VERSION.SDK_INT >= 23) {                // Marshmallow+ Permission APIs                askRuntimePermission();            }                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {                if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) {                    WebView.setWebContentsDebuggingEnabled(true);                }            }            webView.setInitialScale(1);            webView.getSettings().setLoadWithOverviewMode(true);            webView.getSettings().setUseWideViewPort(true);            webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);            webView.setScrollbarFadingEnabled(false);                webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);            webView.getSettings().setBuiltInZoomControls(true);            webView.setWebViewClient(new GeoWebViewClient());            // Below required for geolocation            webView.getSettings().setJavaScriptEnabled(true);            webView.getSettings().setGeolocationEnabled(true);            webView.setWebChromeClient(new GeoWebChromeClient());                webView.getSettings().setAppCacheEnabled(true);            webView.getSettings().setDatabaseEnabled(true);            webView.getSettings().setDomStorageEnabled(true);                webView.getSettings().setGeolocationDatabasePath(getFilesDir().getPath());                webView.loadUrl("file:///android_asset/index.html");        }            /**         * 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) {                // Always grant permission since the app itself requires location                // permission and the user has therefore already granted it                callback.invoke(origin, true, false);        //            final boolean remember = false;    //            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);    //            builder.setTitle("Locations");    //            builder.setMessage("Would like to use your Current Location ")    //                    .setCancelable(true).setPositiveButton("Allow", new DialogInterface.OnClickListener() {    //                public void onClick(DialogInterface dialog, int id) {    //                    // origin, allow, remember    //                    callback.invoke(origin, true, remember);    //                }    //            }).setNegativeButton("Don't Allow", new DialogInterface.OnClickListener() {    //                public void onClick(DialogInterface dialog, int id) {    //                    // origin, allow, remember    //                    callback.invoke(origin, false, remember);    //                }    //            });    //            AlertDialog alert = builder.create();    //            alert.show();            }        }            /**         * 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(WebViewActivity.this);                @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                super.onPageStarted(view, url, favicon);                webViewPreviousState = PAGE_STARTED;                    if (loadingDialog == null || !loadingDialog.isShowing())                    loadingDialog = ProgressDialog.show(WebViewActivity.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(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(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED                                    ) {                        // All Permissions Granted                            // Permission Denied                        Toast.makeText(WebViewActivity.this, "All Permission GRANTED !! Thank You :)", Toast.LENGTH_SHORT)                                .show();                        } else {                        // Permission Denied                        Toast.makeText(WebViewActivity.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 askRuntimePermission() {            List<String> permissionsNeeded = new ArrayList<String>();                final List<String> permissionsList = new ArrayList<String>();            if (!addPermission(permissionsList, 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(WebViewActivity.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(WebViewActivity.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;        }    }