【问题标题】:Android runtime permissions- how to implementAndroid运行时权限——如何实现
【发布时间】:2016-05-11 21:02:48
【问题描述】:

Android Developer Documentation 给出了这个在运行时请求权限的例子:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

本例中的“MY_PERMISSIONS_REQUEST_READ_CONTACTS”是什么?它说它是一个应用程序定义的 int 常量,但这是否意味着我应该创建一个 Constants.java 并声明一个公共静态 int?值应该是多少?

在其他示例中,我看到人们在这里使用 1,或 0 或 0xFFEEDDCC,但我找不到它是什么的解释。有人可以向我解释这里需要什么以及为什么? (在我的情况下,我需要确保该应用有权访问精细位置)

ActivityCompat 文档说“应用程序特定的请求代码与报告给 onRequestPermissionsResult 的结果相匹配”?这对我没有帮助。

【问题讨论】:

标签: java android permissions android-6.0-marshmallow


【解决方案1】:

本例中的“MY_PERMISSIONS_REQUEST_READ_CONTACTS”是什么?

这是一个int,将特定的requestPermissions() 调用绑定到相应的onRequestPermissionsResult() 回调。

在幕后,requestPermissions() 使用startActivityForResult();这个int 的作用与它在startActivityForResult() 中的作用相同。

这是否意味着我应该创建一个 Constants.java 并声明一个公共静态 int?

我会在活动中将其设为private static final int。但是,您可以在任何地方声明它。

值应该是多少?

我似乎记得它需要低于 0x8000000,否则它可以是任何你想要的。您在活动中为每个 requestPermissions() 调用使用的值应该得到不同的 int,但实际数字无关紧要。

如果您的活动只有一个requestPermissions() 调用,那么int 值真的无关紧要。但是许多应用程序在一个活动中会有多个requestPermissions() 调用。在这种情况下,开发人员可能需要在onRequestPermissionsResult() 中知道这是什么请求的结果。

