且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

ACCESS_COARSE_LOCATION 权限可在 Android 上提供手机信号塔精度

更新时间:2023-02-27 08:34:16

这是一个有趣的问题,我的印象是使用 ACCESS_COARSE_LOCATION 会使用 WiFi,因为文档是这么说的.

ACCESS_COARSE_LOCATION 的文档说明:

允许应用访问来自网络的大致位置位置来源,例如手机信号塔和 Wi-Fi.

所以,我进行了测试,结果令人惊讶.

这是我用来测试的代码:

公共类 MainActivity 扩展 Activity 实现GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,LocationListener {LocationRequest 位置请求;GoogleApiClient mGoogleApiClient;@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);构建GoogleApiClient();mGoogleApiClient.connect();}@覆盖受保护的无效 onPause(){超级.onPause();if (mGoogleApiClient != null) {LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);}}受保护的同步无效 buildGoogleApiClient() {Toast.makeText(this,"buildGoogleApiClient",Toast.LENGTH_SHORT).show();mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(这个).addOnConnectionFailedListener(这个).addApi(LocationServices.API).建造();}@覆盖公共无效 onConnected(捆绑包){Toast.makeText(this,"onConnected",Toast.LENGTH_SHORT).show();mLLocationRequest = new LocationRequest();mLLocationRequest.setInterval(10);mLocationRequest.setFastestInterval(10);mLLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);//mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);//mLocationRequest.setSmallestDisplacement(0.1F);LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);}@覆盖公共无效 onConnectionSuspended(int i) {Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();}@覆盖公共无效 onConnectionFailed(ConnectionResult connectionResult) {Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();}@覆盖公共无效onLocationChanged(位置位置){Log.d("locationtesting", "accuracy:" + location.getAccuracy() +" lat:" + location.getLatitude() +" lon:" + location.getLongitude());Toast.makeText(this,"位置已更改",Toast.LENGTH_SHORT).show();}}

AndroidManifest.xml:

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

build.gradle:

编译'com.google.android.gms:play-services:7.3.0'

我做的第一个测试是使用 PRIORITY_BALANCED_POWER_ACCURACY,没有 WiFi.请注意,我还禁用了 Always Allow Scanning,因为它声明:

让 Google 位置服务和其他应用程序扫描 Wi-Fi网络,即使 Wi-Fi 已关闭

所以,如果启用它,那肯定会扭曲结果.

请注意,我还在所有测试中将位置模式设置为省电模式,因此 GPS 无线电一直处于关闭状态.

以下是PRIORITY_BALANCED_POWER_ACCURACYACCESS_COARSE_LOCATION和没有WiFi的结果:

准确度:2000.0 纬度:37.78378378378378 经度:-122.40320943772021

所以,它说的是 2000 米的精度,这里是实际坐标的距离,绿色箭头显示我的实际位置:

然后,我开启了WiFi,再次运行测试,结果竟然一模一样!

准确度:2000.0 纬度:37.78378378378378 经度:-122.40320943772021

然后,我在 LocationRequest 中切换到 LocationRequest.PRIORITY_LOW_POWER,同时在 AndroidManifest.xml 中保留 android.permission.ACCESS_COARSE_LOCATION.p>

没有 WiFi:

准确度:2000.0 纬度:37.78378378378378 经度:-122.40320943772021

使用 WiFi:

准确度:2000.0 纬度:37.78378378378378 经度:-122.40320943772021

结果又一模一样!使用 PRIORITY_LOW_POWER 与使用 PRIORITY_BALANCED_POWER_ACCURACY 的结果相同,因为 WiFi 状态似乎对坐标精度没有任何影响.

然后,为了涵盖所有基础,我改回 LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY,并将 AndroidManifest.xml 切换为 ACCESS_FINE_LOCATION:

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

第一次测试,没有 WiFi:

准确度:826.0 纬度:37.7825458 经度:-122.3948752

所以,它说的准确度是 826 米,这是它在地图上的距离:

然后,我打开WiFi,结果如下:

准确度:18.847 纬度:37.779679 经度:-122.3930918

正如您在地图上看到的那样,它确实在现场:

