Skip to content

[Xamarin.Android.Build.Tasks] <GenerateJavaStubs/> only for MonoAndroid assemblies #2643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions src/Xamarin.Android.Build.Tasks/Tasks/ResolveAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,21 @@ void AddAssemblyReferences (MetadataResolver resolver, Dictionary<string, ITaskI
if (resolutionPath == null)
resolutionPath = new List<string>();

CheckAssemblyAttributes (assembly, reader);
CheckAssemblyAttributes (assembly, reader, out string targetFrameworkIdentifier);

LogMessage ("{0}Adding assembly reference for {1}, recursively...", new string (' ', indent), assemblyName);
resolutionPath.Add (assemblyName);
indent += 2;

// Add this assembly
if (!topLevel) {
assemblies [assemblyName] = CreateAssemblyTaskItem (Path.GetFullPath (assemblyPath));
if (topLevel) {
if (!string.IsNullOrEmpty (targetFrameworkIdentifier) && assemblies.TryGetValue (assemblyName, out ITaskItem taskItem)) {
if (string.IsNullOrEmpty (taskItem.GetMetadata ("TargetFrameworkIdentifier"))) {
taskItem.SetMetadata ("TargetFrameworkIdentifier", targetFrameworkIdentifier);
}
}
} else {
assemblies [assemblyName] = CreateAssemblyTaskItem (assemblyPath, targetFrameworkIdentifier);
}

// Recurse into each referenced assembly
Expand Down Expand Up @@ -257,8 +263,10 @@ void AddAssemblyReferences (MetadataResolver resolver, Dictionary<string, ITaskI
resolutionPath.RemoveAt (resolutionPath.Count - 1);
}

void CheckAssemblyAttributes (AssemblyDefinition assembly, MetadataReader reader)
void CheckAssemblyAttributes (AssemblyDefinition assembly, MetadataReader reader, out string targetFrameworkIdentifier)
{
targetFrameworkIdentifier = null;

foreach (var handle in assembly.GetCustomAttributes ()) {
var attribute = reader.GetCustomAttribute (handle);
switch (reader.GetCustomAttributeFullName (attribute)) {
Expand All @@ -275,14 +283,26 @@ void CheckAssemblyAttributes (AssemblyDefinition assembly, MetadataReader reader
case "System.Runtime.Versioning.TargetFrameworkAttribute": {
var arguments = attribute.GetCustomAttributeArguments ();
foreach (var p in arguments.FixedArguments) {
// Of the form "MonoAndroid,Version=v8.1"
var value = p.Value?.ToString ();
if (value != null && value.StartsWith ("MonoAndroid", StringComparison.Ordinal)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer this original code of using value.StartsWith("MonoAndroid") -- though perhaps it should be extended to value.StartsWith("MonoAndroid,")? -- largely because I'm not sure about what are the requirements and constraints on framework names.

For example, if a "framework name" could contain a comma, the new approach of splitting on all commas may cause a "mismatch". Using StartsWith() against MonoAndroid, would alloy such fears.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After using IndexOf + Substring, I think it's still OK to just compare targetFrameworkIdentifier == "MonoAndroid":

//
// Summary:
//     Reports the zero-based index of the first occurrence of the specified string
//     in the current System.String object. A parameter specifies the type of search
//     to use for the specified string.
//
// Returns:
//     The index position of the value parameter if that string is found, or -1 if it
//     is not. If value is System.String.Empty, the return value is 0.
public int IndexOf (String value, StringComparison comparisonType);

It should be the first instance of , and targetFrameworkIdentifier will be everything before it.

var values = value.Split ('=');
var apiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion (values [1]);
if (apiLevel != null) {
var assemblyName = reader.GetString (assembly.Name);
Log.LogDebugMessage ("{0}={1}", assemblyName, apiLevel);
api_levels [assemblyName] = apiLevel.Value;
if (!string.IsNullOrEmpty (value)) {
int commaIndex = value.IndexOf (",", StringComparison.Ordinal);
if (commaIndex != -1) {
targetFrameworkIdentifier = value.Substring (0, commaIndex);
if (targetFrameworkIdentifier == "MonoAndroid") {
const string match = "Version=";
var versionIndex = value.IndexOf (match, commaIndex, StringComparison.Ordinal);
if (versionIndex != -1) {
versionIndex += match.Length;
string version = value.Substring (versionIndex, value.Length - versionIndex);
var apiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion (version);
if (apiLevel != null) {
var assemblyName = reader.GetString (assembly.Name);
Log.LogDebugMessage ("{0}={1}", assemblyName, apiLevel);
api_levels [assemblyName] = apiLevel.Value;
}
}
}
}
}
}
Expand Down Expand Up @@ -336,15 +356,18 @@ void AddI18nAssemblies (MetadataResolver resolver, Dictionary<string, ITaskItem>
void ResolveI18nAssembly (MetadataResolver resolver, string name, Dictionary<string, ITaskItem> assemblies)
{
var assembly = resolver.Resolve (name);
var assemblyFullPath = Path.GetFullPath (assembly);
assemblies [name] = CreateAssemblyTaskItem (assemblyFullPath);
assemblies [name] = CreateAssemblyTaskItem (assembly);
}

static ITaskItem CreateAssemblyTaskItem (string assemblyFullPath)
static ITaskItem CreateAssemblyTaskItem (string assembly, string targetFrameworkIdentifier = null)
{
return new TaskItem (assemblyFullPath, new Dictionary<string, string> {
{ "ReferenceAssembly", assemblyFullPath }
});
var assemblyFullPath = Path.GetFullPath (assembly);
var dictionary = new Dictionary<string, string> (2) {
{ "ReferenceAssembly", assemblyFullPath },
};
if (!string.IsNullOrEmpty (targetFrameworkIdentifier))
dictionary.Add ("TargetFrameworkIdentifier", targetFrameworkIdentifier);
return new TaskItem (assemblyFullPath, dictionary);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,12 @@ because xbuild doesn't support framework reference assemblies.
Condition="'$(AndroidLinkMode)' != 'None' AND '$(AndroidUseSharedRuntime)' != 'true'">
<Output TaskParameter="Include" ItemName="_ShrunkFrameworkAssemblies" />
</CreateItem>

<CreateItem
Include="@(_ResolvedUserAssemblies)"
Condition="'%(_ResolvedUserAssemblies.TargetFrameworkIdentifier)' == 'MonoAndroid'">
<Output TaskParameter="Include" ItemName="_ResolvedUserMonoAndroidAssemblies" />
</CreateItem>
</Target>

<Target Name="_GenerateJavaStubs"
Expand All @@ -2302,7 +2308,7 @@ because xbuild doesn't support framework reference assemblies.
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp">
<GenerateJavaStubs
ResolvedAssemblies="@(_ResolvedAssemblies)"
ResolvedUserAssemblies="@(_ResolvedUserAssemblies)"
ResolvedUserAssemblies="@(_ResolvedUserMonoAndroidAssemblies)"
ErrorOnCustomJavaObject="$(AndroidErrorOnCustomJavaObject)"
ManifestTemplate="$(_AndroidManifestAbs)"
MergedManifestDocuments="@(ExtractedManifestDocuments)"
Expand Down