Android棉花糖请求权限?

Posted

技术标签:

【中文标题】Android棉花糖请求权限?【英文标题】:Android marshmallow request permission? 【发布时间】:2016-02-13 11:02:50 【问题描述】:

我目前正在开发一个需要多个“危险”权限的应用程序。所以我尝试在android Marshmallow(API Level 23)中添加“请求许可”,但找不到如何做到这一点。

如何在我的应用中使用新的权限模型请求权限?

【问题讨论】:

看看这里,这就是你所需要的:developer.android.com/training/permissions/requesting.html 看看这个inthecheesefactory.com/blog/… 您查看过 Google GitHub 存储库中的示例吗? 从developer.android.com/training/permissions/requesting.html看到的,当时我是android新手,很快android Marshmallow就来了,google的培训让我更加困惑,找不到有关此的任何教程 我已经为它创建了库。通过简单的步骤即可轻松使用。 github.com/Kishanjvaghela/Ask-Permission 【参考方案1】:

我从我的旧代码中找到了一个解决方案,它真的很好用,仍在我的最新应用程序上运行。

把它放在 MainActivity 类或你的 Start Activity 类上

private RequestPermissionHandler mRequestPermissionHandler;

创建时

@Override
protected void onCreate(Bundle savedInstanceState) 
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   mRequestPermissionHandler = new RequestPermissionHandler();
   handleButtonClicked();

私有函数handleButtonClicked()

private void handleButtonClicked() 
        mRequestPermissionHandler.requestPermission(this, new String[]
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.WAKE_LOCK

        , 123, new RequestPermissionHandler.RequestPermissionListener() 
            @Override
            public void onSuccess() 
                //Toast.makeText(MainActivity.this, "request permission success", Toast.LENGTH_SHORT).show();
            

            @Override
            public void onFailed() 
                Toast.makeText(MainActivity.this, "request permission failed", Toast.LENGTH_SHORT).show();
            
        );

    

RequestPermissionHandler.java 类

import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

public class RequestPermissionHandler 
    private Activity mActivity;
    private RequestPermissionListener mRequestPermissionListener;
    private int mRequestCode;

    public void requestPermission(Activity activity, @NonNull String[] permissions, int requestCode,
                                  RequestPermissionListener listener) 
        mActivity = activity;
        mRequestCode = requestCode;
        mRequestPermissionListener = listener;

        if (!needRequestRuntimePermissions()) 
            mRequestPermissionListener.onSuccess();
            return;
        
        requestUnGrantedPermissions(permissions, requestCode);
    

    private boolean needRequestRuntimePermissions() 
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    

    private void requestUnGrantedPermissions(String[] permissions, int requestCode) 
        String[] unGrantedPermissions = findUnGrantedPermissions(permissions);
        if (unGrantedPermissions.length == 0) 
            mRequestPermissionListener.onSuccess();
            return;
        
        ActivityCompat.requestPermissions(mActivity, unGrantedPermissions, requestCode);
    

    private boolean isPermissionGranted(String permission) 
        return ActivityCompat.checkSelfPermission(mActivity, permission)
                == PackageManager.PERMISSION_GRANTED;
    

    private String[] findUnGrantedPermissions(String[] permissions) 
        List<String> unGrantedPermissionList = new ArrayList<>();
        for (String permission : permissions) 
            if (!isPermissionGranted(permission)) 
                unGrantedPermissionList.add(permission);
            
        
        return unGrantedPermissionList.toArray(new String[0]);
    

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) 
        if (requestCode == mRequestCode) 
            if (grantResults.length > 0) 
                for (int grantResult : grantResults) 
                    if (grantResult != PackageManager.PERMISSION_GRANTED) 
                        mRequestPermissionListener.onFailed();
                        return;
                    
                
                mRequestPermissionListener.onSuccess();
             else 
                mRequestPermissionListener.onFailed();
            
        
    

    public interface RequestPermissionListener 
        void onSuccess();

        void onFailed();
    

【讨论】:

【参考方案2】:

将权限添加到AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application ...>
 ....
</application>

检查Android版本是否需要运行时权限。

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) 
    askForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 1);

如果未授予权限,请用户授予权限。

private void askForPermission(String permission, int requestCode) 
    if (ContextCompat.checkSelfPermission(c, permission)
            != PackageManager.PERMISSION_GRANTED) 
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) 
            Toast.makeText(c, "Please grant the requested permission to get your task done!", Toast.LENGTH_LONG).show();
            ActivityCompat.requestPermissions(MainActivity.this, new String[]permission, requestCode);
         else 
            ActivityCompat.requestPermissions(MainActivity.this, new String[]permission, requestCode);
        
    

