secrets-gradle-plugin icon indicating copy to clipboard operation
secrets-gradle-plugin copied to clipboard

Merged Manifest error

Open ElegyD opened this issue 2 years ago • 15 comments

So I followed this guide from the Maps SDK to add the API key to the app. Now in Android Studio the Merged Manifest view no longer works which in turn also breaks the MissingPermission lint.

Android Studio shows this error when viewing the Merged Manifest:

Merging Errors: Error: Attribute meta-data#com.google.android.geo.API_KEY@value at AndroidManifest.xml:57:13-44 requires a placeholder substitution but no value for <MAPS_API_KEY> is provided. redacted.app main manifest (this file), line 56 Error: Validation failed, exiting redacted.app main manifest (this file)

MissingPermission lint warning, despite the permissions being in AndroidManifest.xml:

Missing permissions required by FusedLocationProviderClient.requestLocationUpdates: android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION

A workaround would be to manually add manifestPlaceholders = [MAPS_API_KEY: ""] to the app build.gradle, but this feels wrong. Is there a better way to avoid this, or is this more an error by Android Studio or the Android Gradle plugin?

ElegyD avatar Aug 27 '21 09:08 ElegyD

Just to clarify, you saw the error despite having the API key, MAPS_API_KEY, defined in local.properties? I see developers reporting something similar in the past when running their code on another machine that doesn't have the key defined. In which case you'll need to securely share the key or define a default value for the property so you don't get that error. Do you have any other configuration options set up in your usage?

arriolac avatar Sep 20 '21 18:09 arriolac

Correct, I have a MAPS_API_KEY in local.properties that I'm using in the AndroidManifest.xml like so ${MAPS_API_KEY}. Everything compiles correctly, Maps is working in the app, so the value is applied. But there are still the errors I wrote above. No configurations options.

ElegyD avatar Sep 21 '21 07:09 ElegyD

This issue still exist on following the documentation provided by google on https://developers.google.com/maps/documentation/android-sdk/secrets-gradle-plugin.

is there any workaround for this or a fix?.

Dikyashi avatar Sep 07 '22 08:09 Dikyashi

Please provide more info on how to repro this issue as well as the version of the library and AGP that you are using.

arriolac avatar Sep 07 '22 16:09 arriolac

AGP version 7.2.2 Gradle Version 7.3.3

Steps to repro

  1. Have a Manifest with Any Android Permission for example

  2. Follow steps given in the google link above and change the meta data accordingly

  3. A Sample piece of code

  Connectivity Manager cm;

 cm = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);
 cm.registerNetworkCallback(networkRequest, networkCallback); --> This line is flagged with Missing Permission even when permission is given in the Manifest. This is due to Manifest Merging issue

Workaround

A simple workaround is to define a manifest placeholder in the build.gradle(app module) file.

defaultConfig{
manifestPlaceholders["API_KEY"] = "Any Text Here" 
}

However as this is not mentioned anywhere in the samples/documentation i believe this is a bug.

Dikyashi avatar Sep 07 '22 16:09 Dikyashi

I tried to reproduce the issue you mentioned in 707b1a5. Based on your report, the sample app should not be able to be built due to a merged manifest error when introducing a uses-permission declaration on the manifest file, however, I'm not able to see that. @Dikyashi can you check out the sample app and see if you can repro there.

arriolac avatar Sep 07 '22 17:09 arriolac

Hi i tried this with new project with JAVA as the preferred language and the problem still exists. i used this as metadata

        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="${API_DEVICE_KEY}" />
           

and the callback as follows


 cm = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);
 cm.registerNetworkCallback(networkRequest, networkCallback); --> This line is flagged with Missing Permission even when permission is given in the Manifest. This is due to Manifest Merging issue
 
 
