Android 6.x runtime permissions

One of my teammates left, which caused me to be so busy lately that I didn't have time to write a blog.

I finally have a little free time in the past two days, so I will update an article as soon as possible.

Regarding the runtime permissions of Android 6.0 and above, it is estimated that it has been a headache for two days.

When I was doing it, due to various reasons, the version that had been released and launched on the Android 6.0 or higher system had problems and could not be used normally. To be precise, it did not include Android 6.0, because some mobile phones with 6.0 can be used. The last resort is to release a new version urgently, changing android:targetSdkVersion="23" to android:targetSdkVersion="22" means that we are not ready to adapt to mobile phones above 6.0.

Part of the reason for this problem is that the highest system version of our test machine is 6.0, including Huawei P9, mate8, and a colleague's Xiaomi, which can be used normally before the test. Another reason is that it was supposed to be the next version and then adapted to 6.0, but one of my teammates had already replaced the sdk to 23. After running it on the test machine, it was found that the functions of reading SMS verification codes and system contacts could not be used. After using it, I searched for the code on the Internet and found that there was no problem, and the version was released online. The seriousness of the matter was only discovered after receiving complaints from users after going online. We had to release the version urgently and remind users above 6.0 that they must uninstall and then download and install again, because our app needs to get the user's device id on the boot page when the app is opened, and If you want to continuously update the application, you also need to get the write permission of the SD card storage, and the online version does not apply for these two permissions for the mobile phone above 6.0, so the Android 6.0 mobile phone must be reinstalled.

Why does the permission problem that does not appear on the Android 6.0 mobile phone appear when it comes to the user? Finally, I found two Android 6.0.1 mobile phones at the same time and found the same problem. After debugging, I found that the problem is really serious. My personal opinion is that the higher the system with Android 6.0 or above, the stricter the handling of permission problems will be. The problem has already occurred, and I can only face it and solve it. I read some posts on the Internet, downloaded two demos, and finally found a better solution for my program.

Closer to home, due to the particularity of Android, once users of Android phones install some malicious apps, developers can do a lot of things, which poses great hidden dangers to users of these phones. Google has also been working on solving this problem. Finally, Android 6.0 Marshmallow was launched. The app will not grant app permissions across the board during installation. Instead, it will be replaced by some permissions that are more dangerous for users. The app has to be in the At runtime, users are asked one by one, and they can only be obtained after the user grants them.

General permissions, PROTECTION_NORMAL class permissions, automatically granted when the app is installed, no need to ask for authorization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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

Dangerous permissions. If you need such permissions in the application, you need to apply for authorization from the user. As you can see from the figure below, these permissions are grouped. At present, after a certain permission in the same group is authorized, other permissions in the same group will also be It is also authorized, but I do not recommend that you rely on this practice to save trouble. Maybe this group will be cancelled in the future. It is better to honestly apply to the user which permission is used.


There are also several special permissions and other permissions, which are generally not used, so I won't say more here.

First of all, you can first classify and group the permissions used in your project, like this:


Then there is the specific handling of the permission problem, the code is presented:

Pages that need to apply for permission:

	@Override
	protected void onResume() {
		super.onResume();
		// When the permission is missing, enter the permission configuration page
		if (mPermissionsChecker.lacksPermissions(PERMISSIONS)) {
			startPermissionsActivity();
		}else {
			doNext();
		}
	}
	
	private void startPermissionsActivity() {
		PermissionsActivity.startActivityForResult(this, getResources().getString(R.string.string_help_text2), REQUEST_CODE,
				PERMISSIONS);
	}
Permission processing intermediate page:
public class PermissionsActivity extends BaseActivity {
	public static final int PERMISSIONS_GRANTED = 0;
	// 权限授权
	public static final int PERMISSIONS_DENIED = 1;
	// 权限拒绝
	private static final int PERMISSION_REQUEST_CODE = 0;
	// 系统权限管理页面的参数
	private static final String EXTRA_PERMISSIONS = "me.szf.permission.extra_permission";
	private static final String HELP_TEXT = "me.szf.permission.help_text";
	// 权限参数
	private static final String PACKAGE_URL_SCHEME = "package:";
	// 权限检测器
	private PermissionsChecker mChecker;
	private boolean isRequireCheck;
	private String stringHelpText = "";

	// 是否需要系统权限检测
	// 启动当前权限页面的公开接口
	public static void startActivityForResult(Activity activity, String helpText,
			int requestCode, String... permissions) {
		Intent intent = new Intent(activity, PermissionsActivity.class);
		intent.putExtra(EXTRA_PERMISSIONS, permissions);
		intent.putExtra(HELP_TEXT, helpText);
		ActivityCompat.startActivityForResult(activity, intent, requestCode,
				null);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (getIntent() == null || !getIntent().hasExtra(EXTRA_PERMISSIONS)) {
			throw new RuntimeException("PermissionsActivity需要使用静态startActivityForResult方法启动!");
		}
		setContentView(R.layout.activity_permissions);
		mChecker = new PermissionsChecker(this);
		isRequireCheck = true;
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (isRequireCheck) {
			String[] permissions = getPermissions();
			stringHelpText = getIntent().getStringExtra(HELP_TEXT);
			if (mChecker.lacksPermissions(permissions)) {
				requestPermissions(permissions);// 请求权限
			} else {
				allPermissionsGranted();// 全部权限都已获取
			}
		} else {
			isRequireCheck = true;
		}
	}