无论是否获得许可,都做某事。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
    switch (requestCode) 
        case 1:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                //permission with request code 1 granted
                Toast.makeText(this, "Permission Granted" , Toast.LENGTH_LONG).show();
             else 
                //permission with request code 1 was not granted
                Toast.makeText(this, "Permission was not Granted" , Toast.LENGTH_LONG).show();
            
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    

【讨论】:

【参考方案3】:

Android 中的运行时权限

private static final int PERMISSION_REQ_WRITE_EXTERNAL_STORAGE = 101;

public void onClick(View view) 
    if (view.getId() == yourBtn.getId()) 
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) 
            this.storageWork();
         else 
            ActivityCompat.requestPermissions(this, new String[]  Manifest.permission.WRITE_EXTERNAL_STORAGE , PERMISSION_REQ_WRITE_EXTERNAL_STORAGE);
        
    


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
    if (requestCode == PERMISSION_REQ_WRITE_EXTERNAL_STORAGE) 
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
            this.storageWork();
        
    


public void storageWork()

OnClick 方法是检查运行时权限

如果权限受到限制,则请求权限

【讨论】:

【参考方案4】:

如果您使用的是AndroidX Activity 1.2.0 或AndroidX Fragment 1.3.0

您可以使用新的活动结果 API 来请求权限:

val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission())  isGranted ->
    if (isGranted) 
        // Permission granted. Do the tasks.
    

launcher.launch(Manifest.permission.ACCESS_FINE_LOCATION)

【讨论】:

警告!截至 2020 年 9 月,这两个库仍处于 alpha 阶段。 仍然不稳定所以我不推荐这个功能。【参考方案5】:

运行时权限会在高度耦合的活动中创建大量样板代码。为了减少代码并使事情变得简单,您可以使用Dexter 库。

【讨论】:

【参考方案6】:

从 Android Marshmallow 开始,我们需要向用户请求特定权限。我们还可以通过代码检查是否已经授予权限。以下是常用权限列表:

android.permission_group.CALENDAR

android.permission.READ_CALENDAR android.permission.WRITE_CALENDAR

android.permission_group.CAMERA

android.permission.CAMERA

android.permission_group.CONTACTS

android.permission.READ_CONTACTS android.permission.WRITE_CONTACTS android.permission.GET_ACCOUNTS

android.permission_group.LOCATION

android.permission.ACCESS_FINE_LOCATION android.permission.ACCESS_COARSE_LOCATION

android.permission_group.MICROPHONE

android.permission.RECORD_AUDIO

android.permission_group.PHONE

android.permission.READ_PHONE_STATE android.permission.CALL_PHONE android.permission.READ_CALL_LOG android.permission.WRITE_CALL_LOG android.permission.ADD_VOICEMAIL android.permission.USE_SIP android.permission.PROCESS_OUTGOING_CALLS

android.permission_group.SENSORS

android.permission.BODY_SENSORS

android.permission_group.SMS

android.permission.SEND_SMS android.permission.RECEIVE_SMS android.permission.READ_SMS android.permission.RECEIVE_WAP_PUSH android.permission.RECEIVE_MMS android.permission.READ_CELL_BROADCASTS

android.permission_group.STORAGE

android.permission.READ_EXTERNAL_STORAGE android.permission.WRITE_EXTERNAL_STORAGE

这是检查权限的示例代码:

if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED) 
    if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.WRITE_CALENDAR)) 
        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
        alertBuilder.setCancelable(true);
        alertBuilder.setMessage("Write calendar permission is necessary to write event!!!");
        alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() 
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            public void onClick(DialogInterface dialog, int which) 
                ActivityCompat.requestPermissions((Activity)context, new String[]Manifest.permission.WRITE_CALENDAR, MY_PERMISSIONS_REQUEST_WRITE_CALENDAR);
            
        );
     else 
        ActivityCompat.requestPermissions((Activity)context, new String[]Manifest.permission.WRITE_CALENDAR, MY_PERMISSIONS_REQUEST_WRITE_CALENDAR);
    

【讨论】:

【参考方案7】:

我的班级在ActivityFragment 中请求运行时权限

它还可以帮助您更轻松地显示基本原理或打开设置以在用户拒绝权限后启用权限(带/不带Never ask again)选项更容易

