google / secrets-gradle-plugin

A Gradle plugin for providing your secrets to your Android project.
Apache License 2.0
1.13k stars 99 forks source link

Merged Manifest error #41

Open ElegyD opened 3 years ago

ElegyD commented 3 years ago

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 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?

arriolac commented 2 years ago

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?

ElegyD commented 2 years ago

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.

Dikyashi commented 2 years ago

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?.

arriolac commented 2 years ago

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

Dikyashi commented 2 years ago

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.

arriolac commented 2 years ago

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.

Dikyashi commented 1 year ago

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();
        }
    };
arriolac commented 1 year ago

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

shashankKuchukulla-whoop commented 1 year ago

Any resolution to this error?

ElegyD commented 1 year ago

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

0neel commented 1 year ago

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

ArtemBatkov commented 1 year ago

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?

0neel commented 1 year ago

@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.

ArtemBatkov commented 1 year ago

@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> 
0neel commented 4 months ago

@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: ""]
}
TarekIdrees commented 1 month ago

Well, all what you have to do is to add the secret plugin of google maps inside the gradle file of the same module that you use your map api key on it.

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

local.proprties = MAPS_API_KEY=AIza..............._BdT26Ys

   plugins {
   alias(libs.plugins.mapsplatform.secrets.plugin)
}

mapsplatform-secrets-plugin = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secretsPlugin" }

secretsPlugin = "2.0.1"

luka-lukovic-tyllo commented 3 weeks ago

i tried @TarekIdrees solution, and it works, thumbs up!