Android6.0M权限管理实战,完美轻量级封装

PatMcLellan 8年前
   <p>随着 Android 版本的不断更新,Android再权限管理方面的诟病越来越明显。Google的Android开发人员也意识到了Android应用在权限管理方面的各种问题,让好多用户摸不着头脑就使用了用户的隐私数据。</p>    <p>为了在权限这方面加强管理,给用户一个比较好的体验。Android 6.0代号M的发布彻底解决了这一问题,取而代之的做法是这样的:</p>    <p>app在运行时逐个询问用户授予权限。Android 6.0(api23)M系统中,做了一些限制, 开发者在使用到每条权限时必须自己调用相关代码请求用户授予权限。如果没有获得某项权限,直接使用相关功能,则会导致自己程序crash.。为了解决这方面的问题,我们每次请求某一个权限要写好多代码解决这个问题,非常的麻烦。</p>    <p>下面是我做的一个轻量级的封装,可以减少很多重复的工作。</p>    <p>效果图</p>    <p>请求权限</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/80b48fd98a51d6e319fdb1ad94a5a233.png"></p>    <p>用户禁止了权限</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/cf36a9f24ff7696d30905b41ffa2b433.png"></p>    <h2><strong>一.Android6.0M对权限的划分</strong></h2>    <p>Android6.0M中对用户的权限分为了一般权限和危险权限,这些危险权限除了在AndroidManifest.xml中注册以外,还需要在使用的时候对用户进行请求权限弹窗提醒,才可以使用。</p>    <p>这些危险权限如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/bd8e19f8f90704c4c9655fc7460bbd34.png"></p>    <h2><strong>二.封装一个MPermissionsActivity的思路和步骤</strong></h2>    <ul>     <li>第一步:检测所有的权限是否都已授权</li>    </ul>    <pre>  <code class="language-java">/**        * 检测所有的权限是否都已授权        *        * @param permissions        * @return        */       private boolean checkPermissions(String[] permissions) {           if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {               return true;           }             for (String permission : permissions) {               if (ContextCompat.checkSelfPermission(this, permission) !=                       PackageManager.PERMISSION_GRANTED) {                   return false;               }           }           return true;       }</code></pre>    <ul>     <li>第二步:获取权限集中需要申请权限的列表</li>    </ul>    <pre>  <code class="language-java">/**       * 获取权限集中需要申请权限的列表       *       * @param permissions       * @return       */      private List<String> getDeniedPermissions(String[] permissions) {          List<String> needRequestPermissionList = new ArrayList<>();          for (String permission : permissions) {              if (ContextCompat.checkSelfPermission(this, permission) !=                      PackageManager.PERMISSION_GRANTED ||                      ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {                  needRequestPermissionList.add(permission);              }          }          return needRequestPermissionList;      }</code></pre>    <ul>     <li>第三步:请求权限</li>    </ul>    <pre>  <code class="language-java">/**       * 请求权限       *       * @param permissions 请求的权限       * @param requestCode 请求权限的请求码       */      public void requestPermission(String[] permissions, int requestCode) {          this.REQUEST_CODE_PERMISSION = requestCode;          if (checkPermissions(permissions)) {              permissionSuccess(REQUEST_CODE_PERMISSION);          } else {              List<String> needPermissions = getDeniedPermissions(permissions);              ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), REQUEST_CODE_PERMISSION);          }      }</code></pre>    <ul>     <li>第四步:处理权限请求回调</li>    </ul>    <pre>  <code class="language-java">/**       * 系统请求权限回调       *       * @param requestCode       * @param permissions       * @param grantResults       */      @Override      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {          super.onRequestPermissionsResult(requestCode, permissions, grantResults);          if (requestCode == REQUEST_CODE_PERMISSION) {              if (verifyPermissions(grantResults)) {                  permissionSuccess(REQUEST_CODE_PERMISSION);              } else {                  permissionFail(REQUEST_CODE_PERMISSION);                  showTipsDialog();              }          }      }</code></pre>    <ul>     <li>第五步:查看处理权限请求回调用户是否已经授权</li>    </ul>    <pre>  <code class="language-java">/**       * 确认所有的权限是否都已授权       *       * @param grantResults       * @return       */      private boolean verifyPermissions(int[] grantResults) {          for (int grantResult : grantResults) {              if (grantResult != PackageManager.PERMISSION_GRANTED) {                  return false;              }          }          return true;      }</code></pre>    <ul>     <li>第六步:授权成功处理函数</li>    </ul>    <pre>  <code class="language-java">/**       * 获取权限成功       *       * @param requestCode       */      public void permissionSuccess(int requestCode) {          Log.d(TAG, "获取权限成功=" + requestCode);        }</code></pre>    <ul>     <li>第七步:授权失败处理函数与弹出用户提示</li>    </ul>    <pre>  <code class="language-java">/**       * 权限获取失败       * @param requestCode       */      public void permissionFail(int requestCode) {          Log.d(TAG, "获取权限失败=" + requestCode);      }        /**       * 显示提示对话框       */      private void showTipsDialog() {          new AlertDialog.Builder(this)                  .setTitle("提示信息")                  .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")                  .setNegativeButton("取消", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                      }                  })                  .setPositiveButton("确定", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                          startAppSettings();                      }                  }).show();      }</code></pre>    <ul>     <li>第八步:授权失败给用户提示后想再次开启跳到设置app权限界面</li>    </ul>    <pre>  <code class="language-java">/**       * 启动当前应用设置页面       */      private void startAppSettings() {          Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);          intent.setData(Uri.parse("package:" + getPackageName()));          startActivity(intent);      }</code></pre>    <h2><strong>三.完整的MPermissionsActivity代码</strong></h2>    <pre>  <code class="language-java">package cn.bluemobi.dylan.mpermissions;    import android.content.DialogInterface;  import android.content.Intent;  import android.content.pm.PackageManager;  import android.net.Uri;  import android.os.Build;  import android.provider.Settings;  import android.support.annotation.NonNull;  import android.support.v4.app.ActivityCompat;  import android.support.v4.content.ContextCompat;  import android.support.v7.app.AlertDialog;  import android.support.v7.app.AppCompatActivity;  import android.util.Log;    import java.util.ArrayList;  import java.util.List;    /**   * Created by yuandl on 2016-11-16.   */    public class MPermissionsActivity extends AppCompatActivity {      private final String TAG = "MPermissions";      private int REQUEST_CODE_PERMISSION = 0x00099;        /**       * 请求权限       *       * @param permissions 请求的权限       * @param requestCode 请求权限的请求码       */      public void requestPermission(String[] permissions, int requestCode) {          this.REQUEST_CODE_PERMISSION = requestCode;          if (checkPermissions(permissions)) {              permissionSuccess(REQUEST_CODE_PERMISSION);          } else {              List<String> needPermissions = getDeniedPermissions(permissions);              ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), REQUEST_CODE_PERMISSION);          }      }        /**       * 检测所有的权限是否都已授权       *       * @param permissions       * @return       */      private boolean checkPermissions(String[] permissions) {          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {              return true;          }            for (String permission : permissions) {              if (ContextCompat.checkSelfPermission(this, permission) !=                      PackageManager.PERMISSION_GRANTED) {                  return false;              }          }          return true;      }        /**       * 获取权限集中需要申请权限的列表       *       * @param permissions       * @return       */      private List<String> getDeniedPermissions(String[] permissions) {          List<String> needRequestPermissionList = new ArrayList<>();          for (String permission : permissions) {              if (ContextCompat.checkSelfPermission(this, permission) !=                      PackageManager.PERMISSION_GRANTED ||                      ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {                  needRequestPermissionList.add(permission);              }          }          return needRequestPermissionList;      }        /**       * 系统请求权限回调       *       * @param requestCode       * @param permissions       * @param grantResults       */      @Override      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {          super.onRequestPermissionsResult(requestCode, permissions, grantResults);          if (requestCode == REQUEST_CODE_PERMISSION) {              if (verifyPermissions(grantResults)) {                  permissionSuccess(REQUEST_CODE_PERMISSION);              } else {                  permissionFail(REQUEST_CODE_PERMISSION);                  showTipsDialog();              }          }      }        /**       * 确认所有的权限是否都已授权       *       * @param grantResults       * @return       */      private boolean verifyPermissions(int[] grantResults) {          for (int grantResult : grantResults) {              if (grantResult != PackageManager.PERMISSION_GRANTED) {                  return false;              }          }          return true;      }        /**       * 显示提示对话框       */      private void showTipsDialog() {          new AlertDialog.Builder(this)                  .setTitle("提示信息")                  .setMessage("当前应用缺少必要权限,该功能暂时无法使用。如若需要,请单击【确定】按钮前往设置中心进行权限授权。")                  .setNegativeButton("取消", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                      }                  })                  .setPositiveButton("确定", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                          startAppSettings();                      }                  }).show();      }        /**       * 启动当前应用设置页面       */      private void startAppSettings() {          Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);          intent.setData(Uri.parse("package:" + getPackageName()));          startActivity(intent);      }        /**       * 获取权限成功       *       * @param requestCode       */      public void permissionSuccess(int requestCode) {          Log.d(TAG, "获取权限成功=" + requestCode);        }        /**       * 权限获取失败       * @param requestCode       */      public void permissionFail(int requestCode) {          Log.d(TAG, "获取权限失败=" + requestCode);      }  }</code></pre>    <h2><strong>四.用法</strong></h2>    <ul>     <li>布局文件activity_main.xml</li>    </ul>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:id="@+id/activity_main"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:orientation="vertical"      android:paddingBottom="@dimen/activity_vertical_margin"      android:paddingLeft="@dimen/activity_horizontal_margin"      android:paddingRight="@dimen/activity_horizontal_margin"      android:paddingTop="@dimen/activity_vertical_margin"      tools:context="cn.bluemobi.dylan.mpermissions.MainActivity">        <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="Hello World!" />        <Button          android:id="@+id/button"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:onClick="onClick1"          android:text="打电话" />        <Button          android:id="@+id/button2"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:onClick="onClick2"          android:text="写SD卡" />        <Button          android:id="@+id/button3"          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:onClick="onClick3"          android:text="拍照" />  </LinearLayout></code></pre>    <ul>     <li>MainActivity中使用:继承MPermissionsActivity即可</li>    </ul>    <pre>  <code class="language-java">package cn.bluemobi.dylan.mpermissions;    import android.Manifest;  import android.content.Intent;  import android.net.Uri;  import android.os.Bundle;  import android.view.View;    public class MainActivity extends MPermissionsActivity {        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);      }        /**       * 打电话       *       * @param view       */      public void onClick1(View view) {          requestPermission(new String[]{Manifest.permission.CALL_PHONE}, 0x0001);      }        /**       * 写SD卡       *       * @param view       */      public void onClick2(View view) {          requestPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x0002);      }        /**       * 拍照       *       * @param view       */      public void onClick3(View view) {          requestPermission(new String[]{Manifest.permission.CAMERA}, 0x0003);      }        /**       * 权限成功回调函数       *       * @param requestCode       */      @Override      public void permissionSuccess(int requestCode) {          super.permissionSuccess(requestCode);          switch (requestCode) {              case 0x0001:                  Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:13468857714"));                  startActivity(intent);                  break;          }        }    }</code></pre>    <p> </p>    <p> </p>