class RequestPermissionHandler(private val activity: Activity? = null,
                               private val fragment: Fragment? = null,
                               private val permissions: Set<String> = hashSetOf(),
                               private val listener: Listener? = null
) 
    private var hadShowRationale: Boolean = false

    fun requestPermission() 
        hadShowRationale = showRationaleIfNeed()
        if (!hadShowRationale) 
            doRequestPermission(permissions)
        
    

    fun retryRequestDeniedPermission() 
        doRequestPermission(permissions)
    

    private fun showRationaleIfNeed(): Boolean 
        val unGrantedPermissions = getPermission(permissions, Status.UN_GRANTED)
        val permanentDeniedPermissions = getPermission(unGrantedPermissions, Status.PERMANENT_DENIED)
        if (permanentDeniedPermissions.isNotEmpty()) 
            val consume = listener?.onShowSettingRationale(unGrantedPermissions)
            if (consume != null && consume) 
                return true
            
        

        val temporaryDeniedPermissions = getPermission(unGrantedPermissions, Status.TEMPORARY_DENIED)
        if (temporaryDeniedPermissions.isNotEmpty()) 
            val consume = listener?.onShowPermissionRationale(temporaryDeniedPermissions)
            if (consume != null && consume) 
                return true
            
        
        return false
    

    fun requestPermissionInSetting() 
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        val packageName = activity?.packageName ?: run 
            fragment?.requireActivity()?.packageName
        
        val uri = Uri.fromParts("package", packageName, null)
        intent.data = uri
        activity?.apply 
            startActivityForResult(intent, REQUEST_CODE)
         ?: run 
            fragment?.startActivityForResult(intent, REQUEST_CODE)
        
    

    fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
                                   grantResults: IntArray) 
        if (requestCode == REQUEST_CODE) 
            for (i in grantResults.indices) 
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) 
                    markNeverAskAgainPermission(permissions[i], false)
                 else if (!shouldShowRequestPermissionRationale(permissions[i])) 
                    markNeverAskAgainPermission(permissions[i], true)
                
            
            var hasShowRationale = false
            if (!hadShowRationale) 
                hasShowRationale = showRationaleIfNeed()
            
            if (hadShowRationale || !hasShowRationale) 
                notifyComplete()
            
        
    

    fun onActivityResult(requestCode: Int) 
        if (requestCode == REQUEST_CODE) 
            getPermission(permissions, Status.GRANTED).forEach 
                markNeverAskAgainPermission(it, false)
            
            notifyComplete()
        
    

    fun cancel() 
        notifyComplete()
    

    private fun doRequestPermission(permissions: Set<String>) 
        activity?.let 
            ActivityCompat.requestPermissions(it, permissions.toTypedArray(), REQUEST_CODE)
         ?: run 
            fragment?.requestPermissions(permissions.toTypedArray(), REQUEST_CODE)
        
    

    private fun getPermission(permissions: Set<String>, status: Status): Set<String> 
        val targetPermissions = HashSet<String>()
        for (p in permissions) 
            when (status) 
                Status.GRANTED -> 
                    if (isPermissionGranted(p)) 
                        targetPermissions.add(p)
                    
                
                Status.TEMPORARY_DENIED -> 
                    if (shouldShowRequestPermissionRationale(p)) 
                        targetPermissions.add(p)
                    
                
                Status.PERMANENT_DENIED -> 
                    if (isNeverAskAgainPermission(p)) 
                        targetPermissions.add(p)
                    
                
                Status.UN_GRANTED -> 
                    if (!isPermissionGranted(p)) 
                        targetPermissions.add(p)
                    
                
            
        
        return targetPermissions
    

    private fun isPermissionGranted(permission: String): Boolean 
        return activity?.let 
            ActivityCompat.checkSelfPermission(it, permission) == PackageManager.PERMISSION_GRANTED
         ?: run 
            ActivityCompat.checkSelfPermission(fragment!!.requireActivity(), permission) == PackageManager.PERMISSION_GRANTED
        
    

    private fun shouldShowRequestPermissionRationale(permission: String): Boolean 
        return activity?.let 
            ActivityCompat.shouldShowRequestPermissionRationale(it, permission)
         ?: run 
            ActivityCompat.shouldShowRequestPermissionRationale(fragment!!.requireActivity(), permission)
        
    

    private fun notifyComplete() 
        listener?.onComplete(getPermission(permissions, Status.GRANTED), getPermission(permissions, Status.UN_GRANTED))
    

    private fun getPrefs(context: Context): SharedPreferences 
        return context.getSharedPreferences("SHARED_PREFS_RUNTIME_PERMISSION", Context.MODE_PRIVATE)
    

    private fun isNeverAskAgainPermission(permission: String): Boolean 
        return getPrefs(requireContext()).getBoolean(permission, false)
    

    private fun markNeverAskAgainPermission(permission: String, value: Boolean) 
        getPrefs(requireContext()).edit().putBoolean(permission, value).apply()
    

    private fun requireContext(): Context 
        return fragment?.requireContext() ?: run 
            activity!!
        
    

    enum class Status 
        GRANTED, UN_GRANTED, TEMPORARY_DENIED, PERMANENT_DENIED
    

    interface Listener 
        fun onComplete(grantedPermissions: Set<String>, deniedPermissions: Set<String>)
        fun onShowPermissionRationale(permissions: Set<String>): Boolean
        fun onShowSettingRationale(permissions: Set<String>): Boolean
    

    companion object 
        const val REQUEST_CODE = 200
    

