ChatGPT解决这个技术问题 Extra ChatGPT

Android M 权限:未调用 onRequestPermissionsResult()

我正在更新我们的应用程序以使用新的 M 运行时权限系统。除了 onRequestPermissionsResult() 之外,一切正常。我需要检查按钮按下的权限,如果成功,请发送短信。当我授予执行此操作的权限时,对话框关闭,但在我再次按下按钮之前它不会触发发送文本。

我已经在 onRequestPermissionsResult() 方法中调试并设置了断点,但它从来没有进入过它。

首先调用此方法:

    private void askForPermission() {
    String[] permissions = new String[]{Manifest.permission.SEND_SMS};
    ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}

然后我的回调看起来像这样:

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

    if (requestCode == PERMISSIONS_CODE) {
        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            int grantResult = grantResults[i];

            if (permission.equals(Manifest.permission.SEND_SMS)) {
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    onPPSButtonPress();
                } else {
                    requestPermissions(new String[]{Manifest.permission.SEND_SMS}, PERMISSIONS_CODE);
                }
            }
        }
    }
}

有没有人遇到过类似的问题?感谢您对此的任何帮助。谢谢


S
SilentCloud

我遇到了同样的问题,我刚刚找到了解决方案。使用 Support 库时,您必须使用正确的方法调用。例如:

在 AppCompatActivity 中,应该使用 ActivityCompat.requestPermissions;

在 android.support.v4.app.Fragment 中,你应该简单地使用 requestPermissions(这是 android.support.v4.app.Fragment 的一个实例方法)

如果您在片段中调用 ActivityCompat.requestPermissions,则会在活动而不是片段上调用 onRequestPermissionsResult 回调。


它也发生在 noHistory 活动中:code.google.com/p/android-developer-preview/issues/…
“在 android.support.v4.app.Fragment 中,您应该简单地使用 requestPermissions ” - 谢谢!
@AnthonyBobenrieth 那么 noHistory 活动的解决方案是什么?我们根本无法向他们请求权限?
链接已损坏@AnthonyBobenrieth。没有历史有什么解决办法吗?
使用 Fragment.requestPermissions() 时,父 Activity 实际上正在接收 onRequestPermissionsResult()。 (这是支持库 23.3.0)
S
Someone Somewhere

你可以试试这个:

requestPermissions(permissions, PERMISSIONS_CODE);

如果您从片段中调用此代码,则它有自己的 requestPermissions 方法。我相信问题在于您正在调用静态方法。

如果您想要片段中的 onRequestPermissionsResult(),专业提示:FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)


谢谢您的帮助。我确实注意到,如果它在片段中,则有一个 requestPermissions 方法。我在一个片段中,我尝试只调用 requestPermissions,不幸的是它没有用。我也试过你提到的,它也没有奏效。
这在 Android M 中对我有用。但只是想知道它是否会在 Pre-M 设备中引起任何问题?
@goodgamerguy 确保您不在活动的 onRequestPermissionsResult 中使用请求代码。如果您的活动还使用 onRequestPermissionsResult 回调,您应该提供默认值: super.onRequestPermissionsResult(requestCode, permissions, grantResults);
F
Fabiano

我希望它工作正常

对于活动:

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

对于片段:

 requestPermissions(permissionsList,REQUEST_CODE);

SDK 15 及更低版本呢?
不需要 SDK 15 的权限,只有 Marshmallow 及以上版本需要..
S
Simon Featherstone

我也遇到了这个问题。如果您希望处理权限的 Activity 不在历史记录/最近记录中,那么您会很想更改您的 AndroidManifest.xml 条目。

如果您设置调用 requestPermissionsAppCompatActivity.requestPermissions 的活动

android:noHistory="true"
android:excludeFromRecents="true"

在您的 AndroidManifest.xml 中,将不会调用 onRequestPermissionsResult()。如果您的 Activity 是从 ActivityAppCompatActivity 派生的,则这是正确的。

这可以通过从“AndroidManifest.xml”中删除这两个标志并使用 finishAndRemoveTask() 完成您的活动来解决。


我宁愿不必删除 noHistory 属性,但这是对我有用的解决方案。谢谢!
我在棉花糖上遇到了问题,但在牛轧糖上没有,谢谢它对我有用
M
Misa Lazovic

如果您在 Activity 和 Fragment 中都有 onRequestPermissionsResult,请确保在 Activity 中调用 super.onRequestPermissionsResult。它在片段中不是必需的,但它在活动中。


