34

Maybe I am missing something here, but I am not able to use the new Maps only dependency in Play Services 6.5

I get the following exception:

java.lang.NoSuchFieldError: No static field MapAttrs of type 
    [I in class Lcom/google/android/gms/R$styleable; or its superclasses 
    (declaration of 'com.google.android.gms.R$styleable' appears in 
    /data/app/com.kaching.merchant.dev1-1/base.apk)
        at com.google.android.gms.maps.GoogleMapOptions
            .createFromAttributes(Unknown Source)
        at com.google.android.gms.maps.SupportMapFragment
            .onInflate(Unknown Source)

Manifest:

<meta-data android:name="com.google.android.gms.version"
  android:value="@integer/google_play_services_version" />

<meta-data
  android:name="com.google.android.maps.v2.API_KEY"
  android:value="my-awesome-key"/>


<uses-permission 
  android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

Gradle file:

compile 'com.google.android.gms:play-services-maps:6.5.+'
compile 'com.android.support:support-v4:21.0.2'

Layout:

<fragment
   android:id="@+id/map"
   android:name="com.google.android.gms.maps.MapFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"/>

Is this broken or am I doing something wrong?

The full bundle pushes me over the dex limit and I would prefer not to use multidex

JJD
  • 50,076
  • 60
  • 203
  • 339
Philipp E.
  • 3,296
  • 3
  • 34
  • 52
  • 1
    I'm still trying to know why this happens but I suggest you include the whole gms bundle instead of just `play-services-maps` – Pedro Oliveira Dec 09 '14 at 11:40
  • @PedroOliveira The dependency links in the base bundle so no need – pablisco Dec 09 '14 at 11:43
  • 4
    problem is `com.google.android.gms.R$styleable.MapAttrs` but generated R file for maps has different package `com.google.android.gms.maps.R$styleable.MapAttrs` seems like error with those version of "granualr depends" and as is now `Selectively compiling APIs` is not useable ... – Selvin Dec 09 '14 at 12:06
  • The solution by @PedroOliveira works for me, still beats the point of the new structure though... – Joris Dec 09 '14 at 12:12
  • 3
    I did manage to make it works (apk size: maps+base 1,9 MB whole gms: 2,5MB) ... steps: 1. copy maps and base aar files to libs folder of project 2. add dependency to em in gradle instead of oryginal 3. modify the package inside AndroidManifest.xml inside maps.aar (remove: ".maps") 4. dissable enforceUniquePackageName (set it to false) ... in other words: not worth of time ... we have to wait until google fix it – Selvin Dec 09 '14 at 12:16
  • 6
    Alright, so this is actually broken. I am baffled that apparently nobody at Google thought of tested this before releasing it. – Philipp E. Dec 09 '14 at 12:34
  • 5
    ok, i did a bug report: https://code.google.com/p/android/issues/detail?id=82148&thanks=82148 – Selvin Dec 09 '14 at 12:58
  • 1
    You can create an instance of a MapFragment and add it to a container in a fragment transaction. Worked for me, but I have a simple map with almost no logic in my app. – ibit Dec 09 '14 at 13:05
  • 2
    @Selvin there's also a bug report from yesterday: https://code.google.com/p/gmaps-api-issues/issues/detail?id=7432 I starred both, because your contains more details – Michał Klimczak Dec 09 '14 at 13:24
  • @ibit thanks, this works for me, at least for now. If you add this as an answer, I will accept it. – Philipp E. Dec 09 '14 at 13:43
  • 3
    For future readers too, it only seems that inflating a map fragment (or map view as is my case) from xml causes this issue. If you instantiate the fragment (or view) in code its all good. – krishan711 Dec 09 '14 at 15:18

5 Answers5

17

Updating your Google Repository to version 15 via the SDK Manager should resolve the issues and eliminate the needs for the workarounds. A project clean is required.

Android SDK

This is also mentioned in issue 7432.

JJD
  • 50,076
  • 60
  • 203
  • 339
PaulR
  • 3,223
  • 1
  • 21
  • 32
  • My problem was "Caused by: java.lang.NoSuchFieldError: com.google.android.gms.R$styleable.AdsAttrs", and this solved. Thanks – magirtopcu Feb 16 '15 at 15:18
  • A `gradle clean`, then `gradle build` was required for me after I updated Google Repository. I think when you import new dependencies or update, Android Studio tends to lag a bit behind in finding the resources correctly. – Chris Cirefice Jun 11 '15 at 14:22
  • 1
    I'm developing on xamarin platform and I had a same problem. Cleaning solution is resolved my problem. – ddagsan Apr 24 '16 at 17:19
5

Interim solution

replace the xml map fragment with a FrameLayout container

<FrameLayout
    android:id="@+id/map_container"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp"
/>
<!--<fragment android:id="@+id/map"-->
<!--android:layout_weight="2"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="0dp"-->
<!--android:name="com.google.android.gms.maps.SupportMapFragment"/>-->

Create the fragment in code and replace the container

SupportMapFragment supportMapFragment = SupportMapFragment.newInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.map_container,supportMapFragment).commit();