【讨论】:

    【解决方案2】:

    在“处理权限请求响应”下的文档中再往下看一点,您就会看到它的用途。

    一个名为 onRequestPermissionsResult 的回调方法会返回与参数相同的代码,以便您知道正在请求/授予哪个权限:

    @Override
    public void onRequestPermissionsResult(int requestCode,
            String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
    
                } else {
    
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }
    
            // other 'case' lines to check for other
            // permissions this app might request
        }
    }
    

    由于该常量仅由您使用,因此您可以给它任何您喜欢的值作为public static final int。每个被请求的权限都需要自己的常量。

    【讨论】:

      【解决方案3】:

      我浏览了所有答案,但不满足我确切需要的答案,所以这是一个我编写的并且完美运行的示例,即使用户点击了不再询问复选框。

      1. 创建一个方法,当你想请求运行时权限时会调用它,比如readContacts(),或者你也可以拥有openCamera(),如下所示:

        private void readContacts() {
            if (!askContactsPermission()) {
                return;
            } else {
                queryContacts();
            } }
        

      现在我们需要创建askContactsPermission(),您也可以将其命名为askCameraPermission() 或您要请求的任何权限。

          private boolean askContactsPermission() {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
              return true;
          }
          if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
              return true;
          }
          if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
              Snackbar.make(parentLayout, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
                      .setAction(android.R.string.ok, new View.OnClickListener() {
                          @Override
                          @TargetApi(Build.VERSION_CODES.M)
                          public void onClick(View v) {
                              requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
                          }
                      }).show();
          } else if (contactPermissionNotGiven) {
              openPermissionSettingDialog();
          } else {
              requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
              contactPermissionNotGiven = true;
      
          }
          return false;
      }
      

      在编写此函数之前,请确保您已定义如下实例变量,如下所示:

          private View parentLayout;
          private boolean contactPermissionNotGiven;;
      
      
      /**
       * Id to identity READ_CONTACTS permission request.
       */
      private static final int REQUEST_READ_CONTACTS = 0;
      

      现在是覆盖onRequestPermissionsResult 方法的最后一步,如下所示:

      /**
       * Callback received when a permissions request has been completed.
       */
      @RequiresApi(api = Build.VERSION_CODES.M)
      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                             @NonNull int[] grantResults) {
          if (requestCode == REQUEST_READ_CONTACTS) {
              if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                  queryContacts();
              }
          }
      }
      

      这里我们完成了运行时权限,插件是openPermissionSettingDialog(),如果用户通过单击不再询问复选框永久禁用权限,它只需打开设置屏幕。下面是方法:

          private void openPermissionSettingDialog() {
          String message = getString(R.string.message_permission_disabled);
          AlertDialog alertDialog =
                  new AlertDialog.Builder(MainActivity.this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
                          .setMessage(message)
                          .setPositiveButton(getString(android.R.string.ok),
                                  new DialogInterface.OnClickListener() {
                                      @Override
                                      public void onClick(DialogInterface dialog, int which) {
                                          Intent intent = new Intent();
                                          intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                          Uri uri = Uri.fromParts("package", getPackageName(), null);
                                          intent.setData(uri);
                                          startActivity(intent);
                                          dialog.cancel();
                                      }
                                  }).show();
          alertDialog.setCanceledOnTouchOutside(true);
      }
      

      我们错过了什么? 1.在strings.xml中定义使用的字符串

      <string name="permission_rationale">"Contacts permissions are needed to display Contacts."</string>
          <string name="message_permission_disabled">You have disabled the permissions permanently,
              To enable the permissions please go to Settings -> Permissions and enable the required Permissions,
              pressing OK you will be navigated to Settings screen</string>
      
      1. onCreate方法中初始化parentLayout变量

        parentLayout = findViewById(R.id.content);

      2. AndroidManifest.xml中定义所需的权限

      <uses-permission android:name="android.permission.READ_CONTACTS" />
      
      1. queryContacts 方法,根据您的需要或运行时权限,您可以调用需要permission 的方法。就我而言,我只是使用加载器来获取联系人,如下所示:

        private void queryContacts() {
        getLoaderManager().initLoader(0, null, this);}
        

      这工作非常愉快的编码:)

      【讨论】:

        【解决方案4】:
        public class SplashActivity extends RuntimePermissionsActivity {
        
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
        
            SplashActivity.super.requestAppPermissions(new
                            String[]{android.Manifest.permission.READ_PHONE_STATE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE,
                            Manifest.permission.READ_EXTERNAL_STORAGE}, R.string.app_name
                    , 20);
        
        }
        
        @Override
        public void onPermissionsGranted(int requestCode) {
        
        
            try {
                TelephonyManager tele = (TelephonyManager) getApplicationContext()
                        .getSystemService(Context.TELEPHONY_SERVICE);
        
                String imei =tele.getDeviceId()
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        public abstract class RuntimePermissionsActivity extends AppCompatActivity {
        private SparseIntArray mErrorString;
        
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mErrorString = new SparseIntArray();
        }
        
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            int permissionCheck = PackageManager.PERMISSION_GRANTED;
            for (int permission : grantResults) {
                permissionCheck = permissionCheck + permission;
            }
            if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) {
                onPermissionsGranted(requestCode);
            } else {
        
                finish();
        
            }
        }
        
        public void requestAppPermissions(final String[] requestedPermissions,
                                          final int stringId, final int requestCode) {
            mErrorString.put(requestCode, stringId);
            int permissionCheck = PackageManager.PERMISSION_GRANTED;
            boolean shouldShowRequestPermissionRationale = false;
            for (String permission : requestedPermissions) {
                permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
                shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
            }
            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
                if (shouldShowRequestPermissionRationale) {
                    ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
                    /*Snackbar.make(findViewById(android.R.id.content), stringId,
                            Snackbar.LENGTH_INDEFINITE).setAction("GRANT",
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
                                }
                            }).show();*/
                } else {
                    ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
                }
            } else {
                onPermissionsGranted(requestCode);
            }
        }
        
        public abstract void onPermissionsGranted(int requestCode);
        

        }

        【讨论】:

          猜你喜欢
          • 2017-07-05
          • 1970-01-01
          • 2021-10-05
          • 2016-03-25
          • 1970-01-01
          • 2018-05-10
          • 1970-01-01
          • 2017-10-17
          • 1970-01-01
          相关资源
          最近更新 更多