private ConnectivityManager.NetworkCallback networkCallback = new android.net.ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(@NonNull Network network) {
            NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
            boolean isInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);

            if (isInternet) {
                validNetwork.add(network);
            }

            checkValidNetwork();
        }

        @Override
        public void onLost(@NonNull Network network) {
            validNetwork.remove(network);
            checkValidNetwork();
        }
    };
    ```

Dikyashi avatar Sep 08 '22 10:09 Dikyashi

I'm able to see the issue now. I think this might be an issue with AGP as the manifest keys are eventually injected by this plugin so explicitly adding a manifestPlaceholders should not be necessary. Let me dig into this issue a bit more to see what the correct resolution should be.

image

arriolac avatar Sep 08 '22 17:09 arriolac

Any resolution to this error?

With the latest stable tools (AS Electric Eel 2022.1.1, AGP 7.4.0, Gradle 7.5) I no longer have this issue.

ElegyD avatar Feb 01 '23 12:02 ElegyD

The issue is still there, though AS is now able to display the merged manifest even if there are errors.

0neel avatar Feb 14 '23 15:02 0neel

I added a key to the local.propery file but my manifest has no idea what is the "MAP_API_KEY" and it throws errors when building. What I am doing wrong?

ArtemBatkov avatar Jun 12 '23 23:06 ArtemBatkov

@ArtemBatkov

I added a key to the local.propery file but my manifest has no idea what is the "MAP_API_KEY" and it throws errors when building. What I am doing wrong?

Check if you add this plugin AFTER the com.android.application plugin. Otherwise the secrets plugin silently fails to create the MAP_API_KEY placeholder.

0neel avatar Jun 13 '23 08:06 0neel

@0neel

I added a key to the local.propery file but my manifest has no idea what is the "MAP_API_KEY" and it throws errors when building. What I am doing wrong?

Check if you add this plugin AFTER the com.android.application plugin. Otherwise, the secrets plugin silently fails to create the MAP_API_KEY placeholder.

Alright. Now, I have the following code that may help somebody one day.

First, be sure that your API key works. You can check this if you try Google Maps API through web queries. https://maps.googleapis.com/maps/api/place/autocomplete/json?input=London&types=(cities)&key=YOUR_KEY Insert your key in this query and check if you are possible to see any JSON data.

Second, I added the following row to my "local.properties" file. MAPS_API_KEY=AIzaSyDX9V4L...........TszaLzf8y_Nw-nI

Third, I created an associative variable inside "build.gradle" file.

defaultConfig {
       //other code 
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        manifestPlaceholders = [googleMapsApiKey: "${properties.getProperty('MAPS_API_KEY')}"]
       //other code
}

Now we have "googleMapsApiKey" name that'll be used in the Manifest.

Fourth, Android Manifiest should look like this.

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
       // OTHER CODE
        tools:targetApi="31"
        android:name=".App">

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="${googleMapsApiKey}" />
        <uses-library  android:name="com.google.android.maps"/>

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Notice, the teg "meta-data" is between the "application" tag and "activity" one. Also, Google Map Documentation says use the following "meta-data"

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="${MAPS_API_KEY}" /> 

HOWEVER, I replaced it with this one.

<meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="${googleMapsApiKey}" />
        <uses-library  android:name="com.google.android.maps"/> 

Fifth, if it is still a problem to present a map but you can see Google's logo, you are on the right way. I checked the internet connection and noticed it didn't work. So, please, be sure that your device has the internet spot.

Recently, I used MapView element instead of Fragment, and I had initialization problems, please, change your MapView to Fragment.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <fragment xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/mapView"
        tools:context=".MapPage"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout> 

ArtemBatkov avatar Jun 13 '23 13:06 ArtemBatkov

@ArtemBatkov you don't actually need to manually parse the properties file. As mentioned in the original message setting the placeholder to an empty value is enough to fix the merged Manifest view.

defaultConfig {
    manifestPlaceholders = [googleMapsApiKey: ""]
}

0neel avatar Apr 27 '24 09:04 0neel