From b06188fa454ce995f74b3d866672b04a86a4e2db Mon Sep 17 00:00:00 2001 From: Peter Collins Date: Mon, 13 May 2024 09:53:12 -0700 Subject: [PATCH] [android] Add gradle build task (#19) Introduces a new `@(GradleProjectReference)` item to help simplify the content that needs to be added to the binding .csproj file. This item will translate relevant metadata to the `@(AndroidLibrary)` item that is automatically added to the project after the gradle project is built. A gradle build task has been added to improve msbuild output and error logging when a gradle invocation fails. We will now attempt to set `$ANDROID_HOME` and `$JAVA_HOME` automatically when invoking gradle. These values will be determined by Android SDK tooling resolution tasks, and can be changed by setting `$(AndroidSdkDirectory)` and `$(JavaSdkDirectory)` in the project file or on the command line. --- .editorconfig | 302 ++++++++++++++++++ eng/Common.android.targets | 86 +++-- eng/Common.targets | 19 ++ ....Maui.BindingExtensions.Build.Tasks.csproj | 2 +- .../Tasks/BindingToolTask.cs | 8 +- .../Tasks/Gradle.cs | 46 +++ .../Facebook.Android.Binding.csproj | 14 +- 7 files changed, 432 insertions(+), 45 deletions(-) create mode 100644 .editorconfig create mode 100644 eng/Common.targets create mode 100644 eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/Gradle.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2c0a140 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,302 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +# Default settings: +# A newline ending every file +# Use 4 spaces as indentation +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +spelling_exclusion_path = ./exclusion.dic + +[*.json] +indent_size = 2 + +# Generated code + +# C# files +[*.cs] +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion + +# Types: use keywords instead of BCL types, and permit var only when the type is clear +csharp_style_var_for_built_in_types = false:none +csharp_style_var_when_type_is_apparent = false:none +csharp_style_var_elsewhere = false:none +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# name all constant fields using PascalCase +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# static fields should have s_ prefix +dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion +dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static +dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected +dotnet_naming_style.static_prefix_style.required_prefix = s_ +dotnet_naming_style.static_prefix_style.capitalization = camel_case + +# internal and private fields should be _camelCase +dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal +dotnet_naming_style.camel_case_underscore_style.required_prefix = _ +dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case + +# Code style defaults +csharp_using_directive_placement = outside_namespace:suggestion +dotnet_sort_system_directives_first = true +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true:none +csharp_preserve_single_line_statements = false:none +csharp_prefer_static_local_function = true:suggestion +csharp_prefer_simple_using_statement = false:none +csharp_style_prefer_switch_expression = true:suggestion + +# Code quality +dotnet_style_readonly_field = true:suggestion +dotnet_code_quality_unused_parameters = non_public:suggestion + +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +csharp_prefer_simple_default_expression = true:suggestion + +# Expression-bodied members +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_constructors = true:silent +csharp_style_expression_bodied_operators = true:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = true:silent + +# Pattern matching +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion + +# Null checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Other features +csharp_style_prefer_index_operator = false:none +csharp_style_prefer_range_operator = false:none +csharp_style_pattern_local_over_anonymous_function = false:none + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Default analyzed API surface = 'all' (public APIs + non-public APIs) +dotnet_code_quality.api_surface = all + +# Code files +[*.{cs,vb}] +# Analyzers +dotnet_code_quality.ca1802.api_surface = private, internal +dotnet_code_quality.ca1822.api_surface = private, internal +dotnet_code_quality.ca2208.api_surface = public +# Mark attributes with AttributeUsageAttribute +dotnet_diagnostic.CA1018.severity = warning +# Properties should not be write only +dotnet_diagnostic.CA1044.severity = warning +# Do not declare protected member in sealed type +dotnet_diagnostic.CA1047.severity = warning +# Declare types in namespaces +dotnet_diagnostic.CA1050.severity = warning +# Avoid using cref tags with a prefix +dotnet_diagnostic.CA1200.severity = suggestion +# P/Invokes should not be visible +dotnet_diagnostic.CA1401.severity = warning +# Parameter names should match base declaration +dotnet_diagnostic.CA1725.severity = suggestion +# Remove empty Finalizers +dotnet_diagnostic.CA1821.severity = warning +# Mark assemblies with NeutralResourcesLanguageAttribute +dotnet_diagnostic.CA1824.severity = warning +# Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used +dotnet_diagnostic.CA1828.severity = warning +# Prefer strongly-typed Append and Insert method overloads on StringBuilder. +dotnet_diagnostic.CA1830.severity = warning +# Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1832.severity = warning +# Use AsSpan or AsMemory instead of Range-based indexers when appropriate +dotnet_diagnostic.CA1833.severity = warning +# Prefer IsEmpty over Count +dotnet_diagnostic.CA1836.severity = warning +# Use 'Environment.ProcessPath' +dotnet_diagnostic.CA1839.severity = warning +# Do not call ToImmutableCollection on an ImmutableCollection value +dotnet_diagnostic.CA2009.severity = warning +# Avoid infinite recursion +dotnet_diagnostic.CA2011.severity = warning +# Initialize value type static fields inline +dotnet_diagnostic.CA2207.severity = warning +# Implement serialization constructors +dotnet_diagnostic.CA2229.severity = warning +# Provide correct arguments to formatting methods +dotnet_diagnostic.CA2241.severity = warning +# Test for NaN correctly +dotnet_diagnostic.CA2242.severity = warning +# Do not assign a property to itself. +dotnet_diagnostic.CA2245.severity = warning +# Provide correct 'enum' argument to 'Enum.HasFlag' +dotnet_diagnostic.CA2248.severity = warning +# Do Not Add Schema By URL +dotnet_diagnostic.CA3061.severity = warning +# Insecure DTD processing in XML +dotnet_diagnostic.CA3075.severity = warning +# Insecure XSLT script processing. +dotnet_diagnostic.CA3076.severity = warning +# Insecure Processing in API Design, XmlDocument and XmlTextReader +dotnet_diagnostic.CA3077.severity = warning +# Mark Verb Handlers With Validate Antiforgery Token +dotnet_diagnostic.CA3147.severity = warning +# Do Not Use Broken Cryptographic Algorithms +dotnet_diagnostic.CA5351.severity = warning +# Do Not Disable Certificate Validation +dotnet_diagnostic.CA5359.severity = warning +# Do Not Call Dangerous Methods In Deserialization +dotnet_diagnostic.CA5360.severity = warning +# Do Not Disable SChannel Use of Strong Crypto +dotnet_diagnostic.CA5361.severity = warning +# Do Not Disable Request Validation +dotnet_diagnostic.CA5363.severity = warning +# Do Not Use Deprecated Security Protocols +dotnet_diagnostic.CA5364.severity = warning +# Do Not Disable HTTP Header Checking +dotnet_diagnostic.CA5365.severity = warning +# Set ViewStateUserKey For Classes Derived From Page +dotnet_diagnostic.CA5368.severity = warning +# Use XmlReader For Validating Reader +dotnet_diagnostic.CA5370.severity = warning +# Do not use obsolete key derivation function +dotnet_diagnostic.CA5373.severity = warning +# Do Not Use XslTransform +dotnet_diagnostic.CA5374.severity = warning +# Use SharedAccessProtocol HttpsOnly +dotnet_diagnostic.CA5376.severity = warning +# Use Container Level Access Policy +dotnet_diagnostic.CA5377.severity = warning +# Do not disable ServicePointManagerSecurityProtocols +dotnet_diagnostic.CA5378.severity = warning +# Do Not Use Weak Key Derivation Function Algorithm +dotnet_diagnostic.CA5379.severity = warning +# Do Not Add Certificates To Root Store +dotnet_diagnostic.CA5380.severity = warning +# Ensure Certificates Are Not Added To Root Store +dotnet_diagnostic.CA5381.severity = warning +# Do Not Use Digital Signature Algorithm (DSA) +dotnet_diagnostic.CA5384.severity = warning +# Use Rivest–Shamir–Adleman (RSA) Algorithm With Sufficient Key Size +dotnet_diagnostic.CA5385.severity = warning +dotnet_diagnostic.CS1591.severity = suggestion +# UseIsNullCheck +dotnet_diagnostic.IDE0041.severity = warning +# ValidateFormatString +dotnet_diagnostic.IDE0043.severity = warning +# MakeLocalFunctionStatic +dotnet_diagnostic.IDE0062.severity = warning +# ConvertTypeOfToNameOf +dotnet_diagnostic.IDE0082.severity = warning +# Remove unnecessary lambda expression +dotnet_diagnostic.IDE0200.severity = none +# Remove redundant nullable directive +dotnet_diagnostic.IDE0240.severity = warning + +# C++ Files +[*.{cpp,h,in}] +curly_bracket_next_line = true +indent_brace_style = Allman + +# Xml project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] +indent_size = 2 + +[*.{csproj,vbproj,proj,nativeproj,locproj}] +charset = utf-8-bom + +# Xml build files +[*.builds] +indent_size = 2 + +# Xml files +[*.{xml,stylecop,resx,ruleset}] +indent_size = 2 + +# Xml config files +[*.{props,targets,config,nuspec}] +indent_size = 2 + +# YAML config files +[*.{yml,yaml}] +indent_size = 2 + +# Shell scripts +[*.sh] +end_of_line = lf +[*.{cmd, bat}] +end_of_line = crlf diff --git a/eng/Common.android.targets b/eng/Common.android.targets index 5934073..9b2fbb5 100644 --- a/eng/Common.android.targets +++ b/eng/Common.android.targets @@ -1,36 +1,56 @@ + - - - <_AndroidProjectDirFullPath>$([System.IO.Path]::GetFullPath($(AndroidProjectDir))) - - <_AndroidProjectModuleBuildPath>$(_AndroidProjectDirFullPath)/$(AndroidProjectModule)/build - <_AndroidAarOutputPath>$(_AndroidProjectModuleBuildPath)/outputs/aar/$(AndroidProjectModule).aar - True - - <_AndroidGradleW>gradlew - <_AndroidGradleW Condition="$([MSBuild]::IsOSPlatform('windows'))">$(_AndroidGradleW).exe - <_AndroidGradleWFullPath>$([System.IO.Path]::Combine($(_AndroidProjectDirFullPath), $(_AndroidGradleW))) - - <_AndroidHome>$([System.Environment]::GetEnvironmentVariable('ANDROID_HOME')) - <_AndroidHome Condition=" '$(_AndroidHome)' == '' ">$(HOME)/Library/Developer/Xamarin/android-sdk-macosx - - - - <_AndroidGradleInputs Include="$(_AndroidProjectDirFullPath)/**/*.java" Exclude="$(_AndroidProjectModuleBuildPath)/**/*" /> - <_AndroidGradleInputs Include="$(_AndroidProjectDirFullPath)/**/*.gradle" Exclude="$(_AndroidProjectModuleBuildPath)/**/*" /> - <_AndroidGradleInputs Include="$(_AndroidProjectDirFullPath)/**/*.xml" Exclude="$(_AndroidProjectModuleBuildPath)/**/*" /> - <_AndroidGradleInputs Include="$(_AndroidProjectDirFullPath)/**/*.properties" Exclude="$(_AndroidProjectModuleBuildPath)/**/*" /> - - - - - - - - - + + + + + + Release + + + + + true + true + false + + + + + + <_GradleInputs Include="%(GradleProjectReference.FullPath)/**/*.java" /> + <_GradleInputs Include="%(GradleProjectReference.FullPath)/**/*.gradle" /> + <_GradleInputs Include="%(GradleProjectReference.FullPath)/**/*.xml" /> + <_GradleInputs Include="%(GradleProjectReference.FullPath)/**/*.properties"/> + <_GradleInputs Remove="%(GradleProjectReference.FullPath)/%(GradleProjectReference.ModuleName)/build/**/*" /> + + + + + + + + + + + + %(GradleProjectReference.Bind) + %(GradleProjectReference.Pack) + %(GradleProjectReference.Visible) + + + + + + diff --git a/eng/Common.targets b/eng/Common.targets new file mode 100644 index 0000000..bcff14d --- /dev/null +++ b/eng/Common.targets @@ -0,0 +1,19 @@ + + + + + true + $(MSBuildThisFileDirectory)src\Microsoft.Maui.BindingExtensions.Build.Tasks\bin\Debug\netstandard2.0\Microsoft.Maui.BindingExtensions.Build.Tasks.dll + $(USERPROFILE) + + + + + + + + + + diff --git a/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Microsoft.Maui.BindingExtensions.Build.Tasks.csproj b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Microsoft.Maui.BindingExtensions.Build.Tasks.csproj index dfae8a3..527bd05 100644 --- a/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Microsoft.Maui.BindingExtensions.Build.Tasks.csproj +++ b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Microsoft.Maui.BindingExtensions.Build.Tasks.csproj @@ -1,7 +1,7 @@  - net8.0 + netstandard2.0 enable enable diff --git a/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/BindingToolTask.cs b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/BindingToolTask.cs index 9465dec..fbf2e23 100644 --- a/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/BindingToolTask.cs +++ b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/BindingToolTask.cs @@ -8,13 +8,12 @@ public abstract class BindingToolTask : ToolTask { public abstract string TaskPrefix { get; } - protected string WorkingDirectory { get; private set; } + public string WorkingDirectory { get; set; } = Directory.GetCurrentDirectory(); StringBuilder toolOutput = new StringBuilder(); public BindingToolTask() { - WorkingDirectory = Directory.GetCurrentDirectory(); } public override bool Execute() @@ -43,6 +42,11 @@ protected override void LogEventsFromTextOutput(string singleLine, MessageImport toolOutput.AppendLine(singleLine); } + protected override string GetWorkingDirectory() + { + return WorkingDirectory; + } + public virtual bool RunTask() => base.Execute(); protected object ProjectSpecificTaskObjectKey(object key) => (key, WorkingDirectory); diff --git a/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/Gradle.cs b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/Gradle.cs new file mode 100644 index 0000000..88f2a5c --- /dev/null +++ b/eng/src/Microsoft.Maui.BindingExtensions.Build.Tasks/Tasks/Gradle.cs @@ -0,0 +1,46 @@ +using Microsoft.Build.Framework; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.Maui.BindingExtensions.Build.Tasks +{ + public class Gradle : BindingToolTask + { + public override string TaskPrefix => "GDL"; + + protected override string ToolName => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "gradlew.bat" : "gradlew"; + + + public string AndroidSdkDirectory { get; set; } = string.Empty; + + public string JavaSdkDirectory { get; set; } = string.Empty; + + public string Arguments { get; set; } = string.Empty; + + + public Gradle() + { + } + + protected override string GenerateFullPathToTool() + { + return Path.Combine(ToolPath, ToolExe); + } + + protected override string GenerateCommandLineCommands() => Arguments; + + protected override ProcessStartInfo GetProcessStartInfo(string pathToTool, string commandLineCommands, string responseFileSwitch) + { + ProcessStartInfo psi = base.GetProcessStartInfo(pathToTool, commandLineCommands, responseFileSwitch); + if (Directory.Exists(AndroidSdkDirectory)) + psi.Environment["ANDROID_HOME"] = AndroidSdkDirectory; + + if (Directory.Exists(JavaSdkDirectory)) + psi.Environment["JAVA_HOME"] = JavaSdkDirectory; + + return psi; + } + + } +} diff --git a/facebook/android/Facebook.Android.Binding/Facebook.Android.Binding.csproj b/facebook/android/Facebook.Android.Binding/Facebook.Android.Binding.csproj index 348acd7..4a79ab2 100644 --- a/facebook/android/Facebook.Android.Binding/Facebook.Android.Binding.csproj +++ b/facebook/android/Facebook.Android.Binding/Facebook.Android.Binding.csproj @@ -7,19 +7,15 @@ Facebook false + + - - mauifacebook.aar + + mauifacebook true true - false - + - - $(MSBuildThisFileDirectory)../native - mauifacebook - - \ No newline at end of file