android webview 地理定位

发布于 2024-10-23 20:59:12 字数 424 浏览 1 评论 0原文

我必须在 WebView 中检索用户的位置。我使用以下 Javascript 执行此操作:

function getLocation() {
   navigator.geolocation.getCurrentPosition(displayLocation, handleError);
}

但权限请求弹出窗口永远不会打开。

我已设置以下设置:

ws.setJavaScriptEnabled(true);
ws.setGeolocationEnabled(true);
ws.setJavaScriptCanOpenWindowsAutomatically(true);

WebView 内访问用户位置的正确方法是什么?

I have to retrieve a user's location in a WebView. I do this with the following Javascript:

function getLocation() {
   navigator.geolocation.getCurrentPosition(displayLocation, handleError);
}

But the permission request popup never opens.

I've set these settings:

ws.setJavaScriptEnabled(true);
ws.setGeolocationEnabled(true);
ws.setJavaScriptCanOpenWindowsAutomatically(true);

What is the correct way to access a user's location from within a WebView?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

小女人ら 2024-10-30 20:59:12
  • 必须在 WebView 中启用 JavaScript,使用 WebSettings.setJavaScriptEnabled(true);
  • 应用需要权限 ACCESS_FINE_LOCATION
  • WebView 必须使用实现 WebChromeClient.onGeolocationPermissionsShowPrompt() 的自定义 WebChromeClient。这个方法
    WebView 调用以获得向 JavaScript 公开用户位置的权限。 (在浏览器的情况下,我们向用户显示提示。)默认实现不执行任何操作,因此永远不会获得权限,并且位置永远不会传递给 JavaScript。始终授予权限的简单实现是...

    webView.setWebChromeClient(new WebChromeClient() {
     公共无效onGeolocationPermissionsShowPrompt(字符串起源,GeolocationPermissions.Callback回调){
        回调.invoke(origin, true, false);
     }
    });
    

地理定位使用数据库在会话之间保留缓存的位置和权限。数据库的位置是使用 WebSettings.setGeolocationDatabasePath(...) 设置的。如果未设置数据库的位置,持久存储将不可用,但地理定位将继续正常运行。要设置数据库的位置,请使用...

webView.getSettings().setGeolocationDatabasePath( context.getFilesDir().getPath() );
  • 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() );
如日中天 2024-10-30 20:59:12

接受或拒绝用户位置的对话框是由程序员设计的:D。正如 Chris Cashwell 所说,你只需使用这样的回调即可:

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);
  }
});

在某些情况下,HTML5 需要使用存储,因此你必须启用一些属性,以便 webview 具有完全访问权限才能正常运行。

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

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);
梓梦 2024-10-30 20:59:12

分享我的工作活动类,这是一个完整的解决方案,可以演示

  • 在网页加载时显示加载对话框
  • 在棉花糖及以上请求权限
  • 处理网页错误
  • 检查互联网连接并打开设置页面
  • 处理带或不带对话框的地理位置权限