Activity 中使用喜欢

class MainActivity : AppCompatActivity() 
    private lateinit var smsAndStoragePermissionHandler: RequestPermissionHandler

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        smsAndStoragePermissionHandler = RequestPermissionHandler(this@MainActivity,
                permissions = setOf(Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_EXTERNAL_STORAGE),
                listener = object : RequestPermissionHandler.Listener 
                    override fun onComplete(grantedPermissions: Set<String>, deniedPermissions: Set<String>) 
                        Toast.makeText(this@MainActivity, "complete", Toast.LENGTH_SHORT).show()
                        text_granted.text = "Granted: " + grantedPermissions.toString()
                        text_denied.text = "Denied: " + deniedPermissions.toString()
                    

                    override fun onShowPermissionRationale(permissions: Set<String>): Boolean 
                        AlertDialog.Builder(this@MainActivity).setMessage("To able to Send Photo, we need SMS and" + " Storage permission")
                                .setPositiveButton("OK")  _, _ ->
                                    smsAndStoragePermissionHandler.retryRequestDeniedPermission()
                                
                                .setNegativeButton("Cancel")  dialog, _ ->
                                    smsAndStoragePermissionHandler.cancel()
                                    dialog.dismiss()
                                
                                .show()
                        return true // don't want to show any rationale, just return false here
                    

                    override fun onShowSettingRationale(permissions: Set<String>): Boolean 
                        AlertDialog.Builder(this@MainActivity).setMessage("Go Settings -> Permission. " + "Make SMS on and Storage on")
                                .setPositiveButton("Settings")  _, _ ->
                                    smsAndStoragePermissionHandler.requestPermissionInSetting()
                                
                                .setNegativeButton("Cancel")  dialog, _ ->
                                    smsAndStoragePermissionHandler.cancel()
                                    dialog.cancel()
                                
                                .show()
                        return true
                    
                )

        button_request.setOnClickListener  handleRequestPermission() 
    

    private fun handleRequestPermission() 
        smsAndStoragePermissionHandler.requestPermission()
    

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
                                            grantResults: IntArray) 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        smsAndStoragePermissionHandler.onRequestPermissionsResult(requestCode, permissions,
                grantResults)
    

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        smsAndStoragePermissionHandler.onActivityResult(requestCode)
    

Code on Github

Demo

【讨论】:

我能找到的关于请求许可的最佳解决方案 @Phan,你有代码 sn-p 请求权限和处理不处理 这段代码似乎在 kotlin 中。有可用的 java 版本吗?【参考方案8】:

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

    创建一个方法,当你想请求运行时权限时会调用它,比如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>

    onCreate方法中初始化parentLayout变量

    parentLayout = findViewById(R.id.content);

    AndroidManifest.xml中定义所需的权限

&lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;

    queryContacts 方法,根据您的需要或运行时权限,您可以调用需要permission 的方法。就我而言,我只是使用加载器来获取联系人,如下所示:

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

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

【讨论】:

【参考方案9】:

应用程序中任何位置的运行时权限Here is Example

use dependency
maven  url 'https://jitpack.io' 
dependencies 
implementation 'com.github.irshadsparky:PermissionLib:master-SNAPSHOT'

并像这样调用代码:

PermissionHelper.requestCamera(new PermissionHelper.OnPermissionGrantedListener() 
@Override
public void onPermissionGranted() 


);

你可以找到更多Github

【讨论】:

【参考方案10】:

我使用RxPermission library library 请求许可。因为它是很长的代码,我们必须编写来请求许可。

RxPermissions rxPermissions = new RxPermissions(this); // where this is an Activity instance // Must be done during an initialization phase like onCreate
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> 
        if (granted)  // Always true pre-M
           // I can control the camera now
         else 
           // Oups permission denied
        
    );

在你的build.gradle中添加这些依赖

allprojects 
    repositories 
        ...
        maven  url 'https://jitpack.io' 
    


dependencies 
    implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
    implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'

【讨论】:

【参考方案11】:

通过避免编写大量代码来获得许可的简单方法,

https://github.com/sachinvarma/EasyPermission

如何添加:

repositories 
        maven  url "https://jitpack.io" 
    

implementation 'com.github.sachinvarma:EasyPermission:1.0.1'

如何申请许可:

 List<String> permission = new ArrayList<>();
 permission.add(EasyPermissionList.READ_EXTERNAL_STORAGE);
 permission.add(EasyPermissionList.ACCESS_FINE_LOCATION);

 new EasyPermissionInit(MainActivity.this, permission);

希望对某人有所帮助。

【讨论】:

【参考方案12】:

下面这段代码完美运行。我用一个例子来解释。

在我的例子中,我将权限检查分别放在一个 util 类中,并通过了我需要从适当的类中检查的特定权限。这使得在整个应用程序中重用权限检查 util 文件成为可能。

