Android6.0权限问题

本文介绍Android6.0及以上的权限管理机制变化,包括如何针对不同版本的Android系统实现权限请求逻辑,以及如何处理敏感权限组的问题。此外,还提供了一个实用的权限管理工具类EasyPermissions的使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android6.0权限问题

1、AndroidManifest.xml中android:targetSdkVersion=”22”以下使用旧版本权限,即强制用户使用权限,大于22 使用新版本权限,即权限限制决定用户手中。
2、Android6.0解决权限做法

用户手机版本6.0以下使用旧版本权限,6.0以上动态加载权限。
谷歌将侵犯用户隐私的权限分成九组,同组中只要有一个权限允许,组内所有权限默认允许。
6.0以上权限分组:http://blog.youkuaiyun.com/u013277740/article/details/51647791
6.0以上不侵犯用户隐私的普通权限在AndroidManifest.xml中添加就行。

以下是普通权限:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

3、权限封装
/**
 * Utility to request and check System permissions for apps targeting Android M (API >= 23).
 */
public class EasyPermissions {

public static final int SETTINGS_REQ_CODE = 16061;

private static final String TAG = "EasyPermissions";

public interface PermissionCallbacks extends
        ActivityCompat.OnRequestPermissionsResultCallback {

    void onPermissionsGranted(int requestCode, List<String> perms);

    void onPermissionsDenied(int requestCode, List<String> perms);

}

/**
 * Check if the calling context has a set of permissions.
 *
 * @param context the calling context.
 * @param perms   one ore more permissions, such as {@code android.Manifest.permission.CAMERA}.
 * @return true if all permissions are already granted, false if at least one permission
 * is not yet granted.
 */
public static boolean hasPermissions(Context context, String... perms) {
    // Always return true for SDK < M, let the system deal with the permissions
    if (Build.VERSION.SDK_INT < 23) {
        Log.w(TAG, "hasPermissions: API version < M, returning true by default");
        return true;
    }

    for (String perm : perms) {
        boolean hasPerm = (ContextCompat.checkSelfPermission(context, perm) ==
                PackageManager.PERMISSION_GRANTED);
        if (!hasPerm) {
            return false;
        }
    }

    return true;
}

/**
 * Request a set of permissions, showing rationale if the system requests it.
 *
 * @param object      Activity or Fragment requesting permissions. Should implement
 *                    {@link ActivityCompat.OnRequestPermissionsResultCallback}
 *                    or
 *
 * @param rationale   a message explaining why the application needs this set of permissions, will
 *                    be displayed if the user rejects the request the first time.
 * @param requestCode request code to track this request, must be < 256.
 * @param perms       a set of permissions to be requested.
 */
public static void requestPermissions(final Object object, String rationale,
                                      final int requestCode, final String... perms) {
    requestPermissions(object, rationale,
            android.R.string.ok,
            android.R.string.cancel,
            requestCode, perms);
}

/**
 * Request a set of permissions, showing rationale if the system requests it.
 *
 * @param object         Activity or Fragment requesting permissions. Should implement
 *                       {@link ActivityCompat.OnRequestPermissionsResultCallback}
 *                       or
 *
 * @param rationale      a message explaining why the application needs this set of permissions, will
 *                       be displayed if the user rejects the request the first time.
 * @param positiveButton custom text for positive button
 * @param negativeButton custom text for negative button
 * @param requestCode    request code to track this request, must be < 256.
 * @param perms          a set of permissions to be requested.
 */
public static void requestPermissions(final Object object, String rationale,
                                      @StringRes int positiveButton,
                                      @StringRes int negativeButton,
                                      final int requestCode, final String... perms) {

    checkCallingObjectSuitability(object);

    boolean shouldShowRationale = false;
    for (String perm : perms) {
        shouldShowRationale =
                shouldShowRationale || shouldShowRequestPermissionRationale(object, perm);
    }

    if (shouldShowRationale) {
        Activity activity = getActivity(object);
        if (null == activity) {
            return;
        }

           executePermissionsRequest(object, perms, requestCode);

    } else {
        executePermissionsRequest(object, perms, requestCode);
    }
}

/**
 * Handle the result of a permission request, should be called from the calling Activity's
 * {@link ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}
 * method.
 * <p>
 * If any permissions were granted or denied, the Activity will receive the appropriate
 * callbacks through {@link PermissionCallbacks} and methods annotated with
 * {@link AfterPermissionGranted} will be run if appropriate.
 *
 * @param requestCode  requestCode argument to permission result callback.
 * @param permissions  permissions argument to permission result callback.
 * @param grantResults grantResults argument to permission result callback.
 * @param object       the calling Activity or Fragment.
 * @throws IllegalArgumentException if the calling Activity does not implement
 *                                  {@link PermissionCallbacks}.
 */
public static void onRequestPermissionsResult(int requestCode, String[] permissions,
                                              int[] grantResults, Object object) {

    checkCallingObjectSuitability(object);

    // Make a collection of granted and denied permissions from the request.
    ArrayList<String> granted = new ArrayList<>();
    ArrayList<String> denied = new ArrayList<>();
    for (int i = 0; i < permissions.length; i++) {
        String perm = permissions[i];
        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
            granted.add(perm);
        } else {
            denied.add(perm);
        }
    }

