我将我的应用更新为Android 6兼容。权限模型在理论上并不复杂,但现在我正在实现它,我发现自己在每个需要权限的活动中编写了相同的丑陋样板代码。
对于我需要的每个许可,都有一个
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.PERMISSION) !=
PackageManager.PERMISSION_GRANTED) {
} else {
}
然后在onRequestPermissionsResult
我必须检查/过滤每个请求的结果,并将其转换为我的活动理解的内容。
我现在正在更新我的第二个活动,并且权限代码与第一个类似,它几乎看起来像是复制粘贴的。线条很长,代码很相似,看起来很丑陋。
我不想使用第三方解决方案,我尝试了一些,但我更愿意完全控制代码。例如,有些库不支持我在项目中使用的Java 8。
我可以做些什么来避免在我的所有活动中出现大量重复的代码?
答案 0 :(得分:8)
由于问题中解释的原因,我不想使用任何可用的库,所以我自己开发了一些东西。
我需要一个或多个权限的所有活动都从PermissionActivity
继承,处理所有与权限相关的任务。
如何运作您的活动
if (checkHasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { }
来自父类的。如果已授予权限,则代码可以继续。如果没有,父类将请求权限并使用抽象方法和/或一个或多个可重写方法将结果发送到子类。
父类
除messageForRationale()
和requestCodeForPermission()
中的切换块外,此类可以保持不变。更新您的应用所需权限。
/**
* An activity that can be extended to simplify handling permissions.
* <p>
* Deriving classes will not have to write boilerplate code and code duplication between activities
* that share this functionality is avoided.
*/
public abstract class PermissionActivity extends AppCompatActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// If multiple permissions were requested in one call, check if they were all granted.
if (requestCode == RequestCode.PERMISSION_MULTIPLE) {
boolean allPermissionsGranted = true;
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
allPermissionsGranted = false;
}
}
if (allPermissionsGranted) {
onAllPermissionsGranted(permissions);
return;
}
}
// Else, check each one if it was granted/denied/blocked.
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
// User granted permission.
onPermissionGranted(permissions[i]);
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
// User denied permission.
onPermissionDenied(permissions[i]);
} else {
// User denied permission and checked 'never ask again'.
onPermissionBlocked(permissions[i]);
}
}
}
}
/**
* Checks if the app has the given permission(s).
* <p>
* If not, it will request them.
* <p>
* The method is called `checkHasPermission` to avoid the linter showing a warning in the
* child class when it's delegating permission checks to its parent class. See
* http://stackoverflow.com/questions/36031218/check-android-permissions-in-a
* -method/36193309#36193309 for details.
*/
public boolean checkHasPermission(int requestCode, String... permissions) {
if (!(permissions.length > 0)) {
throw new IllegalArgumentException("must request at least one permission");
}
if (requestCode == RequestCode.PERMISSION_MULTIPLE) {
List<String> permissions_ = new ArrayList<>();
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED) {
permissions_.add(permission);
}
}
if (!permissions_.isEmpty()) {
requestPermissions(this, permissions_.toArray(new String[permissions_.size()]), requestCode);
return false;
} else {
return true;
}
} else {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) !=
PackageManager.PERMISSION_GRANTED) {
requestPermissions(this, permissions, requestCode);
return false;
} else {
return true;
}
}
}
/**
* Requests the given permissions.
*/
private void requestPermissions(Activity activity, String permissions[], int resultCode) {
showRequestPermissionsDialog(activity, permissions, resultCode);
}
/**
* Called when a rationale (explanation why a permission is needed) should be shown to the user.
* <p>
* If the user clicks the positive button, the permission is requested again, otherwise the
* dialog is dismissed.
*/
public void showRationaleDialog(Activity activity, String permission, String message,
int resultCode) {
new AlertDialog.Builder(activity)
.setMessage(message)
.setPositiveButton("ok", (dialog, which) ->
showRequestPermissionDialog(activity, permission, resultCode))
.setNegativeButton("not now", (dialog, which) -> { /* Do nothing */ })
.show();
}
/**
* Requests a single permission.
*/
private void showRequestPermissionDialog(Activity activity, String permission, int resultCode) {
ActivityCompat.requestPermissions(activity, new String[]{permission}, resultCode);
}
/**
* Requests multiple permissions in one call.
*/
private void showRequestPermissionsDialog(Activity activity, String[] permissions,
int resultCode) {
ActivityCompat.requestPermissions(activity, permissions, resultCode);
}
/**
* Returns a message to be shown to the user that explains why a specific permission is
* required.
*/
public String messageForRationale(String permission) {
String s;
switch (permission) {
case Manifest.permission.READ_PHONE_STATE:
s = "access this device's state";
break;
case Manifest.permission.ACCESS_FINE_LOCATION:
s = "access the location of this device";
break;
case Manifest.permission.SEND_SMS:
s = "send text messages";
break;
default:
throw new IllegalArgumentException("Permission not handled: " + permission);
}
return String.format("MyApp needs permission to %s.", s);
}
/**
* Get the RequestCode for the given permission.
*/
public int requestCodeForPermission(String permission) {
int code;
switch (permission) {
case Manifest.permission.READ_PHONE_STATE:
code = RequestCode.PERMISSION_READ_PHONE_STATE;
break;
case Manifest.permission.ACCESS_FINE_LOCATION:
code = RequestCode.PERMISSION_FINE_LOCATION;
break;
case Manifest.permission.SEND_SMS:
code = RequestCode.PERMISSION_SEND_SMS;
break;
// TODO: add required permissions for your app
default:
throw new IllegalArgumentException("Permission not handled: " + permission);
}
return code;
}
/**
* Called if all requested permissions were granted in the same dialog.
* E.g. FINE_LOCATION and SEND_SMS were requested, and both were granted.
* <p>
* Child class can override this method if it wants to know when this happens.
* <p>
* Linter can show an unjust "call requires permission" warning in child class if a method that
* requires permission(s) is called. Silence it with `@SuppressWarnings("MissingPermission")`.
*/
protected void onAllPermissionsGranted(String[] permissions) {
}
/**
* Called for all permissions that were granted in the same dialog, in case not all were
* granted. E.g. if FINE_LOCATION, COARSE_LOCATION and SEND_SMS were requested and FINE_LOCATION
* was not granted but COARSE_LOCATION and SEND_SMS were, it will be called for COARSE_LOCATION
* and SEND_SMS.
* <p>
* Child class can override this method if it wants to know when this happens.
* <p>
* Linter can show an unjust "call requires permission" warning in child class if a method that
* requires permission(s) is called. Silence it with `@SuppressWarnings("MissingPermission")`.
*/
protected void onPermissionGranted(String permission) {
}
/**
* Called for all permissions that were denied in the same dialog, handled one by one.
* <p>
* Child class should not override this general behavior.
*/
protected void onPermissionDenied(String permission) {
String message = messageForRationale(permission);
showRationaleDialog(this, permission, message, requestCodeForPermission(permission));
}
/**
* Called for all permissions that were blocked in the same dialog, handled one by one.
* <p>
* Blocked means a user denied a permission with the 'never ask again' checkbox checked.
* <p>
* Child class must override and decide what to do when a permission is blocked.
*/
protected abstract void onPermissionBlocked(String permission);
}
->
符号为lambda expressions。
RequestCode 是一个仅用于抽象数字的接口:
public interface RequestCode {
int PERMISSION_READ_PHONE_STATE = 0;
int PERMISSION_FINE_LOCATION = 1;
int PERMISSION_SEND_SMS = 2;
int PERMISSION_MULTIPLE = 3;
}
你可以随意改变它。不要使用超过256的数字。如果你这样做,会抛出一个例外
您只能将低8位用于请求代码。
在需要权限的活动中,您可以像这样使用它(只是一个例子)。请务必进行活动extend PermissionActivity
private void callThisSomewhere() {
if (checkHasPermission(RequestCode.PERMISSION_READ_PHONE_STATE,
Manifest.permission.READ_PHONE_STATE)) {
tryDoStuffWithPhoneState();
}
}
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
private void doStuffWithPhoneState() {
// Do stuff.
}
@Override
public void onPermissionGranted(String permission) {
tryDoStuffWithPhoneState();
}
@Override
public void onPermissionBlocked(String permission) {
// Disable parts of app that require this permission.
}
如果您要一次请求多个权限,则应使用RequestCode.PERMISSION_MULTIPLE
。否则,只会请求第一个许可。
AndroidManifest.xml中未列出的权限将自动阻止,而不向用户显示对话框,因此请务必在清单中添加您要请求的任何权限。
<强>限制强>
此解决方案与片段或服务不兼容。
答案 1 :(得分:1)
这是我用来管理应用程序权限的内容。
允许的父类
public class PermissionManager extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {
private static final int REQUEST_CODE = 200;
private Activity context;
private String[] permissions;
private ArrayList<String> grantedPermissions = new ArrayList<>();
private RequestedPermissionResultCallBack callBack;
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
}
@Override
protected void onStart() {
super.onStart();
setContentView(R.layout.actvity_permission);
checkForRequiredPermission(getIntent().getStringArrayExtra(getString(R.string.permission)));
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
checkForGrantedPermissions(permissions, grantResults);
break;
}
}
@TargetApi(Build.VERSION_CODES.M)
private void checkForRequiredPermission(String[] permissions) {
ArrayList<String> requiredPermissionList = new ArrayList<>();
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
requiredPermissionList.add(permission);
} else {
grantedPermissions.add(permission);
}
}
if (requiredPermissionList.size() > 0) {
(this).requestPermissions(requiredPermissionList.toArray(new String[requiredPermissionList.size()]), REQUEST_CODE);
} else {
setResult(grantedPermissions);
}
}
public void checkForGrantedPermissions(String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
grantedPermissions.add(permissions[i]);
}
}
setResult(grantedPermissions);
}
private void setResult(ArrayList<String> grantedPermissions) {
Intent intent = new Intent();
intent.putStringArrayListExtra(getString(R.string.granted_permission), grantedPermissions);
setResult(Activity.RESULT_OK, intent);
this.finish();
}
}
当您想要检查权限时,请像这样调用此类
private void checkForPermissions() {
Intent intent = new Intent(this, PermissionManager.class);
intent.putExtra(getString(R.string.permission), permission);
startActivityForResult(intent, AppConstants.PERMSION_REQUEST_CODE);
}
此处权限是您要求的权限数组 像这样的东西
private String permission[] = new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS};
这是 onActivityResult
的代码case AppConstants.PERMSION_REQUEST_CODE:
ArrayList<String> grantedPermissionList = data.getStringArrayListExtra(getString(R.string.granted_permission));
if (grantedPermissionList != null && grantedPermissionList.size() > 0 && grantedPermissionList.contains(permission[0])) {
createRequest();
} else {
showSettingsDialog(getString(R.string.permission_required));
}
break;