如何在Android M - API 23中读取选定的模拟位置应用程序

14

我正在寻找一种读取Android M中模拟位置的新设置的方法。

在Android M之前,模拟位置设置是一个名为“使用模拟位置”的开关选项,并且可以使用此设置进行读取:Settings.Secure.ALLOW_MOCK_LOCATION

在Android M中,模拟位置设置是一个用于选择模拟位置的应用程序,因此它是一个包含多个元素的列表,其中选定的元素可以是“无”。

那个线程提供了一种解决方案,用于确定侦听位置时位置更新的来源,但不幸的是,我想读取设置本身: 如何在Android Marshmallow中检查模拟位置?

我想读取是否有选定的模拟位置应用程序,以及最好还要读取选定的应用程序。欢迎提供任何关于如何做到这一点的想法!


也许这个链接可以帮到你:http://www.klaasnotfound.com/2016/05/27/location-on-android-stop-mocking-me/? - android developer
4个回答

21

浏览 Android 开发者网站后,我找到了以下内容:您需要使用AppOpsManagercheckOp("android:mock_location", "yourUID", "com.your.package.name")

我认为您可以通过更改软件包名称来检查不同应用程序是否已启用。

public boolean isMockLocationEnabled(){
    boolean isMockLocation = false;
    try {
        //if marshmallow
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            AppOpsManager opsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
            isMockLocation = (opsManager.checkOp(AppOpsManager.OPSTR_MOCK_LOCATION, android.os.Process.myUid(), BuildConfig.APPLICATION_ID)== AppOpsManager.MODE_ALLOWED);
        } else {
            // in marshmallow this will always return true
            isMockLocation = !android.provider.Settings.Secure.getString(mContext.getContentResolver(), "mock_location").equals("0");
        }
    } catch (Exception e) {
        return isMockLocation;
    }
    return isMockLocation;
}

4
谢谢您的回答。不幸的是,这个答案只能检查我的应用程序是否有访问模拟位置的权限,它不能检查系统设置本身:例如,是否选择了另一个应用程序进行模拟位置。 - androidseb
@androidseb 我有和你完全相同的需求。 你找到解决方案了吗?也请指导我一下。 谢谢!此外,我在Marshmallow上尝试了Marlon的解决方案并遇到了问题。 第一次尝试时没有选择任何模拟应用程序,因此我从此代码中获得了预期的结果。 然后我在设置中选择了FakeGPS模拟应用程序,仍然获得了预期的结果(安全异常)。 然后我选择了模拟应用程序中的Nothing,但是此代码仍会引发安全异常。 我继续停止了FakeGPS服务,但仍然没有帮助。 有什么可能引起这种情况的想法吗? - LoveForDroid
@LoveForDroid 我还没有找到扫描哪个应用程序被选为模拟位置的解决方案,我认为你的应用程序需要系统访问权限(也就是需要成为系统应用程序),才能使Marlon的解决方案起作用,而由于你的应用程序没有权限,这可能是你遇到安全异常的原因。最终,我采取了不同的方法,并像这里建议的那样检查位置更新:https://dev59.com/dlwY5IYBdhLWcg3wYnAB - androidseb
1
@androidseb 我不需要知道选择了哪个应用程序进行模拟位置。我的确切要求是要知道是否选择了任何应用程序进行模拟位置。你能为此提供一些建议吗?由于我找不到任何东西来解决这个问题,所以最终我使用了location.isFromMockProvider()。但不幸的是,它总是返回true,无论我选择还是不选择模拟应用程序。看起来假GPS会覆盖位置坐标,并且即使我停止假GPS,位置管理器也不会刷新其坐标。 - LoveForDroid
最好使用checkOpNoThrow而不是checkOp,因为如果mode == MODE_ERRORED,则checkOp会抛出SecurityException。 - ceph3us
显示剩余3条评论

9
以下是使用ADB获取和设置模拟应用程序的命令:
允许应用程序模拟位置:
adb shell appops set <PACKAGE> android:mock_location allow

移除模拟定位应用

adb shell appops set <PACKAGE> android:mock_location deny

检查应用程序是否设置了模拟位置

adb shell appops get <PACKAGE> android:mock_location

0
如果您想检测当前或最近是否使用了模拟位置,请使用以下代码。
    val manager = getSystemService(Context.LOCATION_SERVICE) as? LocationManager
    if (manager?.getLastKnownLocation(LocationManager.GPS_PROVIDER)?.isFromMockProvider == true) {
    // Mock locations are/were used
    }

这需要额外的权限和监听器。 - Vlad
我认为这是很明显的,您需要权限才能访问用户位置。 - mobo

-1
  PackageManager pm = context.getPackageManager();
    List<ApplicationInfo> packages =
            pm.getInstalledApplications(PackageManager.GET_META_DATA);

    for (ApplicationInfo applicationInfo : packages) {
        try {
            PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName,
                    PackageManager.GET_PERMISSIONS);

            // Get Permissions
            String[] requestedPermissions = packageInfo.requestedPermissions;

            if (requestedPermissions != null) {
                for (int i = 0; i < requestedPermissions.length; i++) {
                    if (requestedPermissions[i].equals("android.permission.ACCESS_MOCK_LOCATION")
                            && !applicationInfo.packageName.equals(context.getPackageName())) {
                        //we get Package name here
                    }
                }
            }
        } catch (PackageManager.NameNotFoundException e) {

        }
    }

这只是读取清单,但并不一定意味着模拟位置。 - Vlad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接