另外请注意,如果您针对一个 API(例如 19),您仍将处于旧的权限模型系统下,因此,不会收到请求权限相关的函数调用
如果您扩展了另一个不调用 super 的活动,请查看我的回答
偶然发现了这个。 FragmentActivity.onRequestPermissionsResult(..) 是对片段 onRequestPermissionsResult(..) 的调用被转发到的地方。
@Bonatti 所以,如果我尝试在 android 4.4.2 中请求许可,我不会得到结果?因此我无法更改权限,只能看到它们?
@AlexanderFraggotsis 你会得到一个结果。唯一的区别是您不会被要求授予权限,而是系统会自动授予您权限。
B
Ben.Slama.Jihed

不推荐使用的答案请参考:https://developer.android.com/training/permissions/requesting

在片段内部,您需要调用:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

不是:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

与 android.support.v13.app.FragmentCompat 相关
从 API 27.1.0 开始不推荐使用 FragmentCompat。
我的答案已弃用,请参考:developer.android.com/training/permissions/requesting
M
Mike G

如果您在片段中使用 requestPermissions,它接受 2 个参数而不是 3 个。

您应该使用 requestPermissions(permissions, PERMISSIONS_CODE);


实际上,它确实提供了问题的答案。调用requestPermissions(fragment的实例方法)而不是ActivityCompat.requestPermissions,触发result方法。这是这里的主要问题。谢谢唐
T
TouchBoarder

如果由于某种原因您扩展了位于某些外部库中的自定义 Activity,该库不调用 super,您将需要在您的 Activity onRequestPermissionsResult 中手动调用 Fragment super.onRequestPermissionsResult。

YourActivity extends SomeActivityNotCallingSuperOnRequestPermissionsResult{
Fragment requestingFragment;//the fragment requesting the permission
...
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestingFragment!=null)
            requestingFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
...

我有扩展 AppCompatActivity 的正常活动,我还应该使用 super() 吗?
M
Marta Rodriguez

您在 FragmentCompat 中具有预 Marshmallow 设备的 checkPermissions 功能。我这样使用:

FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

这仅在 android.app.fragment 中询问权限时才有效,并且您必须导入 support-v13 库!
FragmentCompat.requestPermissions() 不适用于 android.support.v4.app.Fragment。任何人都知道如何处理这个问题。
a
almisoft

我发现您调用 android.support.v4.app.Fragment.requestPermissions 的位置很重要。

如果您在 onCreate() 中执行此操作,则永远不会调用 onRequestPermissionsResult()

解决方法:在onActivityCreated()中调用;

@Override
public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED) 
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);

}

我面临同样的问题,但我无法在我的代码中获得 onActivityCreated()。开发工具包 23。
我不在片段中,我正在尝试在活动的 onCreate 上进行
嗯,还是使用 onPause()
A
Ayohaych

这个问题实际上是由 NestedFragments 引起的。基本上,我们扩展了 HostedFragment 的大多数片段,而 HostedFragment 又扩展了 CompatFragment。拥有这些嵌套片段会导致问题,最终由该项目的另一位开发人员解决。

他正在做一些低级的事情,比如位切换来让它工作,所以我不太确定实际的最终解决方案


这帮助我解决了我的问题:我必须将 onRequestPermissionsResult 从父片段重定向到子(嵌套)片段。谢谢你的提示!
S
Shahab Rauf
 /* use the object of your fragment to call the 
 * onRequestPermissionsResult in fragment after
 * in activity and use different request Code for 
 * both Activity and Fragment */

   if (isFragment)
    mFragment.requestPermissions(permissions.toArray(new
    String[permissions.size()]),requestPermission);

   else
    ActivityCompat.requestPermissions(mActivity,permissions.toArray(new
    String[permissions.size()]),requestPermission);

P
PM 77-1

这将工作..

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

超级实现调用片段实现而不是hte框架
P
PounKumar Purushothaman

如果您从片段中调用此代码,则它有自己的 requestPermissions 方法。

所以基本概念是,如果你在一个活动中,然后调用

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

如果在片段中,只需调用

requestPermissions(permissionsList,
                            permissionscode);

需要 API 级别 23...在较早的版本上使用 FragmentCompat.requestPermissions()
S
Sagar

我遇到了类似的问题,只是我按下了一个按钮来拨打电话,这会触发 callIntent。我首先检查了权限,如果没有被授予,我会请求权限,并且 onRequestPermissionResult 我会调用检查权限并再次调用。

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case Constants.PERMISSIONS_REQUEST_CALL_PHONE: {
            if ( grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                checkPermissionsAndCall();
            }
        }
    }
}

