Bug 16364 - Android Manifest - <Application> Tag not merging properly during compilation
Summary: Android Manifest - <Application> Tag not merging properly during compilation
Status: RESOLVED INVALID
Alias: None
Product: Android
Classification: Xamarin
Component: General ()
Version: 4.8.x
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2013-11-20 12:46 UTC by Andrew Way
Modified: 2013-11-20 16:52 UTC (History)
1 user (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description Andrew Way 2013-11-20 12:46:44 UTC
I can recreate the bug quite easily by just moving my API key in the manifest, Here’s the manifest file from the project:

// This generates the bug. (Note location of <application tag>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.startrescue" android:versionCode="1" android:versionName="1">
       <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
       <application android:icon="@drawable/Icon" android:label="@string/app_name"></application>
       <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
       <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
       <uses-permission android:name="android.permission.READ_PHONE_STATE" />
       <uses-feature android:name="android.hardware.telephony" android:required="false" />
       <uses-permission android:name="android.permission.CALL_PHONE" />
    <!-- GOOGLE CLOUD MESSAGING NOTIFICATIONS -->
       <permission android:name="com.startrescue.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.startrescue.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
       <!-- Google Maps for Android v2 requires OpenGL ES v2 -->
       <uses-feature android:glEsVersion="0x00020000" android:required="true" />
       <!-- Allow the application to access Google web-based services. -->
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <!-- Google Maps for Android v2 will cache map tiles on external storage -->
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
       <!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
       <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
       <!-- Permission to receive remote notifications from Google Play Services -->
       <!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
       <uses-permission android:name="com.startrescue.permission.MAPS_RECEIVE" />
       <permission android:name="com.startrescue.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
    <application android:label="@string/app_name">
        <!-- Put your Google Maps V2 API Key here. -->
        <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBSpOUZFIBw8BzOkhV5rMSZQAJEd5HAv3g" />
    </application>
</manifest>
 
 
That results in the following manifest in /obj/android
 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.startrescue" android:versionCode="1" android:versionName="1">
  <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
  <application android:icon="@drawable/icon" android:label="@string/app_name" android:name="mono.android.app.Application" android:debuggable="true">
    <uses-library android:name="com.google.android.maps" />
    <activity android:label="About startrescue.co.uk" android:name="startrescue.About" />
    <activity android:label="Locating you ..." android:name="startrescue.BasicDemoActivity" />
    <activity android:icon="@drawable/icon" android:label="Start Rescue Breakdown Recovery" android:name="startrescue.Main" />
    <activity android:label="Non-Member Registration" android:name="startrescue.NonMemberRegister" />
    <receiver android:permission="com.google.android.c2dm.permission.SEND" android:name="startrescue.NotificationReciever">
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="com.startrescue" />
      </intent-filter>
      <intent-filter>
        <action android:name="com.google.android.gcm.intent.RETRY" />
        <category android:name="com.startrescue" />
      </intent-filter>
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="com.startrescue" />
      </intent-filter>
    </receiver>
    <service android:name="startrescue.MyIntentService" />
    <activity android:label="Register Mobile Device" android:name="startrescue.Register" />
    <activity android:label="Report Breakdown" android:name="startrescue.ReportBreakdown" />
    <activity android:label="Buy Breakdown Cover Now" android:name="startrescue.Sales" />
    <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="2147483647" android:authorities="com.startrescue.mono.MonoRuntimeProvider.__mono_init__" />
    <receiver android:name="mono.android.Seppuku">
      <intent-filter>
        <action android:name="mono.android.intent.action.SEPPUKU" />
        <category android:name="mono.android.intent.category.SEPPUKU.com.startrescue" />
      </intent-filter>
    </receiver>
    <activity android:icon="@drawable/icon" android:label="Start Rescue Breakdown Recovery" android:name="com.startrescue.TrialSplashScreen" android:theme="@style/Mono.Android.Theme.Splash" android:noHistory="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  <uses-feature android:name="android.hardware.telephony" android:required="false" />
  <uses-permission android:name="android.permission.CALL_PHONE" />
  <!-- GOOGLE CLOUD MESSAGING NOTIFICATIONS -->
  <permission android:name="com.startrescue.permission.C2D_MESSAGE" android:protectionLevel="signature" />
  <uses-permission android:name="com.startrescue.permission.C2D_MESSAGE" />
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <!-- Google Maps for Android v2 requires OpenGL ES v2 -->
  <uses-feature android:glEsVersion="0x00020000" android:required="true" />
  <!-- Allow the application to access Google web-based services. -->
  <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
  <!-- Google Maps for Android v2 will cache map tiles on external storage -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <!-- Permission to receive remote notifications from Google Play Services -->
  <!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
  <uses-permission android:name="com.startrescue.permission.MAPS_RECEIVE" />
  <permission android:name="com.startrescue.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
  <application android:label="@string/app_name">
    <!-- Put your Google Maps V2 API Key here. -->
    <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBSpOUZFIBw8BzOkhV5rMSZQAJEd5HAv3g" />
  </application>
</manifest>
 
If I try use the maps service it throws a java error that the API key cannot be found.
 
Changing my manifest like so:
 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="com.startrescue" android:versionCode="1" android:versionName="1">
       <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
    <application android:label="@string/app_name">
        <!-- Put your Google Maps V2 API Key here. -->
        <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBSpOUZFIBw8BzOkhV5rMSZQAJEd5HAv3g" />
    </application>
       <application android:icon="@drawable/Icon" android:label="@string/app_name"></application>
       <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
       <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
       <uses-permission android:name="android.permission.READ_PHONE_STATE" />
       <uses-feature android:name="android.hardware.telephony" android:required="false" />
       <uses-permission android:name="android.permission.CALL_PHONE" />
    <!-- GOOGLE CLOUD MESSAGING NOTIFICATIONS -->
       <permission android:name="com.startrescue.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.startrescue.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
       <!-- Google Maps for Android v2 requires OpenGL ES v2 -->
       <uses-feature android:glEsVersion="0x00020000" android:required="true" />
       <!-- Allow the application to access Google web-based services. -->
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <!-- Google Maps for Android v2 will cache map tiles on external storage -->
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
       <!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
       <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
       <!-- Permission to receive remote notifications from Google Play Services -->
       <!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
       <uses-permission android:name="com.startrescue.permission.MAPS_RECEIVE" />
       <permission android:name="com.startrescue.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
</manifest>
 
Resolves the error.
Comment 1 Jonathan Pryor 2013-11-20 16:52:36 UTC
Android does not support (and does not validate or otherwise error out on) AndroidManifest.xml containing more than one <application/> element:

https://www.google.com/search?q=android+manifest+multiple+applications
http://developer.android.com/guide/topics/manifest/manifest-intro.html#filec
> Only the <manifest> and <application> elements are required, they each must 
> be present and can occur only once.

Furthermore, the build process does not check for multiple <application/> elements, nor will it merge them; they're passed "through" to Android, aside from "merging" XML fragments generated from custom attributes:

http://docs.xamarin.com/guides/android/advanced_topics/working_with_androidmanifest.xml/

Nowhere do we state or imply that we'll take any mishmash of AndroidManifest.xml and turn it into something acceptable to Android, and having multiple <application/> elements qualifies as "mish mash" to my mind.

(Arguably we should validate the resulting AndroidManifest.xml to report errors like this, but we do not yet do any such validation or sanity checking.)