Status Update
Comments
al...@google.com <al...@google.com> #2
Slipped Oct iteration. We... don't really have a plan here yet, but this is P1 to stop the bleeding.
libraries where all resources are currently considered public but have never been tracked
Safest route for external developers is to make all existing resources officially public. That's going to be more work since we can't just copy the public.txt
file. It also means that internal developers are locked into their existing resources, which is... safer, but not good for evolution of libraries.
Easiest route for internal developers (and our team) is to make all existing resources officially private. That will potentially break g3 drops and third-party libraries; however, it's an easy workaround given that we don't do resource namespacing yet. Developers can just define the resource that they (or their dependency) needs. Anyone using a dependency's R class directly is already hosed, anyway, so we'll ignore that.
al...@google.com <al...@google.com> #3
Going to move forward with "fixing" the libraries which accidentally exposed all their resources as public.
Tentatively, we'll:
- Require a
public.txt
to exist in the AAR, with a failure message along the lines of "At least one public resource must be defined. If your library has no public resources then please define a single, empty<public />
element inres/values/public.xml
." - Add a
public.xml
file as described to all failing libraries - Be very, very explicit about the change in release notes
- Deal with the fallout in g3
Estimate is 2 due to g3 issues.
al...@google.com <al...@google.com>
al...@google.com <al...@google.com> #4
(1) in public.txt
output from MergeResources
task, but I'm not confident that would map to "all resources are public by default".
+cc'ing Izabela who might know how to get at this information from within a Gradle plugin.
We could also skip (1) and implement (2) by forcing all libraries to include a resource XML with a single <public />
element.
im...@google.com <im...@google.com> #5
I agree that "no public tag means everything is public" is a nuisance, and gave us a lot of hassle when implementing the conversion of AARs to namespaced ones (which as you know are very strict with res visibility). While we can't change that behaviour for backwards compatibility, we could propose changing to always generating public.txt (filled with *all* local resources if no public tags were defined) - It would increase the AAR size, but it's probably negligible.
For now, you should be able to consume the public.txt from MergeResources (the "PACKAGE" one, since in libraries you will have two MergeResources tasks, the other one being "MERGE"), by extra gradle Task that sees if the file exists - if it doesn't then fail and say "you don't have a <public> tag defined, if you need all resources to be public you need to list them all" or whatever matches your case.
I think Chris has done a lot of work around the APIs recently, and added a public API for getting the public.txt in GenerateApiPublicTxtTask and the artifact ArtifactType.PUBLIC_ANDROID_RESOURCES_LIST. However, this one's behaviour is different, meaning that if there were no <public> tags, it will generate the public.txt will *all* symbols (instead of not writing it). The one matching the AAR's public.txt would be InternalArtifactType.PUBLIC_RES but that one is our internal artifact.
al...@google.com <al...@google.com> #6
if it doesn't then fail and say "you don't have a <public> tag defined, if you need all resources to be public you need to list them all" or whatever matches your case.
I was hoping to avoid this for libraries that don't have any resources defined.
However, this one's behaviour is different, meaning that if there were no <public> tags, it will generate the public.txt will all symbols (instead of not writing it).
I could correlate between the two -- if the AAR does not have a public.txt
but GenerateApiPublicTxtTask
has a non-empty public.txt
then the developer has added resources but no explicit <public />
.
Which feels hacky. I think we'll just force every library to have a single <public />
element by default. One less thing for developers to think about.
al...@google.com <al...@google.com> #7
Forcing every library to have a <public />
element ended up being a bit hacky as well since some libraries were already correct and the build will fail if you define <public />
twice. I ended up removing all the existing <public />
definitions in aosp/1546636.
ap...@google.com <ap...@google.com> #8
Branch: androidx-main
commit 721ee0257e22d51a901eab77d8ba07112b608d55
Author: Alan Viverette <alanv@google.com>
Date: Mon Jan 11 10:55:42 2021
Always define public resources
Relnote: "Resources in libraries with no explicily declared public resources
(ex. via public.xml) are now private by default."
Fixes: 170882230
Test: ./gradlew checkResourceApi
Change-Id: Ia1dcca1ad5c65c1ab90b97c22589e7392161fd62
A buildSrc/res/values/public.xml
M buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
M buildSrc/src/main/kotlin/androidx/build/resources/GenerateResourceApiTask.kt
A buildSrc/src/main/kotlin/androidx/build/resources/PublicResourcesStubHelper.kt
M camera/camera-camera2/src/main/res/values/public.xml
M camera/camera-core/src/main/res/values/public.xml
M compose/ui/ui/src/androidMain/res/values/public.xml
M fragment/fragment/src/main/res/values/public.xml
Description
Our resource API tracking inverts the behavior of AGP by treating the "no public element" case as "all resources are private" when in fact it indicates the legacy "all resources are public" behavior.
The correct way to declare "no public elements" is to define a single
<public />
element.Unclear how we're going to handle this for existing libraries where all resources are currently considered public but have never been tracked.