以下代码部分显示了函数调用。在这种情况下,我正在请求android.Manifest.permission.READ_EXTERNAL_STORAGE 权限。

//the below call is from a fragment
     @OnClick(R.id.button)//butterknife implementation
        public void attachPressed() 
            if (PermissionUtils.hasThisPermission(getContext(), android.Manifest.permission.READ_EXTERNAL_STORAGE)) 
                onAttachPressed();
             else 
                PermissionUtils.isPermissionRequestNeeded(getActivity(), this, android.Manifest.permission.READ_EXTERNAL_STORAGE, PermissionUtils.REQUEST_GROUP_STORAGE);
            
           

在上述情况下,如果允许则检查权限,如果允许,则调用onAttachPressed(); 函数,否则我们检查请求权限。

在我的例子中,下面是 util 类中的代码 PermissionUtils

public final class PermissionUtils 

    public static final int REQUEST_GROUP_STORAGE = 1508;

    private PermissionUtils() 
    

    public static boolean hasThisPermission(Context context, String permission) 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
         else 
            return true;
        
    

    public static boolean isPermissionRequestNeeded(Activity activity, Fragment fragment, String permission, int requestCode) 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasThisPermission(activity, permission)) 
            final String[] permissions = new String[]permission;
            if (fragment == null) 
                activity.requestPermissions(permissions, requestCode);
             else 
                fragment.requestPermissions(permissions, requestCode);
            
            return true;
        
        return false;
    

在请求之后,如果您可能想从onRequestPermissionsResult 调用函数,否则您需要再次按下按钮才能调用函数。

所以只需通过onRequestPermissionsResult 调用它

//the below call  is from a fragment
     @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
            if (requestCode == PermissionUtils.REQUEST_GROUP_STORAGE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                onAttachPressed();
             else 
                Log.e("value", "Permission Denied, You cannot use local drive .");
            
        

【讨论】:

【参考方案13】:

试试这个

这是 Marshmallow 版本中最简单的请求权限。

 if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED&&ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
    
        //TO do here if permission is granted by user
    
    else
    
        //ask for permission if user didnot given
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        
            requestPermissions(new String[]Manifest.permission.CAMERA,Manifest.permission.ACCESS_FINE_LOCATION, 0);
        
    

注意:-不要忘记在清单文件中添加相同的权限

 <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

第二种方法 检查权限的代码是否被授予?

ActivityCompat.requestPermissions(MainActivity.this, new String[]Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA, 1);

并重写方法

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) 
    switch (requestCode) 
        case 1: 
            if (grantResults.length > 0 && grantResults[1] == PackageManager.PERMISSION_GRANTED) 
         //                    grantResult[0] means it will check for the first postion permission which is READ_EXTERNAL_STORAGE
        //                    grantResult[1] means it will check for the Second postion permission which is CAMERA
                Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
            
            else
                Toast.makeText(this, "Permission not Granted", Toast.LENGTH_SHORT).show();
            return;
        
    

【讨论】:

所以你是说如果我以 Marshmallow 或更高版本为目标,那么我不需要在清单中声明权限?我知道无论我们的目标是什么安卓版本,我们都必须把它放进去。如果我错了,请纠正我@Sunil @Nilabja 在清单中声明权限对于所有 android 版本天气无论是否是棉花糖都是强制性的【参考方案14】:

Android-M 即 API 23 引入了Runtime Permissions 以减少 android 设备中的安全漏洞,用户现在可以在运行时直接管理应用程序权限。因此,如果用户拒绝您的应用程序的特定权限,您必须通过询问您在查询中提到的权限对话框。

所以在操作之前检查,即检查您是否有权访问资源link,如果您的应用程序没有该特定权限,您可以请求权限link 并处理权限请求响应,如下所示。

@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
    

最后,如果您打算使用新版本以避免强制关闭,最好通过behavior changes 进行操作:)

Permissions Best Practices.

您可以通过官方示例应用程序here。

【讨论】:

请记住我们必须有 noHistory=false 才能接收回调。如果您没有收到回拨,也请参考this。我浪费了几个小时来弄清楚。【参考方案15】:

你可以使用我的库——NoPermission(只是一个类)

compile 'ru.alexbykov:nopermission:1.1.1'

示例

PermissionHelper permissionHelper = new PermissionHelper(this); //don't use getActivity in fragment!

permissionHelper.check(Manifest.permission.READ_CONTACTS)
                .onSuccess(this::onSuccess)
                .onDenied(this::onDenied)
                .onNeverAskAgain(this::onNeverAskAgain)
                .run();

onRequestPermissionResult:

 @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
        permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
   

我觉得 api 比 Google 的 EasyPermissions 更方便。

【讨论】:

