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);
}