Introducing app using Cordova 12 which requires target SDK Android 13 / API 33. My app depends on the following plugins (among many others)...
cordova-plugin-camera
cordova-plugin-media-capture
Both plugins insert permissions in AndroidManifest.xml. After upgrading to Cordova 12 and setting targetSdk to 33, the build fails trying to merge permissions...
> Task :app:processReleaseMainManifest FAILED
/Users/jmelvin/dev/sizzlescene/repos/mobile/platforms/android/app/src/main/AndroidManifest.xml:47:5-108 Error:
Element uses-permission#android.permission.WRITE_EXTERNAL_STORAGE at AndroidManifest.xml:47:5-108 duplicated with element declared at AndroidManifest.xml:26:5-81
Here are the properties inserted by the cordova-plugin-camera plugin...
11a12,14
> <provider android:authorities="${applicationId}.cordova.plugin.camera.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
> </provider>
22a26,41
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
> <queries>
> <intent>
> <action android:name="android.media.action.IMAGE_CAPTURE" />
> </intent>
> <intent>
> <action android:name="android.intent.action.GET_CONTENT" />
> </intent>
> <intent>
> <action android:name="android.intent.action.PICK" />
> </intent>
> <intent>
> <action android:name="com.android.camera.action.CROP" />
> <data android:mimeType="image/*" android:scheme="content" />
> </intent>
> </queries>
Here are the properties added by cordova-plugin-media-capture plugin...
22a23,28
> <uses-permission android:name="android.permission.RECORD_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.READ_EXTERNAL_STORAGE" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
And lastly, when both plugins are included in the build...
11a12,14
> <provider android:authorities="${applicationId}.cordova.plugin.camera.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
> </provider>
22a26,47
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
> <queries>
> <intent>
> <action android:name="android.media.action.IMAGE_CAPTURE" />
> </intent>
> <intent>
> <action android:name="android.intent.action.GET_CONTENT" />
> </intent>
> <intent>
> <action android:name="android.intent.action.PICK" />
> </intent>
> <intent>
> <action android:name="com.android.camera.action.CROP" />
> <data android:mimeType="image/*" android:scheme="content" />
> </intent>
> </queries>
> <uses-permission android:name="android.permission.RECORD_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.READ_EXTERNAL_STORAGE" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The permission request for WRITE_EXTERNAL_STORAGE are not exactly the same. The media-capture comes with an SDK qualifier...
camera: android:name="android.permission.WRITE_EXTERNAL_STORAGE"
capture: android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
Manually removing the capture plugin entry does allow the build to complete successfully. However, I'm not sure the result is functionally correct.
Question: is this a bug in the manifest merge code or are there workarounds to circumvent the collision and remain functionally the same?
It's not a bug, normally when authoring native projects, if two libraries attempt to declare the same permission with different configurations, it will result similar error.
What is a bug is the fact Cordova's
<edit-config>/<config-file>directives will result in conflicts and/or duplicate directives in the end-result, which has been a bug for several years.A hook however can be used to correct the project
after_prepareAdd
stripExtraWriteExternalStoragePerm.jsfile in yourhooks/directory with the script:In your
config.xmladd:If you already have a
<platform>block for android, then you should add it to your existing<platform>block.As the JS comment states, the conflict may occur with any combination of plugins, depending on how they declare
WRITE_EXTERNAL_STORAGE(e.g. with or without themaxSDKVersionattribute, or with a differentmaxSDKVersionattribute specified). If that's the case, you may need to add additionalmanifest = manifest.replace(...)lines for your project.I originally wrote the hook script for work and so the code is released with the copyright of Total Pave Inc. licensed under the Apache License: https://gist.github.com/breautek/bd157b8598f9a816f2ec0d45e3d932c8