WebView封装的安卓应用无法自动获取当前定位的问题咨询
问题描述
通过WebView封装地址为https://taxif.com/online.html的页面后,出现普通浏览器可自动获取定位、封装应用内无法自动定位的异常,需求是实现与网页端一致的WebView自动定位能力。提前感谢各位的解答。
附带代码片段
MainActivity.java
import androidx.appcompat.app.AppCompatActivity; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.view.View; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private SwipeRefreshLayout refreshLayout; private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.myWebView); refreshLayout = findViewById(R.id.refresh); refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { webView.reload(); } }); webView.getSettings().setLoadWithOverviewMode(true); webView.getSettings().setUseWideViewPort(true); webView.setWebChromeClient(new MyChromeClient()); webView.setWebViewClient(new BrowserClient(refreshLayout)); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowFileAccess(true); webSettings.setAppCacheEnabled(true); webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH); webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); webSettings.setAppCacheEnabled(true); webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); webSettings.setSavePassword(true); webSettings.setSaveFormData(true); webSettings.setEnableSmoothTransition(true); loadWebPage(); } private void loadWebPage() { ConnectivityManager connectivityManager = (ConnectivityManager) MainActivity.this .getApplication().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if(networkInfo != null && networkInfo.isConnectedOrConnecting()){ webView.loadUrl("https://taxif.com/online.html"); }else{ Toast.makeText(this,"You don't have any active internet connection",Toast.LENGTH_SHORT).show(); } } }
BrowserClient.java
import android.graphics.Bitmap; import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; public class BrowserClient extends WebViewClient { SwipeRefreshLayout refreshLayout; public BrowserClient(){ } public BrowserClient(SwipeRefreshLayout refreshLayout) { this.refreshLayout = refreshLayout; } @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); refreshLayout.setRefreshing(true); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); refreshLayout.setRefreshing(false); } }
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.booking"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-feature android:name="android.hardware.type.watch" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.BookingApp"> <!-- Set to true if your app is Standalone, that is, it does not require the handheld app to run. --> <meta-data android:name="com.google.android.wearable.standalone" android:value="true" /> <activity android:name=".SplashScreen" android:label="Booking App"><intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter></activity> <activity android:name=".MainActivity"> </activity> </application> </manifest>
实现方案
异常根源为WebView默认未开启定位能力透传、未处理网页发起的定位权限请求,需完成4项配置:
- 开启WebSettings定位开关
在已有的WebSettings初始化代码块中追加以下配置:// 开启WebView定位能力 webSettings.setGeolocationEnabled(true); // 开启DOM存储,避免部分网页定位依赖的本地标识无法缓存 webSettings.setDomStorageEnabled(true); - 重写WebChromeClient的定位权限回调
你代码中已初始化MyChromeClient,需在该类中补充以下重写逻辑:import android.webkit.GeolocationPermissions; import android.webkit.WebChromeClient; public class MyChromeClient extends WebChromeClient { @Override public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { // 检查系统定位权限是否已授予 if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED) { // 权限已授予,直接允许网页定位请求 callback.invoke(origin, true, false); } else { // 未授予权限,发起系统权限申请 ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); } } } - 补充权限申请结果处理逻辑
在MainActivity中添加权限回调方法,确保用户授权后页面可正常触发定位:@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) { // 授权完成后刷新页面,重新触发起始的定位请求 webView.reload(); } else { Toast.makeText(this, "未授予定位权限,无法获取当前位置", Toast.LENGTH_SHORT).show(); } } } - 清理冗余配置
删除MainActivity中重复调用的webSettings.setAppCacheEnabled(true)代码行;如果应用为普通手机端应用,删除AndroidManifest中手表相关的<uses-feature android:name="android.hardware.type.watch" />及对应手表meta-data配置,避免硬件校验异常。
内容的提问来源于stack exchange,提问作者Rehan Shakir
相关产品推荐
相关产品推荐

