Tuesday, January 2, 2018

AppCompat runtime error: "android.content.res.Resources$NotFoundException: File res/drawable/abc_vector_test.xml from drawable resource ID #0x7f020052"

Developing an Android app with the latest Support Library versions you may encounter this crash at startup on devices running Android < 5.0 (API 21):
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.googleplayservicesdemo/com.example.googleplayservicesdemo.MainActivity}: android.content.res.Resources$NotFoundException: File res/drawable/abc_vector_test.xml from drawable resource ID #0x7f020052
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
       at android.app.ActivityThread.access$600(ActivityThread.java:141)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:137)
       at android.app.ActivityThread.main(ActivityThread.java:5041)
       at java.lang.reflect.Method.invokeNative(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:511)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
       at dalvik.system.NativeStart.main(Native Method)
Caused by: android.content.res.Resources$NotFoundException: File res/drawable/abc_vector_test.xml from drawable resource ID #0x7f020052
       at android.content.res.Resources.loadDrawable(Resources.java:1953)
       at android.content.res.Resources.getDrawable(Resources.java:660)
       at android.support.v7.widget.VectorEnabledTintResources.superGetDrawable(VectorEnabledTintResources.java:74)
       at android.support.v7.widget.AppCompatDrawableManager.onDrawableLoadedFromResources(AppCompatDrawableManager.java:435)
       at android.support.v7.widget.VectorEnabledTintResources.getDrawable(VectorEnabledTintResources.java:67)
       at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:353)
       at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:200)
       at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:188)
       at android.support.v7.widget.AppCompatDrawableManager.checkVectorDrawableSetup(AppCompatDrawableManager.java:755)
       at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:193)
       at android.support.v7.widget.TintTypedArray.getDrawableIfKnown(TintTypedArray.java:87)
       at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:128)
       at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:149)
       at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:29)
       at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:54)
       at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:202)
       at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183)
       at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519)
       at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:70)
       at com.example.googleplayservicesdemo.MainActivity.onCreate(MainActivity.java:19)
       at android.app.Activity.performCreate(Activity.java:5104)
       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
       ... 11 more
Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #17: invalid drawable tag vector
       at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:881)
       at android.graphics.drawable.Drawable.createFromXml(Drawable.java:822)
       at android.content.res.Resources.loadDrawable(Resources.java:1950)
       ... 33 more
Force finishing activity com.example.googleplayservicesdemo/.MainActivity

Cause

Android Developers documentation (Vector Drawables Backward Compatibility Solution) mentions having to add --no-version-vectors AAPT parameter for older versions of Gradle plugin.

Running android-sdk/build-tools/xx.y.z/aapt with no parameters tells us more about the parameter:
   --no-version-vectors
       Do not automatically generate versioned copies of vector XML resources.
If we look at the AppCompat library it contains only one res/drawable/abc_vector_test.xml, but if you dissamble your APK with Apktool (apktool d your.apk) you will notice that during preparing and packaging the Android tools have created two versions from the original: res/drawable/abc_vector_test.xml and res/drawable-v21/abc_vector_test.xml.

Eclipse Andmore

Eclipse Andmore brought support for --no-version-vectors with version 0.5.1 (bug 509663)
  1. Go to your app project > Properties
  2. Check the '--no-version-vectors' option
  3. Project > Clean

Eclipse ADT

Eclipse ADT plugin is no longer supported by Google, but if you are still using it and you haven't migrated to Eclipse Andmore or Android Studio yet there is a solution that involves replacing aapt with a wrapper tool that will add --no-version-vectors when called with package option.

That is because if you enable verbose (Preferences > Android > Build > Build output = Verbose) the path and name of aapt tool is pretty much hardcoded so for this to work we will need to rename the original and replace it with this wrapper program I wrote for this.

  1. Download the latest from Github dandar3/android-aapt-wrapper releases
  2. Go to android-sdk\build-tools\xx.y.z\
  3. Rename aapt.exe to aapt-original.exe (Windows) and aapt to aapt-original (Linux) 
  4. Save aapt-wrapper.exe as aapt.exe (Windows) and aapt-wrapper as aapt (Linux) 
  5. Verify the pass through by running aapt - you should see the wrapper info followed by the real aapt output:
    Android Asset Packaging Tool - Wrapper
    Version 1.0 (31 Dec 2017)
    https://github.com/dandar3/android-aapt-wrapper
    
    Command:
      aapt-original.exe
    
    Android Asset Packaging Tool
    
    Usage:
     aapt l[ist] [-v] [-a] file.{zip,jar,apk}
       List contents of Zip-compatible archive.
    
     aapt d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]
       strings          Print the contents of the resource table string pool in the APK.
    ... 
  6. Project > Clean