Android使用代码开关Location服务

Android系统中,只有系统设置里面有入口开关位置服务。其他的应用应该怎么去开关这个服务呢?

首先,应用需要有系统权限(签名),在这基础上,我们就可以通过一些手段来实现这个功能。
这里要注意一点,不通的Android版本的操作方式也不一样。需要区别对待。

应用加上系统签名

manifest标签里面,加上android:sharedUserId="android.uid.system",然后用系统的签名给apk签名,可以放到系统中去编译,也可以用AndroidStudio指定签名文件签名

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.application"
    android:sharedUserId="android.uid.system">

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application>
    ...
    </application>

</manifest>

Android 5 到 Android 8

对于这几个版本,通过修改Settings.Secure数据库加上广播即可实现。

private static boolean updateLocationMode(Context context, int oldMode, int newMode) {
    Intent intent = new Intent("com.android.settings.location.MODE_CHANGING");
    intent.putExtra("CURRENT_MODE", oldMode);
    intent.putExtra("NEW_MODE", newMode);
    context.sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
    return Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, newMode);
}

/**
 * Settings.Secure.LOCATION_MODE_OFF // 关闭
 * Settings.Secure.LOCATION_MODE_SENSORS_ONLY // GPS only
 * Settings.Secure.LOCATION_MODE_BATTERY_SAVING // 降低GPS上报频率
 * Settings.Secure.LOCATION_MODE_HIGH_ACCURACY // 高精度
 */
public static void setLocationEnabled(Context context, int mode){
    int oldMode = Settings.Secure.getInt(context.getContentResolver(),
                    Settings.Secure.LOCATION_MODE,
                    Settings.Secure.LOCATION_MODE_OFF);
    updateLocationMode(context, oldMode, mode);
}

Android 9

这里需要使用反射,调用LocationManagersetProviderEnabledForUser方法来实现

@RequiresApi(api = Build.VERSION_CODES.P)
public static void setProviderEnabledForUser(Context context, String provider, boolean enabled){
    LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
    try{
        Field field = UserHandle.class.getDeclaredField("SYSTEM");
        field.setAccessible(true);
        UserHandle userHandle = (UserHandle) field.get(UserHandle.class);
        Method method = LocationManager.class.getDeclaredMethod(
                    "setProviderEnabledForUser",
                    String.class,
                    boolean.class,
                    serHandle.class);
        method.invoke(locationManager, provider, enabled, userHandle);
    }catch(Exception e){
        Log.e(TAG, "can not setProviderEnabledForUser:(" + provider +"," + enabled +")");
    }
}

Android 10以上

Android 9类似,只不过调用的方法不一样,通过调用LocationManagersetLocationEnabledForUser方法来实现

@RequiresApi(api = Build.VERSION_CODES.Q)
public static void setLocationEnabledForUser(Context context, boolean enabled){
    LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
    try{
        Field field = UserHandle.class.getDeclaredField("SYSTEM");
        field.setAccessible(true);
        UserHandle userHandle = (UserHandle) field.get(UserHandle.class);
        Method method = LocationManager.class.getDeclaredMethod(
                    "setLocationEnabledForUser",
                    boolean.class,
                    UserHandle.class);
        method.invoke(locationManager, enabled, userHandle);
    }catch(Exception e){
        Log.e(TAG, "can not setLocationEnabledForUser:(" + enabled +")");
    }
}
posted @ 2021-01-20 00:20  hlhuang  阅读(1492)  评论(0编辑  收藏  举报