【参考方案16】:
  if (CommonMethod.isNetworkAvailable(MainActivity.this)) 
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
                        int permissionCheck = ContextCompat.checkSelfPermission(MainActivity.this,
                                android.Manifest.permission.CAMERA);
                        if (permissionCheck == PackageManager.PERMISSION_GRANTED) 
                            //showing dialog to select image
                            callFacebook();
                            Log.e("permission", "granted MarshMallow");
                         else 
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]android.Manifest.permission.READ_EXTERNAL_STORAGE,
                                            android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA, 1);
                        
                     else 
                        Log.e("permission", "Not Required Less than MarshMallow Version");
                        callFacebook();
                    
                 else 
                    CommonMethod.showAlert("Internet Connectivity Failure", MainActivity.this);
                

【讨论】:

【参考方案17】:

Android Marshmallow(API 23) 及以上版本默认禁用所有危险权限(根据官方文档official doc)。安装后,应用程序首次打开时,您必须在运行时授予权限。

我通过以下方式实现了这一点:

public class MarshMallowPermission 

    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE_BY_GALLERY = 0;
    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE_BY_CAMERA = 1;
    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE_BY_LOAD_PROFILE = 2;
    public static final int CAMERA_PERMISSION_REQUEST_CODE = 3;
    public static final int LOCATION_PERMISSION_REQUEST_CODE = 4;
    Activity activity;
    Context mContext;

    public MarshMallowPermission(Activity activity) 
        this.activity = activity;
        this.mContext = activity;
    

    public boolean checkPermissionForExternalStorage()
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED)
            return true;
         else 
            return false;
        
    

    public boolean checkPermissionForCamera()
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
        if (result == PackageManager.PERMISSION_GRANTED)
            return true;
         else 
            return false;
        
    

    public boolean checkLocationPermission()

        int result = ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION);
        if (result == PackageManager.PERMISSION_GRANTED)
            return true;
         else 
            return false;
        
    

    public void requestPermissionForExternalStorage(int requestCode)
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE))
            Toast.makeText(mContext.getApplicationContext(), "External Storage permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
         else 
            ActivityCompat.requestPermissions(activity,new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE,requestCode);
        
    

    public void requestPermissionForCamera()
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA))
            Toast.makeText(mContext.getApplicationContext(), "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
         else 
            ActivityCompat.requestPermissions(activity,new String[]Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE);
        
    
    public void requestPermissionForLocation()
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_COARSE_LOCATION))
            Toast.makeText(mContext.getApplicationContext(), "Location permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
         else 
            ActivityCompat.requestPermissions(activity, new String[]Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST_CODE);
        
    

IN 你的活动课:

 public class MainActivity extends AppCompatActivity

   private MarshMallowPermission marshMallowPermission;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        Log.d("NavHome", "Oncreate_nav");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        marshMallowPermission = new MarshMallowPermission(MainActivity.this);



        if (!marshMallowPermission.checkPermissionForExternalStorage()) 
            marshMallowPermission.requestPermissionForExternalStorage(MarshMallowPermission.EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE_BY_LOAD_PROFILE);
        
    

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) 
            case MarshMallowPermission.EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE_BY_LOAD_PROFILE:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) 

                    //permission granted successfully

                 else 

                 //permission denied

                
                break;
    
    


【讨论】:

【参考方案18】:

这可能是一种更清洁的方式。将所有权限添加到数组中,例如

private static final String[] INITIAL_PERMS=
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
    ;
    private static final int INITIAL_REQUEST=1337;

无论你的权限是什么,每个权限的创建方法

@RequiresApi(api = Build.VERSION_CODES.M)
private boolean canAccessFineLocation() 
    return(hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));


@RequiresApi(api = Build.VERSION_CODES.M)
private boolean canAccessCoarseLocation() 
    return(hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION));


@RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermission(String perm) 
    return(PackageManager.PERMISSION_GRANTED == checkSelfPermission(perm));

onCreate中调用这个方法

 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
      if(!canAccessCoarseLocation() || !canAccessFineLocation())
            requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
        
 

现在覆盖 onRequestPermissionsResult

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 

    if(requestCode == INITIAL_REQUEST)
        if (canAccessFineLocation() && canAccessCoarseLocation())  
            //call your method
        
        else 
            //show Toast or alert that this permissions is neccessary
        
    

【讨论】:

没有 requireApi,我的活动出错了我使用 TragetApi 注释 @Jawad,这很有效,但如果你添加一些被拒绝的权限回调会更好【参考方案19】:

为了处理运行时权限,谷歌提供了一个库项目。你可以从这里查看https://github.com/googlesamples/easypermissions

EasyPermissions 通过将以下依赖项添加到您的 build.gradle 文件来安装:

dependencies 
compile 'pub.devrel:easypermissions:0.3.0'

