Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Sep 26, 2025

Thanks for assigning this issue to me. I'm starting to work on it and will keep this PR's description up to date as I form a plan and make progress.

Original issue description:

Android framework version

net9.0-android

Affected platform version

.NET 9.0.301

Description

We have multiple google-services.json files, per environment.
In our build pipeline, we select the appropriate file like so:

<!-- Some variable that changes based on environment -->
<EntitlementsPostifx Condition="'$(ApplicationEnvironmentName)' != ''">$(ApplicationEnvironmentName)</EntitlementsPostifx>
<GoogleServicesPostfix>$(EntitlementsPostifx)</GoogleServicesPostfix>

<!-- Parameter that selects google sevrices json based on the environment -->
<GoogleServicesJson Condition="$(TargetFramework.Contains('-android'))" Include="Platforms\Android\google-services-$(GoogleServicesPostfix).json" />

We first build the entire solution (without providing the environment name), then we build the use dotnet publish on the android project (MAUI) itself. But in the end an incorrect GoogleServicesJson is used - it uses the old one from when building the entire solution, because the target ProcessGoogleServicesJson is incorrectly skipped.

Steps to Reproduce

  1. New android app
  2. Setup GoogleServices
  3. Make GoogleServices change based on a variable, perhaps like so:
    <GoogleServicesJson Include="Platforms\Android\google-services-$(AppEnvironment).json" />
  4. Build once dotnet build xyz.csproj --property:AppEnvironment=Stage
  5. Do not dotnet clean
  6. Build a second time dotnet build xyz.csproj --property:AppEnvironment=Test
  7. The build skipped the ProcessGoogleServicesJson target, resulting in old configuration being used.

Did you find any workaround?

We use a workaround, that is not ideal.

	<Target Name="InvalidateGoogleServicesStamp" BeforeTargets="ProcessGoogleServicesJson">
		<Delete Files="$(IntermediateOutputPath)googsvcsjson.stamp" />
		<Message Text="InvalidateGoogleServicesStamp: Deleted stamp file." Importance="high" />
	</Target>	

Relevant log output

Original prompt

This section details on the original issue you should resolve

<issue_title>play-services-basement/merge.targets - ProcessGoogleServicesJson target is incorrectly skipped even when Input (GoogleServicesJson) changes</issue_title>
<issue_description>### Android framework version

net9.0-android

Affected platform version

.NET 9.0.301

Description

We have multiple google-services.json files, per environment.
In our build pipeline, we select the appropriate file like so:

<!-- Some variable that changes based on environment -->
<EntitlementsPostifx Condition="'$(ApplicationEnvironmentName)' != ''">$(ApplicationEnvironmentName)</EntitlementsPostifx>
<GoogleServicesPostfix>$(EntitlementsPostifx)</GoogleServicesPostfix>

<!-- Parameter that selects google sevrices json based on the environment -->
<GoogleServicesJson Condition="$(TargetFramework.Contains('-android'))" Include="Platforms\Android\google-services-$(GoogleServicesPostfix).json" />

We first build the entire solution (without providing the environment name), then we build the use dotnet publish on the android project (MAUI) itself. But in the end an incorrect GoogleServicesJson is used - it uses the old one from when building the entire solution, because the target ProcessGoogleServicesJson is incorrectly skipped.

Steps to Reproduce

  1. New android app
  2. Setup GoogleServices
  3. Make GoogleServices change based on a variable, perhaps like so:
    <GoogleServicesJson Include="Platforms\Android\google-services-$(AppEnvironment).json" />
  4. Build once dotnet build xyz.csproj --property:AppEnvironment=Stage
  5. Do not dotnet clean
  6. Build a second time dotnet build xyz.csproj --property:AppEnvironment=Test
  7. The build skipped the ProcessGoogleServicesJson target, resulting in old configuration being used.

Did you find any workaround?

We use a workaround, that is not ideal.

	<Target Name="InvalidateGoogleServicesStamp" BeforeTargets="ProcessGoogleServicesJson">
		<Delete Files="$(IntermediateOutputPath)googsvcsjson.stamp" />
		<Message Text="InvalidateGoogleServicesStamp: Deleted stamp file." Importance="high" />
	</Target>	

Relevant log output

```</issue_description>

<agent_instructions>@jonathanpeppers has an example on how to fix this:
* https://github.com/dotnet/android-libraries/issues/1282#issuecomment-3339113626</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@jonathanpeppers</author><body>
Can you explain what this one means?
> Make it change based on a variable

The target as-is will run again if any of the timestamps on the `@(GoogleServicesJson)` change:

https://github.com/dotnet/android-libraries/blob/3d3cc2df5ddc8c33502f48dd86dab2bfa389a9c9/source/com.google.android.gms/play-services-basement/merge.targets#L54-L60

The only bug I see, is it wouldn't run again, if the list of files change. So, if you removed a file, and built again, for example.</body></comment_new>
<comment_new><author>@jonathanpeppers</author><body>
So, your case is changing the contents of `@(GoogleServicesJson)`, but their timestamps never change.

To fix this, we'd need to do something similar to what the C# compiler does:

```xml
<Hash ItemsToHash="@(GoogleServicesJson)">
  <Output TaskParameter="HashResult" PropertyName="GoogleServicesJsonHash" />
</Hash>
<WriteLinesToFile
    Lines="$(GoogleServicesJsonHash)"
    File="$(IntermediateOutputPath)$(MSBuildProjectFile).GoogleServicesJson.cache"
    Overwrite="True"
    WriteOnlyWhenDifferent="True"
/>

And then use the new $(IntermediateOutputPath)$(MSBuildProjectFile).GoogleServicesJson.cache file as an additional input, so if that file changes it would rerun.

If you don't want to <Delete/> files, you could probably use <Touch Files="@(GoogleServicesJson)" /> as a workaround.</comment_new>

Fixes #1282

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@jonathanpeppers
Copy link
Member

@copilot try again

@jonathanpeppers
Copy link
Member

@copilot try again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

play-services-basement/merge.targets - ProcessGoogleServicesJson target is incorrectly skipped even when Input (GoogleServicesJson) changes

2 participants