Android WebView 中的 Html 網頁定位操作

亦楓發表於2019-02-25

利用 HTML5 提供的定位 API 可以幫助網頁獲取使用者裝置的當前位置資訊。但如果是在 Android 系統下的應用中開啟網頁,我們使用 Hybrid 開發模式時用到的 WebView 包括應用本身都需要做一定的設定才能支援內嵌網頁的定位功能。

這裡是一個簡單的網頁原始碼,其中有一段 JavaScript 程式碼,用於向宿主瀏覽器請求定位:

<!DOCTYPE html>
<head>
</head>
<body>
    <button onclick="fetchLocation()">獲取位置</button>
    <script>
        var tipsEle = document.getElementById('tips')
        function fetchLocation() {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError)
            } else {
                alert('當前裝置不支援定位!')
            }
        }
        function onGeoSuccess(event){
            alert("Success: " + event.coords.latitude + ", " + event.coords.longitude)
        }
        function onGeoError(event){
              alert("Error code " + event.code + ". " + event.message)
        }
    </script>
</body>複製程式碼

簡單說明:(有關 HTML5 定位 API 的詳細使用,可以參考連結:菜鳥教程 - HTML5 Geolocation

  • navigator.geolocation 屬性判斷當前硬體瀏覽器環境是否支援定位;

  • getCurrentPosition() 函式,在支援定位的前提下,發起請求定位,並傳遞定位成功和失敗兩個函式作為回撥引數。

然後在我們的 WebView 中新增如下設定:(這裡假設上面的測試 html 檔案放置在 assets 目錄下)

WebView contentWv = (WebView) findViewById(R.id.wv_content);
WebSettings settings = contentWv.getSettings();
settings.setJavaScriptEnabled(true);
contentWv.setWebChromeClient(new WebChromeClient(){
    @Override
    public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
        callback.invoke(origin, true, true);
        super.onGeolocationPermissionsShowPrompt(origin, callback);
    }
});
contentWv.loadUrl("file:///android_asset/location.html");複製程式碼

程式碼很簡單,最重要的一個地方就是,重寫 WebChromeClient 的這個方法:

onGeolocationPermissionsShowPrompt()

當網頁發起定位請求時,會呼叫到宿主 WebView 的這個方法,由開發者自行處理這個請求。可以看到,示例中包含這麼一行程式碼:

callback.invoke(origin, true, true);複製程式碼

這行程式碼就是用來處理定位請求,一般會向使用者給出一個請求定位許可權的彈窗。第二個 boolean 型別的參數列示是否授予網頁定位許可權;而第三個 boolean 型別的引數則表示是否保留這個許可權狀態。

值得注意的是,第三個引數的設定影響的是整個應用中的 WebView。如果我們在某個頁面的 WebView 中處理過一次網頁的定位請求,並設定第三個引數為 true,即保留狀態的情況下,當下次在其他頁面或者還是這個頁面開啟網頁時將不再向使用者發起定位許可權的請求,而是直接執行定位操作。

一般比較合適的做法是,在該回撥函式中設定一個對話方塊,告知使用者是否授權定位操作。做得更好一點的話,還可以幫助使用者檢測裝置的系統定位是否開啟。沒有開啟的情況下,提示使用者並跳轉至設定介面。

檢測系統定位是否開啟的示例程式碼:

private boolean isSystemLocationEnable() {
    LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    boolean gpsLocationEnable = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    boolean networkLocationEnable = manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    return gpsLocationEnable && networkLocationEnable;
}複製程式碼

跳轉至系統設定中的定位介面:

Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);複製程式碼

還有最後一步,別忘了在 Manifest 清單檔案中新增定位相關的許可權,當然也包括網路許可權:(通過 GPS 精準定位和 WI-FI 的粗略定位)

<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"/>複製程式碼

這段示例網頁程式碼呼叫時的效果如圖:

Android WebView 中的 Html 網頁定位操作

整體看來,使用方式還挺簡單的,那是不是這種方式就一定萬無一失呢?

前面提過,使用 HTML5 定位 API 獲取使用者位置的前提是瀏覽器或者說我們 Android 系統中的原生 WebView 環境支援定位操作。事實上,經測試,這種方式不完全穩定。尤其是在國內各種廠商各種 ROM 的複雜環境下,還是有相當多品牌的手機是不支援這種定位操作的。甚至,你還會遇見,即使是使用同一臺手機,安裝不同的瀏覽器 App 對於定位的支援也不盡相同。

所以,HTML5 自身的定位操作只能作為一種輔助手段。更穩妥的做法是,開發人員通過百度、高德之類的第三方定位 SDK 在原生程式碼中獲取使用者位置資訊,當開啟 WebView 中的網頁時通過拼接 URL 引數的形式傳遞給網頁。網頁自行判斷,如果 URL 中不包含定位資訊的話,再通過自身的 API 發起定位請求。

或者通過HTML 網頁的 JS程式碼 與 Java 原生程式碼互動的方式間接操作。關於 JS 與 Java 互動的相關知識,可以參考我的這篇文章:

Android WebView —— Java 與 JavaScript 互動總結

關於我:亦楓,部落格地址:yifeng.studio/,新浪微博:IT亦楓

微信掃描二維碼,歡迎關注我的個人公眾號:安卓筆記俠

不僅分享我的原創技術文章,還有程式設計師的職場遐想

相關文章