要开始使用 EasyPermissions,请让您的 Activity(或 Fragment)覆盖 onRequestPermissionsResult 方法:

public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks 

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    // Forward results to EasyPermissions
    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);


@Override
public void onPermissionsGranted(int requestCode, List<String> list) 
    // Some permissions have been granted
    // ...


@Override
public void onPermissionsDenied(int requestCode, List<String> list) 
    // Some permissions have been denied
    // ...


在这里,您将获得一个工作示例,该库是如何工作的 https://github.com/milon87/EasyPermission

【讨论】:

【参考方案20】:

有一个很好的库可以在后台服务需要权限时询问权限时使用。尽管库的一个限制是它不能仅用于确定当前是否授予应用程序权限。它总是询问用户应用是否还没有它们。

试试吧,因为它让生活更简单:Android Permissions

【讨论】:

【参考方案21】:

我使用这个结构来检查我的应用是否有权限,如果没有权限则请求。所以在我要检查的主要代码中写以下内容:

int MyVersion = Build.VERSION.SDK_INT;
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) 
                if (!checkIfAlreadyhavePermission()) 
                    requestForSpecificPermission();
                

模块 checkIfAlreadyhavePermission() 实现为:

private boolean checkIfAlreadyhavePermission() 
    int result = ContextCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS);
    if (result == PackageManager.PERMISSION_GRANTED) 
        return true;
     else 
        return false;
    

模块 requestForSpecificPermission() 实现为:

private void requestForSpecificPermission() 
        ActivityCompat.requestPermissions(this, new String[]Manifest.permission.GET_ACCOUNTS, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, 101);

并在 Activity 中覆盖:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
    switch (requestCode) 
        case 101:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                //granted
             else 
                //not granted
            
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    

更多详情请参考此链接:http://revisitingandroid.blogspot.in/2017/01/how-to-check-and-request-for-run-time.html

【讨论】:

友情建议:将checkIfAlreadyhavePermission中的if语句替换为return result == PackageManager.PERMISSION_GRANTED;【参考方案22】:

一次要获得多个权限,您可以使用它。这对我有用..我得到了另一个解决方案。如果你给你的 targetSdkVersion bellow 22 它对我有用。它的行为就像从 manifest.xml 获得许可一样。经过测试并为我工作。

final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;

    private void insertDummyContactWrapper() 
        List<String> permissionsNeeded = new ArrayList<String>();

        final List<String> permissionsList = new ArrayList<String>();
        if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
            permissionsNeeded.add("GPS");
        if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
            permissionsNeeded.add("Read Contacts");
        if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
            permissionsNeeded.add("Write Contacts");

        if (permissionsList.size() > 0) 
            if (permissionsNeeded.size() > 0) 
                // Need Rationale
                String message = "You need to grant access to " + permissionsNeeded.get(0);
                for (int i = 1; i < permissionsNeeded.size(); i++)
                    message = message + ", " + permissionsNeeded.get(i);
                showMessageOKCancel(message,
                        new DialogInterface.OnClickListener() 
                            @Override
                            public void onClick(DialogInterface dialog, int which) 
                                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                            
                        );
                return;
            
            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
            return;
        

        insertDummyContact();
    

    private boolean addPermission(List<String> permissionsList, String permission) 
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) 
            permissionsList.add(permission);
            // Check for Rationale Option
            if (!shouldShowRequestPermissionRationale(permission))
                return false;
        
        return true;
    






@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
        switch (requestCode) 
            case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
                
                Map<String, Integer> perms = new HashMap<String, Integer>();
                // Initial
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
                // Fill with results
                for (int i = 0; i < permissions.length; i++)
                    perms.put(permissions[i], grantResults[i]);
                // Check for ACCESS_FINE_LOCATION
                if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                        && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) 
                    // All Permissions Granted
                    insertDummyContact();
                 else 
                    // Permission Denied
                    Toast.makeText(MainActivity.this, "Some Permission is Denied", Toast.LENGTH_SHORT)
                            .show();
                
                
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        
    

了解更多详情。检查下面的链接

https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

【讨论】:

设置 targetSdkVersion bellow 22 会起作用,但是使用 android M 的用户拒绝设置的一项权限会发生什么? 是的..你是对的,此时应用程序会崩溃。所以,那个时候你需要再次检查用户是否拒绝许可..我不测试它,但我希望它会工作。形成用户的每一个动作,最好检查是否授予权限。【参考方案23】:

使用以下代码打开一个对话框:

 ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]Manifest.permission.READ_EXTERNAL_STORAGE,
                    1);

获取Activity结果如下:

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) 
    switch (requestCode) 
        case 1: 

          // 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.
                Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            
            return;
        

        // other 'case' lines to check for other
        // permissions this app might request
    

更多信息:https://developer.android.com/training/permissions/requesting.html

【讨论】:

