Android WebView关于定位部分研究

作者: Jaesoon | 来源:发表于2018-11-03 21:30 被阅读11次

    啥是H5定位

    HTML5标准中提供Geolocation API,js中调用该API,用于获得用户的地理位置。
    鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的。 该API被设计成即支持一次性请求,也支持反复的位置更新,以及显示的查询缓存的位置的能力。位置信息通过经纬度来呈现。需要注意的是:根据世界大地测量系统坐标[WGS84]提供地理位置信息(GPS使用的是WGS84坐标)。

    The geographic position information is provided in terms of World Geodetic System coordinates [WGS84].

    如何使用H5定位

    Navigator接口扩展

    partial interface Navigator {  
        readonly attribute Geolocation geolocation;  
    };
    

    Navigator的geolocation属性提供了与主设备相关联的位置信息的访问。

    The geolocation attribute gives access to location information associated with the hosting device.

    Geolocation接口

    [NoInterfaceObject]  
    interface Geolocation {
      void getCurrentPosition(PositionCallback successCallback,optional PositionErrorCallback errorCallback,optional PositionOptions options);  
      
      long watchPosition(PositionCallback successCallback,optional PositionErrorCallback errorCallback,optional PositionOptions options);  
      
      void clearWatch(long watchId);  
    };
    

    PositionOptions接口

    dictionary PositionOptions {
      boolean enableHighAccuracy = false;
      [Clamp] unsigned long timeout = 0xFFFFFFFF;
      [Clamp] unsigned long maximumAge = 0;
    };
    

    Position接口

    [NoInterfaceObject]
    interface Position {
      readonly attribute Coordinates coords;
      readonly attribute DOMTimeStamp timestamp;
    };
    

    Coordinates接口

    [NoInterfaceObject]
    interface Coordinates {
      readonly attribute double latitude;
      readonly attribute double longitude;
      readonly attribute double? altitude;
      readonly attribute double accuracy;
      readonly attribute double? altitudeAccuracy;
      readonly attribute double? heading;
      readonly attribute double? speed;
    };
    

    he geographic coordinate reference system used by the attributes in this interface is the World Geodetic System (2d) [WGS84]. No other reference system is supported.

    PositionError接口

    [NoInterfaceObject]
    interface PositionError {
      const unsigned short PERMISSION_DENIED = 1;
      const unsigned short POSITION_UNAVAILABLE = 2;
      const unsigned short TIMEOUT = 3;
      readonly attribute unsigned short code;
      readonly attribute DOMString message;
    };
    

    The code attribute MUST return the appropriate code from the following list:

    • PERMISSION_DENIED (numeric value 1)
      The location acquisition process failed because the document does not have permission to use the Geolocation API.
    • POSITION_UNAVAILABLE (numeric value 2)
      The position of the device could not be determined. For instance, one or more of the location providers used in the location acquisition process reported an internal error that caused the process to fail entirely.
    • TIMEOUT (numeric value 3)
      The length of time specified by the timeout property has elapsed before the implementation could successfully acquire a new Position object.

    下面一些示例展示如何获取基础位置信息

    EXAMPLE 1: Example of a "one-shot" position request

    function showMap(position) {
      // Show a map centered at (position.coords.latitude, position.coords.longitude).
    }
    
    // One-shot position request.
    navigator.geolocation.getCurrentPosition(showMap);
    

    EXAMPLE 2: Example of requesting repeated position updates

    function scrollMap(position) {
      // Scrolls the map so that it is centered at
      //  (position.coords.latitude, position.coords.longitude).
    }
    
    // Request repeated updates.
    var watchId = navigator.geolocation.watchPosition(scrollMap);
    
    function buttonClickHandler() {
      // Cancel the updates when the user clicks a button.
      navigator.geolocation.clearWatch(watchId);
    }
    

    EXAMPLE 3: Example of requesting repeated position updates and handling errors

    function scrollMap(position) {
      // Scrolls the map so that it is centered at
      //  (position.coords.latitude, position.coords.longitude).
    }
    
    function handleError(error) {
      // Update a div element with error.message.
    }
    
    // Request repeated updates.
    var watchId = navigator.geolocation.watchPosition(scrollMap, handleError);
    
    function buttonClickHandler() {
      // Cancel the updates when the user clicks a button.
      navigator.geolocation.clearWatch(watchId);
    }
    

    EXAMPLE 4: Example of requesting a potentially cached position

    // Request a position. We accept positions whose age is not
    // greater than 10 minutes. If the user agent does not have a
    // fresh enough cached position object, it will automatically
    // acquire a new one.
    navigator.geolocation.getCurrentPosition(successCallback,
                                             errorCallback,
                                             {maximumAge:600000});
    
    function successCallback(position) {
      // By using the 'maximumAge' option above, the position
      // object is guaranteed to be at most 10 minutes old.
    }
    
    function errorCallback(error) {
      // Update a div element with error.message.
    }
    

    EXAMPLE 5: Forcing the user agent to return a fresh cached position

    // Request a position. We only accept cached positions whose age is not
    // greater than 10 minutes. If the user agent does not have a fresh
    // enough cached position object, it will immediately invoke the error
    // callback.
    navigator.geolocation.getCurrentPosition(successCallback,
                                             errorCallback,
                                             {maximumAge:600000, timeout:0});
    
    function successCallback(position) {
      // By using the 'maximumAge' option above, the position
      // object is guaranteed to be at most 10 minutes old.
      // By using a 'timeout' of 0 milliseconds, if there is
      // no suitable cached position available, the user agent
      // will asynchronously invoke the error callback with code
      // TIMEOUT and will not initiate a new position
      // acquisition process.
    }
    
    function errorCallback(error) {
      switch(error.code) {
        case error.TIMEOUT:
          // Quick fallback when no suitable cached position exists.
          doFallback();
          // Acquire a new position object.
          navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
          break;
        case ... // treat the other error cases.
      };
    }
    
    function doFallback() {
      // No fresh enough cached position available.
      // Fallback to a default position.
    }
    

    EXAMPLE 6: Forcing the user agent to return any available cached position

    // Request a position. We only accept cached positions, no matter what
    // their age is. If the user agent does not have a cached position at
    // all, it will immediately invoke the error callback.
    navigator.geolocation.getCurrentPosition(successCallback,
                                             errorCallback,
                                             {maximumAge:Infinity, timeout:0});
    
    function successCallback(position) {
      // By setting the 'maximumAge' to Infinity, the position
      // object is guaranteed to be a cached one.
      // By using a 'timeout' of 0 milliseconds, if there is
      // no cached position available at all, the user agent
      // will immediately invoke the error callback with code
      // TIMEOUT and will not initiate a new position
      // acquisition process.
      if (position.timestamp < freshness_threshold &&
          position.coords.accuracy < accuracy_threshold) {
        // The position is relatively fresh and accurate.
      } else {
        // The position is quite old and/or inaccurate.
      }
    }
    
    function errorCallback(error) {
      switch(error.code) {
        case error.TIMEOUT:
          // Quick fallback when no cached position exists at all.
          doFallback();
          // Acquire a new position object.
          navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
          break;
        case ... // treat the other error cases.
      };
    }
    
    function doFallback() {
      // No cached position available at all.
      // Fallback to a default position.
    }
    

    如何给Android设备的Webview添加定位功能

    1. 首先在AndroidManifest.xml中添加定位权限申明
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
      

    如果应用的target小于Android.M,至此就完成了给WebView添加支持定位功能。因为默认是许可网站获取位置的。如图:。But,你看到这篇文章时,肯定target不下于Android.M了,所以,接着看。

    1. 给WebView设置setWebChromeClient;
    2. 重写setWebChromeClient的 onGeolocationPermissionsShowPrompt() 方法;
    3. 判断App是否获得了定位权限,如果没有请求定位权限;
    4. 判断设备是否开启了定位服务,在某些情况下如果没有开启定位无法获取到定位的,如下:
    • 获取不到位置
      • 设备很长时间没有开启定位了。
      • 设备不久前开启了定位,现在已经关闭定位了,但是js又要求必须获取到实时的位置(不允许使用缓存位置)。
    • 获取到了位置
      • 设备当前定位服务处于开启状态。
      • 设备不久前开启了定位,现在处于关闭状态,js中接受缓存位置。
    1. 调用 GeolocationPermissionsCallback 回调,设置是否许可js获取当前设备的权限

    整体逻辑就是这样。中间比较复杂的是第4步。这一步需要考虑到这一点:App申请定位权限时,系统会给用户三种选择,分别是:

    • 许可: 用户选择之后,我们就可以走第5步了。
    • 禁止: 走第6步,回调,拒绝js的位置请求。js下一次请求时,会回调 onGeolocationPermissionsShowPrompt() 方法,继续走4、5、6。
    • 禁止并不再提示:
      本次的调用同上,但是,js下一次请求时,流程就有一点点不一样。首先,系统直接不提示用户授权了。what?这还玩个P啊。但是,系统会给我们的回调一个拒绝的结果。所以,在此时,我们可以请求让用户到系统的设置去给应用授权。用户如果愿意去设置,就让他去设置,然后回来时,我们判断一下,用户给应用权限了,我们就到第6步,许可权限;如果没有给权限,对不起,只能到第6步,回调不许可权限了。如果用户不愿意去设置,那也是到第6步,回调不许可权限。

    嗯,但愿你没有晕倒[苦笑]。我也想给你讲的简单点,但是,事实就是这么复杂,我能怎么办,我也很无奈啊[笑哭]。
    好了,你们一定想说,别扯淡了,赶紧放码出来。诺,这是你要的代码

    会遇到哪些问题

    • H5请求定位,客户端的onGeolocationPermissionsShowPrompt方法没有回调
      三点需要注意
      1. Android系统版本是不是大于6.0?
      2. 是不是安全链接?
        从Android6.0开始,如果链接不是安全的,该方法不被调用。

      Note that for applications targeting Android N and later SDKs (API level > Build.VERSION_CODES.M) this method is only called for requests originating from secure origins such as https. On non-secure origins geolocation requests are automatically denied.

      1. js是否接受缓存地址?
        如果js接受缓存地址,尽管定位服务处于关闭状态,如果不久前设备刚刚定了位置,这个方法也不会被调用。

    相关文章

      网友评论

      本文标题:Android WebView关于定位部分研究

      本文链接:https://www.haomeiwen.com/subject/zehcxqtx.html