	// 返回传递的权限参数
	private String[] getPermissions() {
		return getIntent().getStringArrayExtra(EXTRA_PERMISSIONS);
	}

	// 请求权限兼容低版本
	private void requestPermissions(String... permissions) {
		ActivityCompat.requestPermissions(this, permissions,
				PERMISSION_REQUEST_CODE);
	}

	// 全部权限均已获取
	private void allPermissionsGranted() {
		setResult(PERMISSIONS_GRANTED);
		finish();
	}

	/**
	 * 用户权限处理, 
	 * 如果全部获取, 则直接过. 
	 * 如果权限缺失, 则提示Dialog.
	 * @param requestCode 请求码
	 * @param permissions 权限 
	 * @param grantResults 结果
	 */
	@Override
	public void onRequestPermissionsResult(int requestCode,
			String[] permissions, int[] grantResults) {
		if (requestCode == PERMISSION_REQUEST_CODE
				&& hasAllPermissionsGranted(grantResults)) {
			isRequireCheck = true;
			allPermissionsGranted();
		} else {
			isRequireCheck = false;
			showMissingPermissionDialog();
		}
	}

	// 含有全部的权限
	private boolean hasAllPermissionsGranted(int[] grantResults) {
		for (int grantResult : grantResults) {
			if (grantResult == PackageManager.PERMISSION_DENIED) {
				return false;
			}
		}
		return true;
	}

	// 显示缺失权限提示
	private void showMissingPermissionDialog() {
		
		int width = getWindowManager().getDefaultDisplay().getWidth();
		LayoutInflater inflater = LayoutInflater.from(PermissionsActivity.this);
		View view = inflater.inflate(R.layout.permission_dialog, null);

		TextView tvContent = (TextView) view
				.findViewById(R.id.tv_permission_content);

		LinearLayout llContainer = (LinearLayout) view
				.findViewById(R.id.ll_permission_container);

		Button btnSetting = (Button) view.findViewById(R.id.btn_setting);
		Button btnQuit = (Button) view.findViewById(R.id.btn_quit);

		final Dialog dialog = new Dialog(PermissionsActivity.this,
				R.style.dialog_view);
		dialog.setCancelable(false);
		dialog.setContentView(llContainer, new LinearLayout.LayoutParams(
				(int) (width * 0.8), LinearLayout.LayoutParams.WRAP_CONTENT));
		tvContent.setText(stringHelpText);
		btnSetting.setOnClickListener(new android.view.View.OnClickListener() {

					@Override
					public void onClick(View v) {
						dialog.dismiss();
						startAppSettings();
					}
				});
		
		btnQuit.setOnClickListener(new android.view.View.OnClickListener() {

			@Override
			public void onClick(View v) {
				dialog.dismiss();
				setResult(PERMISSIONS_DENIED);
				sendBroadcast(new Intent("com.pica.mobilebusiness.exit"));
			}
		});

		dialog.show();
		
		
		
		/*final ReminderDialog2 dialog = new ReminderDialog2(
				PermissionsActivity.this, stringHelpText);
		dialog.setTitle(getResources().getString(R.string.help));
		dialog.setEnterTextLeft(getResources().getString(R.string.quit));
		dialog.setEnterTextRight(getResources().getString(R.string.setting));
		dialog.setCancelable(false);
		dialog.getEnterButtonLeft().setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				dialog.dismiss();
				setResult(PERMISSIONS_DENIED);
				sendBroadcast(new Intent("com.pica.mobilebusiness.exit"));
			}
		});
		dialog.getEnterButtonRight().setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				dialog.dismiss();
				startAppSettings();
			}
		});
		dialog.show();*/
	}

	// 启动应用的设置
	private void startAppSettings() {
		Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
		intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName()));
		startActivity(intent);
	}
}
权限检测器:
public class PermissionsChecker {
	private final Context mContext;

	public PermissionsChecker(Context context) {
		mContext = context.getApplicationContext();
	}

	// 判断权限集合
	public boolean lacksPermissions(String... permissions) {
		for (String permission : permissions) {
			if (lacksPermission(permission)) {
				return true;
			}
		}
		return false;
	}

	// 判断是否缺少权限 
	private boolean lacksPermission(String permission) {
		return ContextCompat.checkSelfPermission(mContext, permission) == PackageManager.PERMISSION_DENIED;
	}
}

大家可以根据自己项目的实际情况作为参考,demo地址: http://download.csdn.net/detail/cunjicsdn/9695519


                                                                                       



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326440754&siteId=291194637