我已经为它创建了库。通过简单的步骤即可轻松使用。 github.com/Kishanjvaghela/Ask-Permission 这部分也适用于如果用户单击取消:else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) ActivityCompat.requestPermissions 是否已弃用? (在努加特) 你从哪里得到这个变量?活动兼容性? @gumuruh,什么变量?【参考方案24】:

我将它用作基本的 Fragment 类。我只请求片段的权限,但你可以重构它并制作一个类似的 Activity 版本。

public class BaseFragment extends Fragment 

    private static final int PERMISSION_REQUEST_BLOCK_INTERNAL = 555;
    private static final String PERMISSION_SHARED_PREFERENCES = "permissions";

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
        if (requestCode == PERMISSION_REQUEST_BLOCK_INTERNAL) 
            boolean allPermissionsGranted = true;

            for (int iGranting : grantResults) 
                if (iGranting != PermissionChecker.PERMISSION_GRANTED) 
                    allPermissionsGranted = false;
                    break;
                
            

            if (allPermissionsGranted && permissionBlock != null) 
                permissionBlock.run();
            

            permissionBlock = null;
        
    

    public void runNowOrAskForPermissionsFirst(String permission, Runnable block) 
        if (hasPermission(permission)) 
            block.run();
         else if (!hasPermissionOrWillAsk(permission)) 
            permissionBlock = block;
            askForPermission(permission, PERMISSION_REQUEST_BLOCK_INTERNAL);
        
    

    public boolean hasPermissionOrWillAsk(String permission) 
        boolean hasPermission = hasPermission(permission);
        boolean hasAsked = hasPreviouslyAskedForPermission(permission);
        boolean shouldExplain = shouldShowRequestPermissionRationale(permission);

        return hasPermission || (hasAsked && !shouldExplain);
    

    private boolean hasPermission(String permission) 
        return (ContextCompat.checkSelfPermission(getContext(), permission) == PackageManager.PERMISSION_GRANTED);
    

    private boolean hasPreviouslyAskedForPermission(String permission) 
        SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_SHARED_PREFERENCES, Context.MODE_PRIVATE);
        return prefs.getBoolean(permission, false);
    

    private void askForPermission(String permission, int requestCode) 
        SharedPreferences.Editor editor = getContext().getSharedPreferences(PERMISSION_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();

        editor.putBoolean(permission, true);
        editor.apply();

        requestPermissions(new String[]  permission , requestCode);
    

您应该使用两种关键方法:

hasPermissionOrWillAsk - 使用它来查看是否已请求权限并被不想再次请求的用户拒绝。当用户给出他们不想要某个功能的最终答案时,这对于禁用 UI 很有用。

runNowOrAskForPermissionsFirst - 使用它来运行一些需要权限的代码。如果用户已经授予权限,代码将立即运行。否则,如果用户授予权限,代码将稍后运行。或者根本没有。这很好,因为您在一个地方指定了代码。

这是一个例子:

mFragment.runNowOrAskForPermissionsFirst(Manifest.permission.ACCESS_FINE_LOCATION, new Runnable() 
    @Override
    public void run() 
        ...do something if we have permission...
    
);

很高兴收到对此的反馈。并不是说这个特定示例稍微简化了一点,因为您还需要检查设备上是否启用了定位服务。 (这与权限不同。)此外,它一次只支持一个权限,但如果您需要一次支持多个权限,修改起来也很简单。

【讨论】:

【参考方案25】:

我使用了这个由谷歌开发者编写的包装器(推荐)。它超级好用。

https://github.com/googlesamples/easypermissions

处理检查并在需要时请求许可的功能

public void locationAndContactsTask() 
    String[] perms =  Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_CONTACTS ;
    if (EasyPermissions.hasPermissions(this, perms)) 
        // Have permissions, do the thing!
        Toast.makeText(this, "TODO: Location and Contacts things", Toast.LENGTH_LONG).show();
     else 
        // Ask for both permissions
        EasyPermissions.requestPermissions(this, getString(R.string.rationale_location_contacts),
                RC_LOCATION_CONTACTS_PERM, perms);
    

编码愉快:)

【讨论】:

@Farhan 我明白 :) 我只希望 Android 的 API 更简单,这样我们就不必使用包装器了。 我看不到“RC_CAMERA_AND_LOCATION”来自哪里,或者在哪里可以找到其他权限而不是那些,你知道它来自哪里吗?

以上是关于Android棉花糖请求权限?的主要内容,如果未能解决你的问题,请参考以下文章

安卓 6.0 棉花糖。无法写入 SD 卡

聊一聊 Android 6.0 的运行时权限

Android 6.0 系统棉花糖新的特性和功能

安卓6.0(棉花糖)新特性汇总

使用后退按钮关闭棉花糖上的权限请求对话框

图片来自 Android 6 中的图库(棉花糖)