//this you should do anyway
supportMapFragment.getMapAsync(new OnMapReadyCallback() {
    @Override
    public void onMapReady(GoogleMap googleMap) {
        //setup map - optional
        UiSettings settings = googleMap.getUiSettings();
        settings.setCompassEnabled(false);
        settings.setZoomControlsEnabled(false);
        settings.setAllGesturesEnabled(true);
        settings.setMyLocationButtonEnabled(true);
    }
});

Please note that the above was done in 'onCreate' in an activity without any other fragments, so make sure you adapt the transaction to your lifecycle and logic.

ibit
  • 316
  • 1
  • 6
4

I found a "hacky" fix to make it work with your app until Google decides to fix this :

Add this to your app gradle script:

afterEvaluate {
    def pattern = ~/process(.*)Resources/
    tasks.matching { pattern.matcher(it.name).find() }.each {
        def matcher = pattern.matcher(it.name)
        matcher.find()
        def buildType = matcher.group(1)
        buildType = buildType.substring(0, 1).toLowerCase() + buildType.substring(1)
        def rDirectory = "$project.buildDir/generated/source/r/$buildType"
        it << {
            def badFile = file("$rDirectory/com/google/android/gms/R.java")
            def goodFile = file("$rDirectory/com/google/android/gms/maps/R.java")
            if (badFile.exists() && goodFile.exists()) {
                badFile.text = goodFile.text.replaceAll('com.google.android.gms.maps', 'com.google.android.gms')
            }
        }
    }
}
pablisco
  • 14,027
  • 4
  • 48
  • 70
  • 12
    Note that this is a terrible fix that will not scale if you use more that one play-services-* sub-libraries. We are going to fix the problem properly. – Xavier Ducrohet Dec 09 '14 at 20:29
  • 1
    @XavierDucrohet: Yeah! merging them would be too much. I imagined you'll be working on it... But amazing to see you are on the hunt. I was too exited and wanted to try your new libraries, hehe. Wasn't intended for a final fix :) – pablisco Dec 09 '14 at 20:36
  • does not work for me. Do I need to do anything else? – Philipp E. Dec 10 '14 at 10:03
  • @PhilippE.: Are you putting it in the `app` gradle and not the project gradle? – pablisco Dec 10 '14 at 11:26
  • app gradle, below the android block – Philipp E. Dec 10 '14 at 12:44
  • Thanks to your suggestion I was able to place the xml file correctly when doing it on Eclipse. Answer is below. – Pier Betos Sep 11 '15 at 05:29
1

I think you have layout in both library and module with same name or inflating multiple xml layout with duplicate resource id.

Find map_attrs in play-services-lib and replace with this code:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <declare-styleable name="MapAttrs">
    <attr name="mapType" format="enum">
      <enum name="none" value="0"/>
      <enum name="normal" value="1"/>
      <enum name="satellite" value="2"/>
      <enum name="terrain" value="3"/>
      <enum name="hybrid" value="4"/>



    </attr>
    <attr name="cameraBearing" format="float"/>
    <attr name="cameraTargetLat" format="float"/>
    <attr name="cameraTargetLng" format="float"/>
    <attr name="cameraTilt" format="float"/>
    <attr name="cameraZoom" format="float"/>
    <attr name="liteMode" format="boolean"/>



    <attr name="uiCompass" format="boolean"/>
    <attr name="uiRotateGestures" format="boolean"/>
    <attr name="uiScrollGestures" format="boolean"/>
    <attr name="uiTiltGestures" format="boolean"/>
    <attr name="uiZoomControls" format="boolean"/>
    <attr name="uiZoomGestures" format="boolean"/>
    <attr name="useViewLifecycle" format="boolean"/>
    <attr name="zOrderOnTop" format="boolean"/>
    <attr name="uiMapToolbar" format="boolean"/>
    <attr name="ambientEnabled" format="boolean"/>
  </declare-styleable>

</resources>
Adnan
  • 1,440
  • 2
  • 18
  • 38
  • Thanks,your answer solved my problem also :) I think you have layout in both library and module with same name or inflating multiple xml layout with duplicate resource id. – Smit.Satodia Jun 23 '16 at 10:47
0

Finally I found out the cause. If you are on a habit of kidnapping the aar files for your own Eclipse benefit (I'm not gonna teach here how because it's not the Android Studio way), you need to move the maps_attrs.xml file on the play-services-base res/values folder. This will align the attributes and the generated R.class file on the class path the maps library is expecting.

Sample use of play-services-base

Pier Betos
  • 1,038
  • 9
  • 17