| name | shiny-permissions-msbuild |
| description | Generate Android manifest permissions/features and iOS Info.plist entries for .NET MAUI apps using Shiny.Permissions.MSBuild |
| auto_invoke | true |
| triggers | ["maui permission","maui permissions","android permission","android manifest","ios plist","info plist","uses-permission","uses-feature","MauiPermission","AndroidManifestPermission","AndroidManifestFeature","InfoPlistPermission","NSCameraUsageDescription","NSLocationWhenInUseUsageDescription","NSBluetoothAlwaysUsageDescription","UIBackgroundModes","Shiny.Permissions.MSBuild","BluetoothLE permission","location permission","camera permission","push notification permission","biometric permission"] |
Shiny.Permissions.MSBuild Skill
You are an expert in Shiny.Permissions.MSBuild, an MSBuild task library that automatically generates Android manifest permissions/features and iOS Info.plist entries during the .NET MAUI build process.
When to Use This Skill
Invoke this skill when the user wants to:
- Add platform permissions to a .NET MAUI project
- Configure Android manifest permissions or hardware features
- Configure iOS Info.plist usage description strings or background modes
- Use high-level
MauiPermission items instead of manual platform XML
- Understand what Android/iOS entries a particular permission generates
- Debug permission-related build issues
Library Overview
Package: Shiny.Permissions.MSBuild
How it works: Declare MSBuild items in .csproj → the build task generates platform XML into $(IntermediateOutputPath) before the Build target runs.
There are four item types:
MauiPermission — high-level permission sets that generate both Android and iOS entries
AndroidManifestPermission — individual Android <uses-permission> entries
AndroidManifestFeature — individual Android <uses-feature> entries
InfoPlistPermission — individual iOS Info.plist key/value entries
MauiPermission — High-Level Permission Sets
This is the primary API. One item generates all required platform entries.
Usage
<ItemGroup>
<MauiPermission Include="Camera" />
<MauiPermission Include="Location" />
<MauiPermission Include="BluetoothLE" />
</ItemGroup>
Known Permissions and Their Mappings
BluetoothLE
- Android permissions:
BLUETOOTH, BLUETOOTH_ADMIN, BLUETOOTH_CONNECT, BLUETOOTH_SCAN, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION
- Android features: (none)
- iOS:
UIBackgroundModes → bluetooth-central, NSBluetoothAlwaysUsageDescription
Location
- Android permissions:
ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION
- Android features:
LOCATION.GPS (required=false), LOCATION.NETWORK (required=false)
- iOS:
UIBackgroundModes → location, NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription
LocationBackground
- Android permissions:
FOREGROUND_SERVICE_LOCATION, FOREGROUND_SERVICE, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION
- Android features:
LOCATION.GPS (required=false), LOCATION.NETWORK (required=false)
- iOS:
UIBackgroundModes → location, NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription
Geofencing
- Android permissions:
ACCESS_BACKGROUND_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION
- Android features:
LOCATION.GPS (required=false), LOCATION.NETWORK (required=false)
- iOS:
UIBackgroundModes → location, NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription
Push
- Android permissions:
POST_NOTIFICATIONS
- iOS:
UIBackgroundModes → remote-notification
Microphone
- Android permissions:
RECORD_AUDIO
- iOS:
NSMicrophoneUsageDescription
Contacts
- Android permissions:
READ_CONTACTS
- iOS:
NSContactsUsageDescription
Calendar
- Android permissions:
READ_CALENDAR
- iOS:
NSCalendarsUsageDescription
Camera
- Android permissions:
CAMERA
- iOS:
NSCameraUsageDescription
Photos
- Android permissions:
READ_EXTERNAL_STORAGE
- iOS:
NSPhotoLibraryUsageDescription
Maps
- Android permissions:
ACCESS_FINE_LOCATION
- iOS:
NSLocationWhenInUseUsageDescription
Biometric
- Android permissions:
USE_BIOMETRIC
- iOS:
NSFaceIDUsageDescription
Deduplication and Merging Rules
When multiple MauiPermission items are declared:
- Android permissions are deduplicated by resolved name (case-insensitive)
- Android features are deduplicated by resolved name (case-insensitive)
- iOS array entries (e.g.
UIBackgroundModes) are merged — values from all permission sets are combined into a single array, preserving insertion order and removing duplicates
- iOS non-array entries use last-seen-wins — this allows custom entries to override auto-generated defaults
Default Usage Description Strings
All iOS usage description strings default to: "Say something useful here that your users will understand". Users should override these with real descriptions for App Store submission.
AndroidManifestPermission — Fine-Grained Android Permissions
<ItemGroup>
<AndroidManifestPermission Include="CAMERA" />
<AndroidManifestPermission Include="ACCESS_FINE_LOCATION" />
<AndroidManifestPermission Include="READ_EXTERNAL_STORAGE" MaxSdkVersion="32" />
<AndroidManifestPermission Include="WRITE_EXTERNAL_STORAGE" MinSdkVersion="19" MaxSdkVersion="28" />
</ItemGroup>
Metadata: MinSdkVersion (optional), MaxSdkVersion (optional)
Name resolution: Short names are prefixed with android.permission.. Fully qualified names (3+ dot segments) are used as-is.
AndroidManifestFeature — Fine-Grained Android Features
<ItemGroup>
<AndroidManifestFeature Include="CAMERA" />
<AndroidManifestFeature Include="LOCATION.GPS" Required="true" />
<AndroidManifestFeature Include="BLUETOOTH" Required="false" />
</ItemGroup>
Metadata: Required (optional, true or false)
Name resolution: Short names are prefixed with android.hardware.. Fully qualified names (3+ dot segments) are used as-is.
InfoPlistPermission — Fine-Grained iOS Info.plist Entries
<ItemGroup>
<InfoPlistPermission Include="NSCameraUsageDescription" Type="string" Value="We need camera access" />
<InfoPlistPermission Include="UIRequiresPersistentWiFi" Type="boolean" Value="true" />
<InfoPlistPermission Include="LSApplicationQueriesSchemes" Type="stringarray" Value="fb;instagram;twitter" />
<InfoPlistPermission Include="UIDeviceFamily" Type="integerarray" Value="1;2" />
</ItemGroup>
Metadata: Type (optional, default string — supports string, boolean/bool, stringarray, integerarray), Value (optional)
For arrays, separate items with ;. Use stringarray for <string> elements and integerarray for <integer> elements. The legacy type name array is accepted as an alias for stringarray.
Generated Output Files
All files are written to $(IntermediateOutputPath):
| Item Group | Output File |
|---|
MauiPermission | AndroidManifest.xml + Info.plist |
AndroidManifestPermission / AndroidManifestFeature | AndroidManifest.xml |
InfoPlistPermission | Info.plist |
Architecture
src/Shiny.Permissions.MSBuild/
├── build/
│ ├── Shiny.Permissions.MSBuild.props # Defines item groups
│ └── Shiny.Permissions.MSBuild.targets # Registers tasks and targets
├── Generators/
│ ├── AndroidManifestGenerator.cs # Android XML generation
│ ├── InfoPlistGenerator.cs # iOS plist XML generation
│ └── MauiPermissionsGenerator.cs # Permission set resolution + orchestration
├── Models/
│ ├── AndroidPermission.cs # Name, MinSdkVersion, MaxSdkVersion
│ ├── AndroidFeature.cs # Name, Required
│ └── InfoPlistEntry.cs # Key, Type, Value
└── Tasks/
├── GenerateAndroidManifestTask.cs # MSBuild task for AndroidManifestPermission/Feature
├── GenerateInfoPlistTask.cs # MSBuild task for InfoPlistPermission
└── GenerateMauiPermissionsTask.cs # MSBuild task for MauiPermission
Best Practices
- Prefer
MauiPermission over individual items — it handles all platform details and deduplication automatically
- Override default usage descriptions before App Store / Play Store submission
- Combine permission sets freely — deduplication ensures no duplicate manifest entries
- Use fine-grained items only when you need SDK version constraints or custom permission names not covered by the known sets
- Check
obj/ output to verify generated XML during development
Example: Full MAUI Project Configuration
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0-android;net9.0-ios</TargetFrameworks>
<OutputType>Exe</OutputType>
<UseMaui>true</UseMaui>
</PropertyGroup>
<ItemGroup>
<MauiPermission Include="Camera" />
<MauiPermission Include="BluetoothLE" />
<MauiPermission Include="Location" />
<MauiPermission Include="Push" />
<MauiPermission Include="Biometric" />
<MauiPermission Include="Contacts" />
</ItemGroup>
</Project>
This single declaration generates:
- Android: 12
<uses-permission> entries (deduplicated) + 2 <uses-feature> entries
- iOS:
UIBackgroundModes array with bluetooth-central, location, remote-notification + 6 usage description strings