您在 Java 代码中的 LocationRequest 中使用什么似乎并不重要,而在 AndroidManifest.xml 中使用什么权限更重要,因为这里的结果清楚地表明,当使用 ACCESS_FINE_LOCATION,打开或关闭 WiFi 无线电对准确性有很大影响,而且总体上也更准确.

文档似乎有点误导,并且在使用 android.permission.ACCESS_COARSE_LOCATION 时,打开或关闭 WiFi 无线电对您的应用没有任何影响是唯一一个发出位置请求的人.

文档指出的另一件事是,使用 PRIORITY_BALANCED_POWER_ACCURACY 将使您的应用搭载"其他应用发出的位置请求.来自文档:

他们只会在由setInterval(long), 但仍然可以接收其他触发的位置应用程序的速率高达 setFastestInterval(long).

因此,如果用户打开 Google 地图,根据文档,您的应用可以在该点获得更准确的位置.这是使用新的 Fused Location Provider 而不是旧 API 的主要优点之一,因为它可以减少应用程序的电池消耗量,而无需您做太多工作.

我对此功能进行了测试,看看使用 ACCESS_COARSE_LOCATION 时会发生什么.

第一次测试:ACCESS_COARSE_LOCATIONPRIORITY_BALANCED_POWER_ACCURACY,WiFi 开启:

准确度:2000.0 纬度:37.78378378378378 经度:-122.38041129850662

这让我掉进了水里,离我现在的位置很远.然后,我退出了测试应用程序,启动了谷歌地图,它准确地定位了我所在的位置,然后重新启动了测试应用程序.测试应用无法从谷歌地图中捎带到位置,结果和以前完全一样!

准确度:2000.0 纬度:37.78378378378378 经度:-122.38041129850662

为了确定,我重新测试了几次,但看起来使用 ACCESS_COARSE_LOCATION 也会禁用应用程序搭载"其他应用程序获得的位置的能力.

看起来在 AndroidManifest.xml 中使用 ACCESS_COARSE_LOCATION 确实会削弱应用获取精确位置数据的能力.

总之,您唯一真正能做的就是磨练适合您和您的应用的***设置组合,希望此测试的结果可以帮助您做出决定.

I am making some tests with the requestLocationUpdates() function from the FusedLocationApi. I am using the PRIORITY_BALANCED_POWER_ACCURACY. A city block precision is fine for me.

When I request the ACCESS_FINE_LOCATION permission, I get around a 100m precision which is great with GPS off. As I do not need a GPS precision but a city block precision, I would like to request only the ACCESS_COARSE_LOCATION permission. However when I request the ACCESS_COARSE_LOCATION permission, I get a 2 km precision. It seems that the device does not use anymore the Wifi permission and only a cell tower precision.

How can I have a better precision with the ACCESS_COARSE_LOCATION permission?

Note: the GPS is disabled on my test device.

This is an interesting problem, and I was under the impression that using ACCESS_COARSE_LOCATION would use WiFi, since that's what the documentation says.

The documentation for ACCESS_COARSE_LOCATION states:

Allows an app to access approximate location derived from network location sources such as cell towers and Wi-Fi.

So, I put it to the test, and the results are surprising.

Here is the code that I used to test with:

public class MainActivity extends Activity implements
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildGoogleApiClient();
        mGoogleApiClient.connect();
    }

    @Override
    protected void onPause(){
        super.onPause();
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    protected synchronized void buildGoogleApiClient() {
        Toast.makeText(this,"buildGoogleApiClient",Toast.LENGTH_SHORT).show();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    @Override
    public void onConnected(Bundle bundle) {
        Toast.makeText(this,"onConnected",Toast.LENGTH_SHORT).show();

        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10);
        mLocationRequest.setFastestInterval(10);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        //mLocationRequest.setPriority(LocationRequest.PRIORITY_LOW_POWER);
        //mLocationRequest.setSmallestDisplacement(0.1F);

        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
    }

    @Override
    public void onConnectionSuspended(int i) {
        Toast.makeText(this,"onConnectionSuspended",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Toast.makeText(this,"onConnectionFailed",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLocationChanged(Location location) {

        Log.d("locationtesting", "accuracy: " + location.getAccuracy() + " lat: " + location.getLatitude() + " lon: " + location.getLongitude());

        Toast.makeText(this,"Location Changed",Toast.LENGTH_SHORT).show();
    }
}

AndroidManifest.xml:

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

build.gradle:

compile 'com.google.android.gms:play-services:7.3.0'

The first test I did was with PRIORITY_BALANCED_POWER_ACCURACY, and no WiFi. Note that I also disabled Always Allow Scanning, since it states:

Let Google Location Service and other applications scan for Wi-Fi networks, even when Wi-Fi is off

So, that would certainly skew the results if it was enabled.

Note that I also had Location Mode set in Battery Saving Mode for all tests, so the GPS radio was off the entire time.

Here are the results of PRIORITY_BALANCED_POWER_ACCURACY, ACCESS_COARSE_LOCATION, and no WiFi:

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.40320943772021

So, it says 2000 meter accuracy, and here is how far away the actual coordinates are, the green arrow shows where I actually am:

Then, I enabled WiFi, and ran the test again, and surprisingly, the results were exactly the same!

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.40320943772021

Then, I switched to LocationRequest.PRIORITY_LOW_POWER in the LocationRequest while keeping android.permission.ACCESS_COARSE_LOCATION in the AndroidManifest.xml.

No WiFi:

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.40320943772021

With WiFi:

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.40320943772021

The results were exactly the same again! Using PRIORITY_LOW_POWER had the same results as using PRIORITY_BALANCED_POWER_ACCURACY, in that the WiFi state did not seem to have any effect on accuracy of coordinates.

Then, just to cover all the bases, I changed back to LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY, and switched the AndroidManifest.xml to ACCESS_FINE_LOCATION :

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

First test, no WiFi:

accuracy: 826.0 lat: 37.7825458 lon: -122.3948752

So, it says accuracy of 826 meters, and here is how close it was on the map:

Then, I powered on WiFi, and here is the result:

accuracy: 18.847 lat: 37.779679 lon: -122.3930918

It's literally spot on, as you can see on the map:

It seems that it matters less what you use in your LocationRequest in the Java code, and more what permission you use in the AndroidManifest.xml, since the results here clearly show that when using ACCESS_FINE_LOCATION, having the WiFi radio on or off made a huge difference in the accuracy, and it was also more accurate in general.

It certainly seems as though the documentation is a bit miss-leading, and that while using android.permission.ACCESS_COARSE_LOCATION, having the WiFi radio on or off doesn't make a difference when your app is the only one making location requests.

Another thing that the documentation states is that using PRIORITY_BALANCED_POWER_ACCURACY will let your app "piggy-back" onto location requests made by other apps. From the documentation:

They will only be assigned power blame for the interval set by setInterval(long), but can still receive locations triggered by other applications at a rate up to setFastestInterval(long).

So if the user opens up Google Maps, according to the documentation your app can obtain a more accurate location at that point. That is one of the major up-sides of using the new Fused Location Provider rather than the older APIs, since it decreases the amount of battery drain of your app without much work on your part.

Edit: I performed a test of this functionality, to see what would happen while using ACCESS_COARSE_LOCATION.

First Test: ACCESS_COARSE_LOCATION, PRIORITY_BALANCED_POWER_ACCURACY, and WiFi on:

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.38041129850662

That placed me out in the water, quite far from my current location. Then, I exited the test app, launched Google Maps, which located me exactly where I am, then re-launched the test app. The test app was not able to piggy-back onto the location from Google Maps, and the result was exactly the same as before!

accuracy: 2000.0 lat: 37.78378378378378 lon: -122.38041129850662

I re-tested this a few times, just to be sure, but it really looks like using ACCESS_COARSE_LOCATION also disables the ability of apps to "piggy-back" on to locations obtained by other apps.

It looks like using ACCESS_COARSE_LOCATION in the AndroidManifest.xml really cripples the app in terms of getting precise location data.

In conclusion, the only thing you can really do is hone in on the best combination of settings that work for you and your app, and hopefully the results of this test can help you make that decision.