public void checkPermissionsAndCall(){
    if (Build.VERSION.SDK_INT > 22) {
        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED){
            requestPermissions( new String[]{Manifest.permission.CALL_PHONE}, Constants.PERMISSIONS_REQUEST_CALL_PHONE);
        }
        else{
            callIntent();
        }
    }
}

h
havabon

基于 goodgamerguy's answer 的解决方案是:

myFragment.this.requestPermissions(....)

C
Chandler

在根据上述答案检查所有内容之前,请确保您的请求代码不为 0!!!

查看 FragmentActivity.java 中 onRequestPermissionsResult() 的代码:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    int index = (requestCode>>16)&0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode&0xffff, permissions, grantResults);
        }
    }
}

R
Robert
private void showContacts() {
    if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
    } else {
        doShowContacts();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        doShowContacts();
    }
}

A
Abhishek Dubey

我有一个了不起的解决方案来实现这一点,使 BaseActivity 像这样。

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));


}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case 1: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                CustomToast.getInstance().setCustomToast("Now you can share the Hack.");

            } else {
                Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

}

现在你可以像这样调用代码来请求许可

 ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

现在,每当这种情况发生在任何地方,无论是在您的片段中还是在任何活动中,都会调用基本活动。

谢谢


R
Remario

您可以使用 requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);。如果您使用的是 v4,请不要使用 FragmentCompat。


请详细说明原因。
V
Vasily Bodnarchuk

细节

科特林 1.2.70

签入 minSdkVersion 19

安卓工作室 3.1.4

算法

模块 - 相机,位置,....

检查是否有系统功能(如果手机中存在模块) 检查用户是否有权访问模块 发送权限请求(要求用户允许使用模块)

特征

使用活动和片段只有一个结果响应可以在一个请求中检查多个模块

解决方案

class PermissionType(val manifest_permission: String, val packageManager: String) {
    object Defined {
        val camera = PermissionType(Manifest.permission.CAMERA, PackageManager.FEATURE_CAMERA)
        val currentLocation = PermissionType(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.FEATURE_LOCATION_GPS)
    }
}

class  Permission {

    enum class PermissionResult {
        ACCESS_ALLOWED, ACCESS_DENIED, NO_SYSTEM_FEATURE;
    }

    interface ManagerDelegate {
        fun permissionManagerDelegate(result: Array<Pair<String, PermissionResult>>)
    }

    class Manager internal constructor(private val delegate: ManagerDelegate?) {

        private var context: Context? = null
        private var fragment: Fragment? = null
        private var activity: AppCompatActivity? = null
        private var permissionTypes: Array<PermissionType> = arrayOf()
        private val REQUEST_CODE = 999
        private val semaphore = Semaphore(1, true)
        private var result: Array<Pair<String, PermissionResult>> = arrayOf()


        constructor(permissionType: PermissionType, delegate: ManagerDelegate?): this(delegate) {
            permissionTypes = arrayOf(permissionType)
        }

        constructor(permissionTypes: Array<PermissionType>, delegate: ManagerDelegate?): this(delegate) {
            this.permissionTypes = permissionTypes
        }

        init {
            when (delegate) {
                is Fragment -> {
                    this.fragment = delegate
                    this.context = delegate.context
                }

                is AppCompatActivity -> {
                    this.activity = delegate
                    this.context = delegate
                }
            }
        }

        private fun hasSystemFeature(permissionType: PermissionType) : Boolean {
            return context?.packageManager?.hasSystemFeature(permissionType.packageManager) ?: false
        }

        private fun hasAccess(permissionType: PermissionType) : Boolean {
            return if (Build.VERSION.SDK_INT < 23) true else {
                context?.checkSelfPermission(permissionType.manifest_permission) == PackageManager.PERMISSION_GRANTED
            }
        }

        private fun sendRequest(permissionTypes: Array<String>) {

            if (fragment != null) {
                fragment?.requestPermissions(permissionTypes, REQUEST_CODE)
                return
            }

            if (activity != null){
                ActivityCompat.requestPermissions(activity!!, permissionTypes, REQUEST_CODE)
            }
        }

