Fixing Xamarin Google Play Services (Gingerbread) component compile errors

Project setup

  1. Create a new Android Application project.

  2. Set the Compile, Minimum, and Target Android versions. For this example, use Gingerbread API Level 10 (v2.3) for both Compile and Target. Set the Minimum to 10 or lower.

    Compile, Minimum, and Target Android versions for Xamarin.Android in Visual Studio. In Xamarin Studio, "Compile" is called "Target framework".

  3. Reload the project, as requested by the prompt.

    Reload Project dialog, Xamarin.Android for Visual Studio

  4. Add the Google Play Services (Gingerbread) component from the Xamarin component store.

    Google Play Services (Gingerbread) in the Xamarin component store

    The component will add four new references to the project:

    Google Play Services component, included references: GooglePlayServicesLib, Xamarin.Android.Support.v4, Xamarin.Android.Support.v7.AppCompat, Xamarin.Android.Support.v7.MediaRouter

Build attempt 1: AppCompat values-v14 errors

If you build the project at this step, for example via Build -> Build $(MSBuildProjectName), the build will fail.

Build Xamarin.Android application in Visual Studio

Errors

Build errors caused by missing Holo theme in AppCompat library, values-v14

Example error text:

Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Holo.ActionBar'.

With diagnostic build output enabled, the Output -> Build window shows that these errors happen during the aapt packaging step:

aapt.exe package -f -m -M C:\Users\Brendan\AppData\Local\Temp\rkpjcydb.cqo\AndroidManifest.xml -J C:\Users\Brendan\AppData\Local\Temp\rkpjcydb.cqo --custom-package androidapplication1.androidapplication1 -F C:\Users\Brendan\AppData\Local\Temp\rkpjcydb.cqo\resources.apk.bk -S obj\Release\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.1\lib\android\15\content\google-play-services/libproject/google-play-services_lib\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support/v7/appcompat\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support/v7/mediarouter\res -I C:\Users\Brendan\AppData\Local\Android\android-sdk\platforms\android-10\android.jar --auto-add-overlay

The errors arise from the appcompat/res/values-v14 folder because that folder contains style definitions that depend on the Holo theme. The Holo theme was first introduced in Ice Cream Sandwich (Android v4.0, API 14), and is not available on Gingerbread (Android v2.3, API 10).

Working around the errors in the AppCompat library

To stop the Holo theme problems, we can simply delete the appcompat/res/values-v14 folder located at:

$(MSBuildProjectDirectory)..\Components\googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support\v7\appcompat\res\values-v14

Build attempt 2: AppCompat values-v11 errors

On the second build attempt, we get some new errors:

Build errors caused by missing Holo theme in AppCompat library, values-v11

Example error text:

… googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support\v7\appcompat\res\values-v11\styles_base.xml(27): error : Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Holo.ProgressBar.Horizontal'.

These errors are essentially the same as the values-v14 errors, but this time they are caused by the values-v11 folder. So let's delete that folder, and try again.

Build attempt 3: MediaRouter layout errors

The third build attempt gets a little farther, but uncovers another set of errors:

Build errors caused by missing divider and padding attributes in the MediaRouter library

Example error text:

… googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support\v7\mediarouter\res\layout\mr_media_route_controller_dialog.xml(18): error : No resource identifier found for attribute 'showDividers' in package 'android'
… googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support\v7\mediarouter\res\layout-v11\mr_media_route_controller_dialog.xml(18): error : No resource found that matches the given name (at 'divider' with value '?android:attr/dividerHorizontal').
… googleplayservicesgingerbread-15.0.1\lib\android\19.0.1\content\support\v7\mediarouter\res\layout-v17\mr_media_route_list_item.xml(23): error : No resource identifier found for attribute 'paddingStart' in package 'android'

Again the build fails due to resource errors during the aapt packaging step, but this time the problems are in the MediaRouter library. The incompatible resources are:

We can again delete the unneeded layout-v11 and layout-v14 folders. That will leave just one error from the layout folder.

Error in layout/mr_media_route_controller_dialog.xml: "No resource found for attribute 'showDividers'"

Now we hit an interesting case. The mediarouter developers included the same divider and showDividers attributes in the default mr_media_route_controller_dialog.xml layout as in the v11 version, but these attributes aren't available on API 10. As expected, this causes an error during aapt bundling. What is the correct way to fix this? Is it safe simply to delete these attributes from the layout? We can try a quick experiment: what happens if you include these attribtues in a layout, compile the app on Android 3.0 (API 11), and run it on a Gingerbread (API 10) device? The result is that the app ignores the attributes. So yes, deleting the attributes is a sensible fix:

--- a/mediarouter/res/layout/mr_media_route_controller_dialog.xml
+++ b/mediarouter/res/layout/mr_media_route_controller_dialog.xml
@@ -17,9 +17,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:divider="?android:attr/dividerHorizontal"
-              android:showDividers="middle">
+              android:orientation="vertical">
     <!-- Optional volume slider section. -->
     <LinearLayout android:id="@+id/media_route_volume_layout"
                   android:layout_width="fill_parent"

Build attempt 4: AppCompat attr.xml error

Build error caused by missing preserveIconSpacing attribute, AppCompat library values/attr.xml

Error text:

AAPT : error : In MenuView, unable to find attribute android:preserveIconSpacing

Unfortunately, in this case aapt does not name the file where the problematic android:preserveIconSpacing attribute appears. But that's no problem. A quick grep, findstr, or gci -r | select-string easily finds the line:

appcompat\res\values\attrs.xml:309
<attr name="android:preserveIconSpacing"/>

Again, since this attribute only appears in Ice Cream Sandwich, we'll assume it would be ignored on Gingerbread, and delete the line:

--- a/appcompat/res/values/attrs.xml
+++ b/appcompat/res/values/attrs.xml
@@ -305,8 +305,6 @@
         <attr name="android:windowAnimationStyle"/>
         <!-- Default disabled icon alpha for each menu item that shows an icon. -->
         <attr name="android:itemIconDisabledAlpha"/>
-        <!-- Whether space should be reserved in layout when an icon is missing. -->
-        <attr name="android:preserveIconSpacing"/>
     </declare-styleable>
     <declare-styleable name="ActionMenuView">
         <!-- Size of padding on either end of a divider. -->

Build attempt 5: Java heap space error

COMPILETODALVIK : UNEXPECTED TOP-LEVEL error : 
   java.lang.OutOfMemoryError: Java heap space (TaskId:158)
    at com.android.dx.rop.code.RegisterSpecSet.<init>(RegisterSpecSet.java:49) (TaskId:158)
    at com.android.dx.rop.code.RegisterSpecSet.mutableCopy(RegisterSpecSet.java:383) (TaskId:158)

As discussed in the Troubleshooting section of the component's Getting Started page, the fix for this problem is to increase Java's heap size via the JavaMaximumHeapSize property. You can set this directly in the .csproj file, or by using the project property editor: Application -> Advanced Android Build Settings [section] -> Java Max Heap Size.

Xamarin.Android Java Max Heap Size property in Visual Studio

If 512M isn't enough, you can increase it to 1G or more.

Build attempt 6: success!

After all of these changes, the project now successfully builds!

Why are the resource fixes necessary?

One remaining question you might have is: If the Google Play Services (Gingerbread) component is targeted for Gingerbread, why are these steps necessary? The short answer is that all of the problems are with resources, and these are included directly from Google's original libraries. The Xamarin part of the component is just a thin layer of C# that allows access to the Java classes and methods. This C# binding treats the resources exactly like the original Java classes and methods. Specifically, it only looks at the contents of the .xml resource files at run time. In fact, compiling the appcompat and mediarouter libraries in a Java Eclipse Android project produces identical resource errors, and requires the same workarounds.

An alternative workaround for incompatible resource directories: --max-res-version 10

The Android Asset Packaging Tool aapt includes a --max-res-version option that helps with many of the errors. This technique is quite difficult to use with Xamarin.Android at the moment because there is no MSBuild variable for additional aapt options. Additionally, running aapt by hand from the command line isn't sufficient because the Xamarin.Android MSBuild tasks will re-run aapt regardless of whether it has already been run. There are some plans to make it easier to use --max-res-version in future versions of Xamarin.Android.

To get an idea for how --max-res-version will help, we can return to build attempt 1, copy the aapt command from the Output -> Build window, add the --max-res-version 10 option, and then run the command from the command line (for example using cmd.exe):

C:\Users\Brendan\AppData\Local\Android\android-sdk\build-tools\17.0.0\aapt.exe package -f -m -M C:\Users\Brendan\AppData\Local\Temp\4cppgmha.k1m\AndroidManifest.xml -J C:\Users\Brendan\AppData\Local\Temp\4cppgmha.k1m --custom-package androidapplication1.androidapplication1 -F C:\Users\Brendan\AppData\Local\Temp\4cppgmha.k1m\resources.apk.bk -S obj\Debug\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.2\lib\android\15\content\google-play-services/libproject/google-play-services_lib\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.2\lib\android\19.0.1\content\support/v7/appcompat\res -S C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.2\lib\android\19.0.1\content\support/v7/mediarouter\res -I C:\Users\Brendan\AppData\Local\Android\android-sdk\platforms\android-10\android.jar --auto-add-overlay --max-res-version 10

This produces some output to indicate that aapt is skipping the incompatible resource directories:

max res 10, skipping layout-v11
max res 10, skipping layout-v17
max res 10, skipping layout-v11
max res 10, skipping layout-v14
max res 10, skipping values-v11
max res 10, skipping values-v14

... but it also produces a couple errors:

C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.2\lib\android\19.0.1\content\support\v7\mediarouter\res\layout\mr_media_route_controller_dialog.xml:17: error: No resource identifier found for attribute 'showDividers' in package 'android'
C:\Users\Brendan\Desktop\AndroidApplication1\Components\googleplayservicesgingerbread-15.0.2\lib\android\19.0.1\content\support\v7\mediarouter\res\layout\mr_media_route_controller_dialog.xml:17: error: Error: No resource found that matches the given name (at 'divider' with value '?android:attr/dividerHorizontal').

These are the same showDividers and divider errors in the mediarouter library that we saw at the end of build attempt 3. To resolve these errors, we would again need to delete the problematic attributes from mr_media_route_controller_dialog.xml. After that, we would be back at build attempt 4. We would again see the In MenuView, unable to find attribute android:preserveIconSpacing error, and we would again need to fix the error by editing the attrs.xml file.

Aapt command line options documentation

When run from the command line with no arguments, aapt outputs some short documentation for the various command line options. For --max-res-version, the corresponding output is:

--max-res-version
    ignores versioned resource directories above the given value.

Found a mistake?

Submit a comment or correction

Updates

31 Mar 2014 Add discussion of --max-res-version
11 Mar 2014 Posted