Order of Cordova Plugins Matters
I was convinced that it doesn't matter in what order plugins are added to a Cordova project. However, I recently encountered an issue with unexpected entries in iOS Info.plist
file, which turned out to be caused by incorrect order of plugins in config.xml
file.
I started out with cordova-plugin-geolocation plugin in my Cordova application:
cordova plugin add cordova-plugin-geolocation --save \
--variable GEOLOCATION_USAGE_DESCRIPTION="My very own reason"
Using the plugin, the application can access the user location. On iOS I need to specify the reason, why the application requires access to location, which will be displayed to the user in the dialog when asking for permission. The plugin reads the corresponding text from a variable, which can be later changed in the config.xml
file:
<plugin name="cordova-plugin-geolocation" spec="~2.4.3">
<variable name="GEOLOCATION_USAGE_DESCRIPTION" value="My very own reason" />
</plugin>
With this configuration, the final Info.plist
file (located in platforms/ios/<projectname>/<projectname>-Info.plist
, where <projectname>
is the name of the project) had the expected value for NSLocationWhenInUseUsageDescription
from my variable:
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>My very own reason</string>
</dict>
</plist>
The problems started when I added cordova.plugins.diagnostic plugin to the same application:
cordova plugin add cordova.plugins.diagnostic --save
Suddenly, the value for NSLocationWhenInUseUsageDescription
in Info.plist
file changed:
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>
This app requires access to your location when the screen is on
and the app is displayed.
</string>
</dict>
</plist>
I had to do a text search through my project folder to find the source of the changed text. I found it in the plugin.xml
file:
<config-file target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription">
<string>
This app requires access to your location when the screen is on
and the app is displayed.
</string>
</config-file>
Obviously, the plugin contains a hardcoded value for NSLocationWhenInUseUsageDescription
, hence now the value is defined twice in my project. Which value gets used? The answer can be found in ios.json
file, which is placed in platforms/ios
folder:
{
"config_munge": {
"files": {
"*-Info.plist": {
"parents": {
"NSLocationWhenInUseUsageDescription": [
{
"xml": "<string>My very own reason</string>",
"count": 1
},
{
"xml": "<string>This app requires access to your location when the screen is on and the app is displayed.</string>",
"count": 1
}
]
}
}
}
}
}
This file serves as the basis for the final Info.plist
file. The list of values for the same key will be applied one after the other, with the next one always overriding the previous one. As a result, the last value wins.
The order in which the values are listed in ios.json
matches the order of plugins in config.xml
. To fix my issue I need to make sure, that cordova-plugin-geolocation is the last one setting the key. I could move it to the end by removing and re-adding it to the project:
cordova plugin remove cordova-plugin-geolocation --save
cordova plugin add cordova-plugin-geolocation --save \
--variable GEOLOCATION_USAGE_DESCRIPTION="My very own reason"
Alternatively, I could just change the order in config.xml
manually, but then I need to delete the platforms
and plugins
folders and reinstall everything based on the contents of config.xml
:
cordova prepare
Now, the order of values for NSLocationWhenInUseUsageDescription
in ios.json
is correct:
{
"config_munge": {
"files": {
"*-Info.plist": {
"parents": {
"NSLocationWhenInUseUsageDescription": [
{
"xml": "<string>This app requires access to your location when the screen is on and the app is displayed.</string>",
"count": 1
},
{
"xml": "<string>My very own reason</string>",
"count": 1
}
]
}
}
}
}
}
And so is the value in the final Info.plist
file:
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>My very own reason</string>
</dict>
</plist>
Another word of caution: make sure that on the build server you start with a clean working folder and reinstall all the plugins for every build, otherwise the changes to config.xml
won't affect the Info.plist
file because it is generated when the plugins are installed, not when the project is built.