        fun check() {

            semaphore.acquire()
            AsyncTask.execute {
                var permissionsForSendingRequest: Array<String> = arrayOf()
                this.result = arrayOf()

                for (it in permissionTypes) {
                    if (!hasSystemFeature(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.NO_SYSTEM_FEATURE)
                        continue
                    }

                    if (hasAccess(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                    } else {
                        permissionsForSendingRequest += it.manifest_permission
                    }
                }

                if (permissionsForSendingRequest.isNotEmpty()) {
                    sendRequest(permissionsForSendingRequest)
                } else {
                    delegate?.permissionManagerDelegate(result)
                }
            }
        }

        fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            when (requestCode) {
                REQUEST_CODE -> {
                    if (grantResults.isEmpty()) {
                        return
                    }
                    for ((i,permission) in permissions.withIndex()) {
                        for (item in this.permissionTypes) {
                            if (permission == item.manifest_permission && i < grantResults.size) {
                                result += if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                                } else {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_DENIED)
                                }
                                break
                            }
                        }
                    }
                    delegate?.permissionManagerDelegate(result)
                }
            }
            semaphore.release()
        }
    }
}

Activity中的用法(片段中相同)

class BaseActivity : AppCompatActivity(), Permission.ManagerDelegate {

    private lateinit var permissionManager: Permission.Manager

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

        permissionManager = Permission.Manager(arrayOf(PermissionType.Defined.camera, PermissionType.Defined.currentLocation), this)
        permissionManager.check()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }


    override fun permissionManagerDelegate(result: Array<Pair<String, Permission.PermissionResult>>) {
        result.forEach {
            println("!!! ${it.first} ${it.second}")
//            when (it.second) {
//                Permission.PermissionResult.NO_SYSTEM_FEATURE -> {
//                }
//
//                Permission.PermissionResult.ACCESS_DENIED  -> {
//                }
//
//                Permission.PermissionResult.ACCESS_ALLOWED -> {
//                }
//            }
        }
    }
}

p
pavel

在这里,我想展示我的代码我是如何管理它的。

public class CheckPermission {

public Context context;

public static final int PERMISSION_REQUEST_CODE =  200;

public CheckPermission(Context context){
    this.context = context;
}

public boolean isPermissionGranted(){
    int read_contact = ContextCompat.checkSelfPermission(context.getApplicationContext() , READ_CONTACTS);
    int phone = ContextCompat.checkSelfPermission(context.getApplicationContext() , CALL_PHONE);

    return read_contact == PackageManager.PERMISSION_GRANTED && phone == PackageManager.PERMISSION_GRANTED;
   }
}

在这堂课中,我想检查是否授予了权限。不是那么我会从我的 MainActivity 中调用许可,比如

public void requestForPermission() {
       ActivityCompat.requestPermissions(MainActivity.this, new String[]    {READ_CONTACTS, CALL_PHONE}, PERMISSION_REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                    showMessageOKCancel("You need to allow access to both the permissions",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE},
                                                PERMISSION_REQUEST_CODE);
                                    }
                                }
                            });
                    return;
                }
            }
    }
}

现在在 onCreate 方法中你需要调用 requestForPermission() 函数。

就是这样。您也可以一次请求多个权限。


K
Kabir

更新:看到了其他人关于在 Activity 中调用 super.onRequestPermissionResult() 的回答,并修复了我提到的请求代码问题并调用了 片段的 onRequestPermissionResult。

忽略这些东西:

对我来说,尽管我调用了 fragment.requestPermission(...),但它还是调用了 Activity 的 onRequestPermissionResult,但它返回的结果是错误的 requestCode(111 变成了 65647,为什么???我永远不会知道)。

幸运的是,这是我们在该屏幕上请求的唯一权限,所以我只是忽略了请求代码(现在没有时间弄清楚为什么它不正确)


添加 65536 和 111 即可。这是因为位掩码。查看一些主题。
V
VolodymyrH

我还遇到了一个问题,即使你调用了正确的 requestPermissions,你仍然会遇到这个问题。问题是父活动可能会在不调用 super 的情况下覆盖此方法。添加超级,它将被修复。


A
Aury0n

对于 kotlin 用户,这里是我的扩展来检查和验证权限而不覆盖 onRequestPermissionResult

 * @param permissionToValidate (request and check currently permission)
 *
 * @return recursive boolean validation callback (no need OnRequestPermissionResult)
 *
 * */
internal fun Activity.validatePermission(
    permissionToValidate: String,
    recursiveCall: (() -> Boolean) = { false }
): Boolean {
    val permission = ContextCompat.checkSelfPermission(
        this,
        permissionToValidate
    )

    if (permission != PackageManager.PERMISSION_GRANTED) {
        if (recursiveCall()) {
            return false
        }

        ActivityCompat.requestPermissions(
            this,
            arrayOf(permissionToValidate),
            110
        )
        return this.validatePermission(permissionToValidate) { true }
    }

    return true

}