希望,它节省了某人的时间

    /**
     * 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;
        }
    }

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;
        }
    }
相守太难 2024-10-30 20:59:12

您是否在清单中声明了该许可?

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

Are you declaring that permission in your manifest?

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

You may also need to declare other location permissions, like these:

<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_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
王权女流氓 2024-10-30 20:59:12

我最近遇到了这种情况,并采取了以下步骤来实现这一目标:

第 1 步:
AndroidManifest.xml 文件中添加权限

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

第 2 步:创建一个包含 WebViewProgressBar 的活动(在我的例子中)

xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="0dp"
        android:minHeight="4dp"
        android:padding="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <WebView
        android:id="@+id/webView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>

步骤 3:在您的活动类中,添加以下代码并根据您的需要进行更改

class WebActivity : AppCompatActivity() {
    var pageUrl: String = "https://couponia.co/"
    var mGeoLocationRequestOrigin: String? = null
    var mGeoLocationCallback: GeolocationPermissions.Callback? = null
    val MAX_PROGRESS = 100
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_web)
        initWebView()
        setWebClient()
        loadUrl(pageUrl)
    }


    @SuppressLint("SetJavaScriptEnabled")
    private fun initWebView() {
        webView.settings.javaScriptEnabled = true
        webView.settings.loadWithOverviewMode = true
        webView.settings.useWideViewPort = true
        webView.settings.domStorageEnabled = true
        webView.settings.databaseEnabled = true
        webView.settings.setAppCacheEnabled(true)
        webView.webViewClient = object : WebViewClient() {
            override
            fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                handler?.proceed()
            }
        }

    }

    private fun setWebClient() {

        webView.webChromeClient = object : WebChromeClient() {
            override fun onGeolocationPermissionsShowPrompt(
                origin: String?,
                callback: GeolocationPermissions.Callback?
            ) {

                if (ContextCompat.checkSelfPermission(
                        this@WebActivity,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    )
                    != PackageManager.PERMISSION_GRANTED
                ) {

                    if (ActivityCompat.shouldShowRequestPermissionRationale(
                            this@WebActivity,
                            Manifest.permission.ACCESS_FINE_LOCATION
                        )
                    ) {
                        AlertDialog.Builder(this@WebActivity)
                            .setMessage("Please turn ON the GPS to make app work smoothly")
                            .setNeutralButton(
                                android.R.string.ok,
                                DialogInterface.OnClickListener { dialogInterface, i ->
                                    mGeoLocationCallback = callback
                                    mGeoLocationRequestOrigin = origin
                                    ActivityCompat.requestPermissions(
                                        this@WebActivity,
                                        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                                    )

                                })
                            .show()

                    } else {
                        //no explanation need we can request the locatio
                        mGeoLocationCallback = callback
                        mGeoLocationRequestOrigin = origin
                        ActivityCompat.requestPermissions(
                            this@WebActivity,
                            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                        )
                    }
                } else {
                    //tell the webview that permission has granted
                    callback!!.invoke(origin, true, true)
                }

            }

            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                super.onProgressChanged(view, newProgress)
                progressBar.progress = newProgress
                if (newProgress < MAX_PROGRESS && progressBar.visibility == ProgressBar.GONE) {
                    progressBar.visibility = ProgressBar.VISIBLE
                }
                if (newProgress == MAX_PROGRESS) {
                    progressBar.visibility = ProgressBar.GONE
                }
            }


        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        // Check if the key event was the Back button and if there's history
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack()
            return true
        }
        // If it wasn't the Back key or there's no web page history, exit the activity)
        return super.onKeyDown(keyCode, event)
    }

    private fun loadUrl(pageUrl: String) {
        webView.loadUrl(pageUrl)
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        when (requestCode) {
            1001 -> {
                //if permission is cancel result array would be empty
                if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //permission was granted
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, true, true)
                    }
                } else {
                    //permission denied
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, false, false)
                    }
                }
            }

        }
    }
}

I have recently come across this type of situation and have done below steps to achieve this:

Step 1:
Add permissions in your AndroidManifest.xml file

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 

Step 2: Create an activity that would contain a WebView and ProgressBar (in my case)

xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="0dp"
        android:minHeight="4dp"
        android:padding="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <WebView
        android:id="@+id/webView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: In your activity class, add below code and make changes according to your need

class WebActivity : AppCompatActivity() {
    var pageUrl: String = "https://couponia.co/"
    var mGeoLocationRequestOrigin: String? = null
    var mGeoLocationCallback: GeolocationPermissions.Callback? = null
    val MAX_PROGRESS = 100
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_web)
        initWebView()
        setWebClient()
        loadUrl(pageUrl)
    }


    @SuppressLint("SetJavaScriptEnabled")
    private fun initWebView() {
        webView.settings.javaScriptEnabled = true
        webView.settings.loadWithOverviewMode = true
        webView.settings.useWideViewPort = true
        webView.settings.domStorageEnabled = true
        webView.settings.databaseEnabled = true
        webView.settings.setAppCacheEnabled(true)
        webView.webViewClient = object : WebViewClient() {
            override
            fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                handler?.proceed()
            }
        }

    }

    private fun setWebClient() {

        webView.webChromeClient = object : WebChromeClient() {
            override fun onGeolocationPermissionsShowPrompt(
                origin: String?,
                callback: GeolocationPermissions.Callback?
            ) {

                if (ContextCompat.checkSelfPermission(
                        this@WebActivity,
                        Manifest.permission.ACCESS_FINE_LOCATION
                    )
                    != PackageManager.PERMISSION_GRANTED
                ) {

                    if (ActivityCompat.shouldShowRequestPermissionRationale(
                            this@WebActivity,
                            Manifest.permission.ACCESS_FINE_LOCATION
                        )
                    ) {
                        AlertDialog.Builder(this@WebActivity)
                            .setMessage("Please turn ON the GPS to make app work smoothly")
                            .setNeutralButton(
                                android.R.string.ok,
                                DialogInterface.OnClickListener { dialogInterface, i ->
                                    mGeoLocationCallback = callback
                                    mGeoLocationRequestOrigin = origin
                                    ActivityCompat.requestPermissions(
                                        this@WebActivity,
                                        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                                    )

                                })
                            .show()

                    } else {
                        //no explanation need we can request the locatio
                        mGeoLocationCallback = callback
                        mGeoLocationRequestOrigin = origin
                        ActivityCompat.requestPermissions(
                            this@WebActivity,
                            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1001
                        )
                    }
                } else {
                    //tell the webview that permission has granted
                    callback!!.invoke(origin, true, true)
                }

            }

            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                super.onProgressChanged(view, newProgress)
                progressBar.progress = newProgress
                if (newProgress < MAX_PROGRESS && progressBar.visibility == ProgressBar.GONE) {
                    progressBar.visibility = ProgressBar.VISIBLE
                }
                if (newProgress == MAX_PROGRESS) {
                    progressBar.visibility = ProgressBar.GONE
                }
            }


        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        // Check if the key event was the Back button and if there's history
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack()
            return true
        }
        // If it wasn't the Back key or there's no web page history, exit the activity)
        return super.onKeyDown(keyCode, event)
    }

    private fun loadUrl(pageUrl: String) {
        webView.loadUrl(pageUrl)
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        when (requestCode) {
            1001 -> {
                //if permission is cancel result array would be empty
                if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //permission was granted
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, true, true)
                    }
                } else {
                    //permission denied
                    if (mGeoLocationCallback != null) {
                        mGeoLocationCallback!!.invoke(mGeoLocationRequestOrigin, false, false)
                    }
                }
            }

        }
    }
}
情绪 2024-10-30 20:59:12

这是显示警报对话框以提升用户使用其位置的权限的示例:

    final Context context = this;

     @Override
     public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
        Log.i(TAG, "onGeolocationPermissionsShowPrompt()");

        final boolean remember = false;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        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();
     }

This is an example of showing alert dialog to promote for user permission to use his/her location:

    final Context context = this;

     @Override
     public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
        Log.i(TAG, "onGeolocationPermissionsShowPrompt()");

        final boolean remember = false;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        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();
     }
怪异←思 2024-10-30 20:59:12

当从 Webview 请求位置时,您需要动态请求权限

确保您已将 ACCESS_FINE_LOCATION 添加到清单

   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

在顶级类中定义您的回调和来源,以便能够将它们分配给 ChromeClient 提供的回调和来源

public class MainActivity extends AppCompatActivity {

    private android.webkit.WebView myWebView;
    String mGeoLocationRequestOrigin = null;
    GeolocationPermissions.Callback  mGeoLocationCallback = null;

...................................................

处理地理位置请求和为回调分配值,以便在授予权限后能够使用它们

      myWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public void onGeolocationPermissionsShowPrompt(final String origin,
                                                           final GeolocationPermissions.Callback callback) {

                int permissionCheckFineLocation = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
                if (permissionCheckFineLocation!= PackageManager.PERMISSION_GRANTED) {
                    mGeoLocationCallback=callback;
                    mGeoLocationRequestOrigin=origin;
                    //requesting permission
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 123);
                }

                else {// permission and the user has therefore already granted it
                    callback.invoke(origin, true, false);
                }

            }
        });

,一旦收到权限,就可以使用 origin 调用回调

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
            //you have the permission now.
            if(requestCode==123) {
                mGeoLocationCallback.invoke(mGeoLocationRequestOrigin, true, false);
            }
        }

you need to dynamically request for Permission when location is requested from Webview

Make sure You you have added ACCESS_FINE_LOCATION to Manifest

   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Define Your callback and origin at top level Class ,to be able to assign them to the callbacks and origin provided by ChromeClient

public class MainActivity extends AppCompatActivity {

    private android.webkit.WebView myWebView;
    String mGeoLocationRequestOrigin = null;
    GeolocationPermissions.Callback  mGeoLocationCallback = null;

...................................................

Handle geoLocation Request and Assign value to callbacks to be able to use them once permission is granted

      myWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public void onGeolocationPermissionsShowPrompt(final String origin,
                                                           final GeolocationPermissions.Callback callback) {

                int permissionCheckFineLocation = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
                if (permissionCheckFineLocation!= PackageManager.PERMISSION_GRANTED) {
                    mGeoLocationCallback=callback;
                    mGeoLocationRequestOrigin=origin;
                    //requesting permission
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 123);
                }

                else {// permission and the user has therefore already granted it
                    callback.invoke(origin, true, false);
                }

            }
        });

once permission is received invoke calbacks using origin

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
            //you have the permission now.
            if(requestCode==123) {
                mGeoLocationCallback.invoke(mGeoLocationRequestOrigin, true, false);
            }
        }
何以笙箫默 2024-10-30 20:59:12

作为更新的 Android 的新答案发布,所有内容都在一篇文章中,因为您不再需要使用 setWebChromeClient

对于 Android 6+,您只需在运行时使用 ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 123); 请求 GPS 权限。

Posting as a new answer for updated Android with everything in one post, because you no longer need to use setWebChromeClient.

With android 6+ you just to ask for the GPS permissions at runtime using ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 123);.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文