    // Report granted permissions, if any.
    if (!granted.isEmpty()) {
        // Notify callbacks
        if (object instanceof PermissionCallbacks) {
            ((PermissionCallbacks) object).onPermissionsGranted(requestCode, granted);
        }
    }

    // Report denied permissions, if any.
    if (!denied.isEmpty()) {
        if (object instanceof PermissionCallbacks) {
            ((PermissionCallbacks) object).onPermissionsDenied(requestCode, denied);
        }
    }

    // If 100% successful, call annotated methods
    if (!granted.isEmpty() && denied.isEmpty()) {
        runAnnotatedMethods(object, requestCode);
    }
}

/**
 * Calls {@link #checkDeniedPermissionsNeverAskAgain(Object, String, int, int, DialogInterface.OnClickListener, List)}
 * with a {@code null} argument for the negatieb buttonOnClickListener.
 */
public static boolean checkDeniedPermissionsNeverAskAgain(final Object object,
                                                          String rationale,
                                                          @StringRes int positiveButton,
                                                          @StringRes int negativeButton,
                                                          List<String> deniedPerms) {
    return checkDeniedPermissionsNeverAskAgain(object, rationale,
            positiveButton, negativeButton, null, deniedPerms);
}

/**
 * If user denied permissions with the flag NEVER ASK AGAIN, open a dialog explaining the
 * permissions rationale again and directing the user to the app settings. After the user
 * returned to the app, {@link Activity#onActivityResult(int, int, Intent)} or
 * {@link Fragment#onActivityResult(int, int, Intent)} or
 * {@link android.app.Fragment#onActivityResult(int, int, Intent)} will be called with
 * {@value #SETTINGS_REQ_CODE} as requestCode
 * <p>
 * NOTE: use of this method is optional, should be called from
 * {@link PermissionCallbacks#onPermissionsDenied(int, List)}
 *
 * @param object                        the calling Activity or Fragment.
 * @param deniedPerms                   the set of denied permissions.
 * @param negativeButtonOnClickListener negative button on click listener. If the
 *                                      user click the negative button, then this listener will
 *                                      be called. Pass null if you don't want to handle it.
 * @return {@code true} if user denied at least one permission with the flag NEVER ASK AGAIN.
 */
public static boolean checkDeniedPermissionsNeverAskAgain(final Object object,
                                                          String rationale,
                                                          @StringRes int positiveButton,
                                                          @StringRes int negativeButton,
                                                          @Nullable DialogInterface.OnClickListener negativeButtonOnClickListener,
                                                          List<String> deniedPerms) {
    boolean shouldShowRationale;
    for (String perm : deniedPerms) {
        shouldShowRationale = shouldShowRequestPermissionRationale(object, perm);
        if (!shouldShowRationale) {
            final Activity activity = getActivity(object);
            if (null == activity) {
                return true;
            }             
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
            intent.setData(uri);
            startAppSettingsScreen(object, intent);    

            return true;
        }
    }

    return false;
}

