You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms适配Android 13时存储权限弹窗不显示问题求助

问题:Xamarin.Forms项目TargetSdkVersion升级到33后,Android 13设备不弹出权限请求弹窗

我用Visual Studio 2022开发Xamarin.Forms安卓项目,把android:targetSdkVersion从29升级到33后,在Android 13设备上运行时,权限请求弹窗完全不出现。以下是我的相关代码:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" package="com.myapp.app" android:versionCode="23" android:versionName="12.6.1">
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.telephony" android:required="false" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CALL_PHONE" android:required="false" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application android:allowBackup="false" android:requestLegacyExternalStorage="true" android:label="FieldDirect" android:largeHeap="true">
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/icon_transparent" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/brown" />
<meta-data android:name="com.google.android.geo.API_KEY" android:value="Adfsgrgsdvewsdvevwdvsdvsdv" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<service android:name="crc6494e14b9856016c30.PNFirebaseMessagingService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.myapp.app.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_path" />
</provider>
</application>
</manifest>

App.xaml.cs

if (context != null)
{
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
    {
        if ((Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.Camera) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadExternalStorage) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.WriteExternalStorage) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.AccessCoarseLocation) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.AccessFineLocation) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadPhoneState) != Android.Content.PM.Permission.Granted)
        && (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadPhoneNumbers) != Android.Content.PM.Permission.Granted))
        {

            ActivityCompat.RequestPermissions(context, new String[] { Manifest.Permission.Camera,
            Manifest.Permission.ReadExternalStorage,
            Manifest.Permission.WriteExternalStorage,
            Manifest.Permission.AccessCoarseLocation,
            Manifest.Permission.AccessFineLocation,
            Manifest.Permission.ReadPhoneNumbers,
            Manifest.Permission.ReadPhoneState,
            Manifest.Permission.CallPhone }, 100);

        }
    }
}

解决方案

1. 修复权限判断逻辑(核心问题)

你的权限判断用了&&逻辑,意思是只有当所有权限都未被授予时才会触发请求。只要有一个权限已经被授予,整个条件就不成立,弹窗自然不会出现。

把判断条件改成||,只要有任意一个权限未授予,就发起请求:

if ((Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.Camera) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadExternalStorage) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.WriteExternalStorage) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.AccessCoarseLocation) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.AccessFineLocation) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadPhoneState) != Android.Content.PM.Permission.Granted)
|| (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(context, Manifest.Permission.ReadPhoneNumbers) != Android.Content.PM.Permission.Granted))

2. 适配Android 13(API 33)权限变更

Android 13对部分权限做了拆分和替换,需要更新Manifest和请求逻辑:

  • 存储权限:READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE在API33中被弃用,需要根据你的使用场景添加对应的媒体权限,比如:

    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    

    如果需要兼容API32及以下设备,保留原来的READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,同时添加新的媒体权限。

  • 电话权限:Android 13中READ_PHONE_STATE不再包含读取电话号码的权限,你已经单独申请了READ_PHONE_NUMBERS,这部分没问题,但要确保请求时包含该权限。

3. 确保权限请求的上下文正确

在Xamarin.Forms中,建议在MainActivity的OnCreate或OnResume方法中发起权限请求,而不是App.xaml.cs——App.xaml.cs中的context可能不是有效的Activity上下文,会导致权限请求无法正常触发弹窗。

修改示例(在MainActivity中):

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    // 其他初始化代码...
    RequestPermissionsIfNeeded();
}

private void RequestPermissionsIfNeeded()
{
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
    {
        List<string> permissionsToRequest = new List<string>();

        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.Camera);
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessCoarseLocation) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.AccessCoarseLocation);
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.AccessFineLocation);
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.CallPhone);
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadPhoneState) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.ReadPhoneState);
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadPhoneNumbers) != Android.Content.PM.Permission.Granted)
            permissionsToRequest.Add(Manifest.Permission.ReadPhoneNumbers);
        
        // 适配Android 13存储权限
        if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Tiramisu)
        {
            if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadMediaImages) != Android.Content.PM.Permission.Granted)
                permissionsToRequest.Add(Manifest.Permission.ReadMediaImages);
        }
        else
        {
            if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != Android.Content.PM.Permission.Granted)
                permissionsToRequest.Add(Manifest.Permission.ReadExternalStorage);
            if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != Android.Content.PM.Permission.Granted)
                permissionsToRequest.Add(Manifest.Permission.WriteExternalStorage);
        }

        if (permissionsToRequest.Count > 0)
        {
            ActivityCompat.RequestPermissions(this, permissionsToRequest.ToArray(), 100);
        }
    }
}

4. 处理权限请求结果

记得重写OnRequestPermissionsResult方法来处理用户的权限选择:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 100)
    {
        // 处理权限授予结果,比如检查哪些权限被授予
        for (int i = 0; i < permissions.Length; i++)
        {
            if (grantResults[i] == Android.Content.PM.Permission.Granted)
            {
                // 权限已授予,执行对应逻辑
            }
            else
            {
                // 权限被拒绝,提示用户或做降级处理
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Manthiram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:47:01