我正在更新我们的应用程序以使用新的 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);
}
}
}
}
}
有没有人遇到过类似的问题?感谢您对此的任何帮助。谢谢
我遇到了同样的问题,我刚刚找到了解决方案。使用 Support 库时,您必须使用正确的方法调用。例如:
在 AppCompatActivity 中,应该使用 ActivityCompat.requestPermissions;
在 android.support.v4.app.Fragment 中,你应该简单地使用 requestPermissions(这是 android.support.v4.app.Fragment 的一个实例方法)
如果您在片段中调用 ActivityCompat.requestPermissions,则会在活动而不是片段上调用 onRequestPermissionsResult 回调。
你可以试试这个:
requestPermissions(permissions, PERMISSIONS_CODE);
如果您从片段中调用此代码,则它有自己的 requestPermissions 方法。我相信问题在于您正在调用静态方法。
如果您想要片段中的 onRequestPermissionsResult()
,专业提示:FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)
我希望它工作正常
对于活动:
ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);
对于片段:
requestPermissions(permissionsList,REQUEST_CODE);
我也遇到了这个问题。如果您希望处理权限的 Activity 不在历史记录/最近记录中,那么您会很想更改您的 AndroidManifest.xml
条目。
如果您设置调用 requestPermissions
或 AppCompatActivity.requestPermissions
的活动
android:noHistory="true"
android:excludeFromRecents="true"
在您的 AndroidManifest.xml
中,将不会调用 onRequestPermissionsResult()
。如果您的 Activity 是从 Activity
或 AppCompatActivity
派生的,则这是正确的。
这可以通过从“AndroidManifest.xml”中删除这两个标志并使用 finishAndRemoveTask()
完成您的活动来解决。
如果您在 Activity 和 Fragment 中都有 onRequestPermissionsResult
,请确保在 Activity 中调用 super.onRequestPermissionsResult
。它在片段中不是必需的,但它在活动中。
FragmentActivity.onRequestPermissionsResult(..)
是对片段 onRequestPermissionsResult(..)
的调用被转发到的地方。
不推荐使用的答案请参考:https://developer.android.com/training/permissions/requesting
在片段内部,您需要调用:
FragmentCompat.requestPermissions(permissionsList, RequestCode)
不是:
ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);
如果您在片段中使用 requestPermissions,它接受 2 个参数而不是 3 个。
您应该使用 requestPermissions(permissions, PERMISSIONS_CODE);
如果由于某种原因您扩展了位于某些外部库中的自定义 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()
吗?
您在 FragmentCompat 中具有预 Marshmallow 设备的 checkPermissions 功能。我这样使用:
FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
我发现您调用 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。
onPause()
?
这个问题实际上是由 NestedFragments 引起的。基本上,我们扩展了 HostedFragment 的大多数片段,而 HostedFragment 又扩展了 CompatFragment。拥有这些嵌套片段会导致问题,最终由该项目的另一位开发人员解决。
他正在做一些低级的事情,比如位切换来让它工作,所以我不太确定实际的最终解决方案
/* 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);
这将工作..
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
如果您从片段中调用此代码,则它有自己的 requestPermissions 方法。
所以基本概念是,如果你在一个活动中,然后调用
ActivityCompat.requestPermissions(this,
permissionsList,
permissionscode);
如果在片段中,只需调用
requestPermissions(permissionsList,
permissionscode);
FragmentCompat.requestPermissions()
。
我遇到了类似的问题,只是我按下了一个按钮来拨打电话,这会触发 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();
}
}
}
在根据上述答案检查所有内容之前,请确保您的请求代码不为 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);
}
}
}
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();
}
}
我有一个了不起的解决方案来实现这一点,使 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);
现在,每当这种情况发生在任何地方,无论是在您的片段中还是在任何活动中,都会调用基本活动。
谢谢
您可以使用 requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);
。如果您使用的是 v4,请不要使用 FragmentCompat。
细节
科特林 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 -> {
// }
// }
}
}
}
在这里,我想展示我的代码我是如何管理它的。
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() 函数。
就是这样。您也可以一次请求多个权限。
更新:看到了其他人关于在 Activity 中调用 super.onRequestPermissionResult()
的回答,并修复了我提到的请求代码问题并调用了 片段的 onRequestPermissionResult。
忽略这些东西:
对我来说,尽管我调用了 fragment.requestPermission(...)
,但它还是调用了 Activity 的 onRequestPermissionResult
,但它返回的结果是错误的 requestCode(111 变成了 65647,为什么???我永远不会知道)。
幸运的是,这是我们在该屏幕上请求的唯一权限,所以我只是忽略了请求代码(现在没有时间弄清楚为什么它不正确)
我还遇到了一个问题,即使你调用了正确的 requestPermissions,你仍然会遇到这个问题。问题是父活动可能会在不调用 super 的情况下覆盖此方法。添加超级,它将被修复。
对于 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
}
Fragment.requestPermissions()
时,父 Activity 实际上正在接收onRequestPermissionsResult()
。 (这是支持库 23.3.0)