@TargetApi(23)
private static boolean shouldShowRequestPermissionRationale(Object object, String perm) {
    if (object instanceof Activity) {
        return ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, perm);
    } else if (object instanceof Fragment) {
        return ((Fragment) object).shouldShowRequestPermissionRationale(perm);
    } else if (object instanceof android.app.Fragment) {
        return ((Fragment) object).shouldShowRequestPermissionRationale(perm);
    } else {
        return false;
    }
}

@TargetApi(23)
private static void executePermissionsRequest(Object object, String[] perms, int requestCode) {
    checkCallingObjectSuitability(object);

    if (object instanceof Activity) {
        ActivityCompat.requestPermissions((Activity) object, perms, requestCode);
    } else if (object instanceof Fragment) {
        ((Fragment) object).requestPermissions(perms, requestCode);
    } else if (object instanceof android.app.Fragment) {
        ((Fragment) object).requestPermissions(perms, requestCode);
    }
}

@TargetApi(11)
private static Activity getActivity(Object object) {
    if (object instanceof Activity) {
        return ((Activity) object);
    } else if (object instanceof Fragment) {
        return ((Fragment) object).getActivity();
    } else if (object instanceof android.app.Fragment) {
        return ((android.app.Fragment) object).getActivity();
    } else {
        return null;
    }
}

@TargetApi(11)
private static void startAppSettingsScreen(Object object,
                                           Intent intent) {
    if (object instanceof Activity) {
        ((Activity) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
    } else if (object instanceof Fragment) {
        ((Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
    } else if (object instanceof android.app.Fragment) {
        ((android.app.Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE);
    }
}

private static void runAnnotatedMethods(Object object, int requestCode) {
    Class clazz = object.getClass();
    if (isUsingAndroidAnnotations(object)) {
        clazz = clazz.getSuperclass();
    }
    for (Method method : clazz.getDeclaredMethods()) {
        if (method.isAnnotationPresent(AfterPermissionGranted.class)) {
            // Check for annotated methods with matching request code.
            AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class);
            if (ann.value() == requestCode) {
                // Method must be void so that we can invoke it
                if (method.getParameterTypes().length > 0) {
                    throw new RuntimeException(
                            "Cannot execute non-void method " + method.getName());
                }

                try {
                    // Make method accessible if private
                    if (!method.isAccessible()) {
                        method.setAccessible(true);
                    }
                    method.invoke(object);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "runDefaultMethod:IllegalAccessException", e);
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "runDefaultMethod:InvocationTargetException", e);
                }
            }
        }
    }
}

private static void checkCallingObjectSuitability(Object object) {
    // Make sure Object is an Activity or Fragment
    boolean isActivity = object instanceof Activity;
    boolean isSupportFragment = object instanceof Fragment;
    boolean isAppFragment = object instanceof android.app.Fragment;
    boolean isMinSdkM = Build.VERSION.SDK_INT >= 23;

    if (!(isSupportFragment || isActivity || (isAppFragment && isMinSdkM))) {
        if (isAppFragment) {
            throw new IllegalArgumentException(
                    "Target SDK needs to be greater than 23 if caller is android.app.Fragment");
        } else {
            throw new IllegalArgumentException("Caller must be an Activity or a Fragment.");
        }
    }
}

private static boolean isUsingAndroidAnnotations(Object object) {
        if (!object.getClass().getSimpleName().endsWith("_")) {
            return false;
        }

        try {
            Class clazz = Class.forName("org.androidannotations.api.view.HasViews");
            return clazz.isInstance(object);
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

定义接口

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterPermissionGranted {

    int value();

}

使用实例

//如果sdk<23返回true 即在AndroidManifest声明权限即可,>=23时要动态请求权限
if (!EasyPermissions.hasPermissions(this, Manifest.permission.CALL_PHONE)){
      EasyPermissions.requestPermissions(this,"拨打电话",3,Manifest.permission.CALL_PHONE);
 }else {
    Intent intentServePhoneOne = new      Intent(Intent.ACTION_CALL, Uri.parse("tel:5554");
    startActivity(intentServePhoneOne);
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值