An MSBuild task library that automatically generates Android manifest permissions/features and iOS Info.plist entries during the build process. Declare permissions in your project file and the correct platform-specific XML is generated for you.
Install the NuGet package:
dotnet add package Shiny.Permissions.MSBuild
Once installed, the .props and .targets files are imported automatically. Generation runs before the Build target and only when items are defined.
The simplest way to declare permissions for a .NET MAUI app. Add MauiPermission items and the task generates both Android manifest entries and iOS Info.plist entries automatically:
<ItemGroup>
<MauiPermission Include="Camera" />
<MauiPermission Include="BluetoothLE" />
<MauiPermission Include="Location" />
<MauiPermission Include="Push" />
<MauiPermission Include="Biometric" />
<MauiPermission Include="Contacts" />
</ItemGroup>| Permission | Android Permissions | iOS Entries |
|---|---|---|
BluetoothLE |
BLUETOOTH, BLUETOOTH_ADMIN, BLUETOOTH_CONNECT, BLUETOOTH_SCAN, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION |
UIBackgroundModes (bluetooth-central), NSBluetoothAlwaysUsageDescription |
Location |
ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION + features: LOCATION.GPS, LOCATION.NETWORK |
UIBackgroundModes (location), NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription |
LocationBackground |
FOREGROUND_SERVICE_LOCATION, FOREGROUND_SERVICE, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION + features: LOCATION.GPS, LOCATION.NETWORK |
UIBackgroundModes (location), NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription |
Geofencing |
ACCESS_BACKGROUND_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION + features: LOCATION.GPS, LOCATION.NETWORK |
UIBackgroundModes (location), NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription |
Push |
POST_NOTIFICATIONS |
UIBackgroundModes (remote-notification) |
Microphone |
RECORD_AUDIO |
NSMicrophoneUsageDescription |
Contacts |
READ_CONTACTS |
NSContactsUsageDescription |
Calendar |
READ_CALENDAR |
NSCalendarsUsageDescription |
Camera |
CAMERA |
NSCameraUsageDescription |
Photos |
READ_EXTERNAL_STORAGE |
NSPhotoLibraryUsageDescription |
Maps |
ACCESS_FINE_LOCATION |
NSLocationWhenInUseUsageDescription |
Biometric |
USE_BIOMETRIC |
NSFaceIDUsageDescription |
When multiple permission sets share entries, the generator automatically:
- Deduplicates Android permissions and features (e.g.
BluetoothLE+Locationboth declareACCESS_FINE_LOCATION— it appears only once) - Merges iOS array entries (e.g.
BluetoothLE+Location+Pushmerge into a singleUIBackgroundModesarray withbluetooth-central,location, andremote-notification)
MauiPermission items generate two files in $(IntermediateOutputPath):
| File | Description |
|---|---|
AndroidManifest.xml |
Android permissions and features |
Info.plist |
iOS Info.plist entries |
For fine-grained control, add AndroidManifestPermission items directly:
<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>This generates $(IntermediateOutputPath)AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:minSdkVersion="19" android:maxSdkVersion="28" />
</manifest>| Metadata | Required | Description |
|---|---|---|
MinSdkVersion |
No | Minimum Android SDK version for this permission |
MaxSdkVersion |
No | Maximum Android SDK version for this permission |
Short names like CAMERA are automatically prefixed with android.permission.. Fully qualified names with 3+ dot-separated segments (e.g. com.example.myapp.CUSTOM_PERMISSION) are used as-is.
Add AndroidManifestFeature items to your project file:
<ItemGroup>
<AndroidManifestFeature Include="CAMERA" />
<AndroidManifestFeature Include="LOCATION.GPS" Required="true" />
<AndroidManifestFeature Include="BLUETOOTH" Required="false" />
</ItemGroup>This generates $(IntermediateOutputPath)AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.CAMERA" />
<uses-feature android:name="android.hardware.LOCATION.GPS" android:required="true" />
<uses-feature android:name="android.hardware.BLUETOOTH" android:required="false" />
</manifest>| Metadata | Required | Description |
|---|---|---|
Required |
No | Whether the feature is required (true or false) |
Short names like CAMERA are automatically prefixed with android.hardware.. Fully qualified names with 3+ dot-separated segments are used as-is.
Add InfoPlistPermission items to your project file:
<ItemGroup>
<!-- String values -->
<InfoPlistPermission Include="NSCameraUsageDescription" Type="string" Value="We need camera access for video calls" />
<InfoPlistPermission Include="NSLocationWhenInUseUsageDescription" Type="string" Value="Your location helps us find nearby places" />
<!-- Boolean values -->
<InfoPlistPermission Include="UIRequiresPersistentWiFi" Type="boolean" Value="true" />
<!-- String array values (semicolon-delimited) -->
<InfoPlistPermission Include="LSApplicationQueriesSchemes" Type="stringarray" Value="fb;instagram;twitter" />
<!-- Integer array values (semicolon-delimited) -->
<InfoPlistPermission Include="UIDeviceFamily" Type="integerarray" Value="1;2" />
</ItemGroup>This generates $(IntermediateOutputPath)Info.plist:
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>We need camera access for video calls</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location helps us find nearby places</string>
<key>UIRequiresPersistentWiFi</key>
<true/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fb</string>
<string>instagram</string>
<string>twitter</string>
</array>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
</dict>
</plist>| Metadata | Required | Default | Description |
|---|---|---|---|
Type |
No | string |
Value type: string, boolean / bool, stringarray, or integerarray |
Value |
No | empty | The entry value. For arrays, separate items with ; |
See the samples/SampleMauiApp project for a .NET MAUI app demonstrating MauiPermission with Camera, BluetoothLE, Location, Push, Biometric, and Contacts.