This commit is contained in:
Jonathan Dick 2020-11-25 20:29:08 -05:00
Родитель 8f942b2134
Коммит 7044106709
63 изменённых файлов: 8291 добавлений и 0 удалений

10
NuGet.config Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="globalPackagesFolder" value=".\packages" />
</config>
<packageSources>
<!-- Add this repository to the list of available repositories -->
<add key="XamarinBindingHelpers" value=".\output" />
</packageSources>
</configuration>

Просмотреть файл

@ -0,0 +1,6 @@
<Project>
<PropertyGroup>
<RestoreNoCache>true</RestoreNoCache>
<RestorePackagesPath>..\packages</RestorePackagesPath>
</PropertyGroup>
</Project>

Просмотреть файл

@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with your package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

Просмотреть файл

@ -0,0 +1,21 @@
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Widget;
using AndroidX.AppCompat.App;
namespace SampleAndroidApp
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.companyname.sampleandroidapp">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

Просмотреть файл

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SampleAndroidApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SampleAndroidApp")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,44 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.xml file, or R.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

5778
Samples/SampleAndroidApp/Resources/Resource.designer.cs сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Двоичные данные
Samples/SampleAndroidApp/Resources/mipmap-hdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.5 KiB

Двоичные данные
Samples/SampleAndroidApp/Resources/mipmap-mdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 958 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.4 KiB

Двоичные данные
Samples/SampleAndroidApp/Resources/mipmap-xhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Двоичные данные
Samples/SampleAndroidApp/Resources/mipmap-xxhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.8 KiB

Двоичные данные
Samples/SampleAndroidApp/Resources/mipmap-xxxhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 11 KiB

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#2c3e50</color>
<color name="colorPrimaryDark">#1B3147</color>
<color name="colorAccent">#3498db</color>
</resources>

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#2C3E50</color>
</resources>

Просмотреть файл

@ -0,0 +1,4 @@
<resources>
<string name="app_name">SampleAndroidApp</string>
<string name="action_settings">Settings</string>
</resources>

Просмотреть файл

@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

Просмотреть файл

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{122416d6-6b49-4ee2-a1e8-b825f31c79fe}</TemplateGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SampleAndroidApp</RootNamespace>
<AssemblyName>SampleAndroidApp</AssemblyName>
<FileAlignment>512</FileAlignment>
<Deterministic>True</Deterministic>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<AndroidUseAapt2>true</AndroidUseAapt2>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Properties\AndroidManifest.xml" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\activity_main.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\colors.xml" />
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
<AndroidResource Include="Resources\values\strings.xml" />
<AndroidResource Include="Resources\values\styles.xml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\drawable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.AppCompat">
<Version>1.2.0.5</Version>
</PackageReference>
<PackageReference Include="Xamarin.Binding.Helpers" Version="0.1.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SampleAndroidBinding\SampleAndroidBinding.csproj">
<Project>{a4d2280b-c68c-4835-a930-be03d64809bc}</Project>
<Name>SampleAndroidBinding</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,48 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

Просмотреть файл

@ -0,0 +1,24 @@
This directory is for Android .jars.
There are 2 types of jars that are supported:
== Input Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
Set the build action for these jars in the properties page to "InputJar".
== Reference Jars ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".

Просмотреть файл

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="MSBuild.Sdk.Extras/2.1.2">
<PropertyGroup>
<TargetFrameworks>MonoAndroid10.0</TargetFrameworks>
<IsBindingProject>true</IsBindingProject>
<AssemblyName>Xamarin.Binding.Helpers.Sample.Android</AssemblyName>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<AndroidUseIntermediateDesignerFile>True</AndroidUseIntermediateDesignerFile>
<RootNamespace>Xamarin.Binding.Helpers.Sample.Android</RootNamespace>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageId>Xamarin.Binding.Helpers.Sample.Android</PackageId>
<Title>Sample Binding Helpers Project</Title>
<PackageVersion>1.0.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Transforms\*.xml" />
<TransformFile Include="Transforms\*.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Binding.Helpers" Version="0.1.0" PrivateAssets="all" />
<PackageReference Include="Naxam.SoLoader.Droid" Version="0.6.1.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
</ItemGroup>
<ItemGroup>
<AndroidStudioProject Include="C:\Users\jondi\Downloads\DuoNativeSamples\MyApplication" Module="mylibrary" />
<MavenNuGetMapping Include="com.google.code.gson:gson" MavenGroupId="com.google.code.gson" MavenArtifactId="gson" NuGetPackageId="GoogleGson" NuGetVersion="2.8.5" />
<MavenNuGetMapping Include="com.squareup.okhttp3:okhttp" MavenGroupId="com.squareup.okhttp3" MavenArtifactId="okhttp" NuGetPackageId="Square.OkHttp" NuGetVersion="3.12.3" />
</ItemGroup>
<Target
Name="GetProjectIntermediateOutputPath"
DependsOnTargets="_ResolveMonoAndroidSdks"
Outputs="@(XamarinAndroidBindngHelperSuggestionFile)">
<ItemGroup>
<XamarinAndroidBindngHelperSuggestionFile Include="$(IntermediateOutputPath)\xbh\_xbhpackagerefs.txt" />
</ItemGroup>
<Message Text="Project Intermediate Output Path: $(IntermediateOutputPath)" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

Просмотреть файл

@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

Просмотреть файл

@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

Просмотреть файл

@ -0,0 +1,294 @@
using NuGet.Frameworks;
using NuGet.Packaging;
using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Xml;
using Xamarin.Binding.Helpers.NugetResolvers;
namespace Xamarin.Binding.Helpers.Tests
{
public class UnitTest1
{
const string dependenciesTree =
@"
> Task :mylibrary:dependencies
------------------------------------------------------------
Project :mylibrary
------------------------------------------------------------
implementation - Implementation only dependencies for 'main' sources.
+--- com.mapbox.mapboxsdk:mapbox-android-sdk:9.5.0
| +--- com.mapbox.mapboxsdk:mapbox-android-telemetry:6.1.0
| | +--- com.squareup.okhttp3:okhttp:3.12.0 -> 3.12.3
| | | \--- com.squareup.okio:okio:1.15.0
| | +--- com.google.code.gson:gson:2.8.5 -> 2.8.6
| | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | +--- com.mapbox.mapboxsdk:mapbox-android-core:3.0.0
| | \--- androidx.legacy:legacy-support-core-utils:1.0.0
| | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | +--- androidx.core:core:1.0.0 -> 1.3.0
| | | +--- androidx.annotation:annotation:1.1.0
| | | +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.1.0
| | | | +--- androidx.lifecycle:lifecycle-common:2.1.0
| | | | | \--- androidx.annotation:annotation:1.1.0
| | | | +--- androidx.arch.core:core-common:2.1.0
| | | | | \--- androidx.annotation:annotation:1.1.0
| | | | \--- androidx.annotation:annotation:1.1.0
| | | +--- androidx.versionedparcelable:versionedparcelable:1.1.0
| | | | +--- androidx.annotation:annotation:1.1.0
| | | | \--- androidx.collection:collection:1.0.0 -> 1.1.0
| | | | \--- androidx.annotation:annotation:1.1.0
| | | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
| | +--- androidx.documentfile:documentfile:1.0.0
| | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | +--- androidx.loader:loader:1.0.0
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | | +--- androidx.core:core:1.0.0 -> 1.3.0 (*)
| | | +--- androidx.lifecycle:lifecycle-livedata:2.0.0
| | | | +--- androidx.arch.core:core-runtime:2.0.0
| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | | | | \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0
| | | | | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.1.0 (*)
| | | | | +--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
| | | | | \--- androidx.arch.core:core-runtime:2.0.0 (*)
| | | | \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
| | | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0
| | | \--- androidx.annotation:annotation:1.1.0
| | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
| | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | \--- androidx.print:print:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| +--- com.mapbox.mapboxsdk:mapbox-sdk-geojson:5.3.0
| | \--- com.google.code.gson:gson:2.8.6
| +--- com.mapbox.mapboxsdk:mapbox-android-gestures:0.7.0
| | +--- androidx.core:core:1.0.0 -> 1.3.0 (*)
| | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| +--- com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| +--- com.mapbox.mapboxsdk:mapbox-android-sdk-gl-core:5.0.0
| +--- com.mapbox.mapboxsdk:mapbox-sdk-turf:5.3.0
| | \--- com.mapbox.mapboxsdk:mapbox-sdk-geojson:5.3.0 (*)
| +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| +--- androidx.fragment:fragment:1.0.0 -> 1.1.0
| | +--- androidx.annotation:annotation:1.1.0
| | +--- androidx.core:core:1.1.0 -> 1.3.0 (*)
| | +--- androidx.collection:collection:1.1.0 (*)
| | +--- androidx.viewpager:viewpager:1.0.0
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | | +--- androidx.core:core:1.0.0 -> 1.3.0 (*)
| | | \--- androidx.customview:customview:1.0.0
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | | \--- androidx.core:core:1.0.0 -> 1.3.0 (*)
| | +--- androidx.loader:loader:1.0.0 (*)
| | +--- androidx.activity:activity:1.0.0
| | | +--- androidx.annotation:annotation:1.1.0
| | | +--- androidx.core:core:1.1.0 -> 1.3.0 (*)
| | | +--- androidx.lifecycle:lifecycle-runtime:2.1.0 (*)
| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.1.0 (*)
| | | \--- androidx.savedstate:savedstate:1.0.0
| | | +--- androidx.annotation:annotation:1.1.0
| | | +--- androidx.arch.core:core-common:2.0.1 -> 2.1.0 (*)
| | | \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.1.0 (*)
| | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 (*)
| \--- com.squareup.okhttp3:okhttp:3.12.3 (*)
+--- androidx.appcompat:appcompat:1.2.0
| +--- androidx.annotation:annotation:1.1.0
| +--- androidx.core:core:1.3.0 (*)
| +--- androidx.cursoradapter:cursoradapter:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| +--- androidx.fragment:fragment:1.1.0 (*)
| +--- androidx.appcompat:appcompat-resources:1.2.0
| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
| | +--- androidx.annotation:annotation:1.1.0
| | +--- androidx.core:core:1.0.1 -> 1.3.0 (*)
| | +--- androidx.vectordrawable:vectordrawable:1.1.0
| | | +--- androidx.annotation:annotation:1.1.0
| | | +--- androidx.core:core:1.1.0 -> 1.3.0 (*)
| | | \--- androidx.collection:collection:1.1.0 (*)
| | \--- androidx.vectordrawable:vectordrawable-animated:1.1.0
| | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*)
| | +--- androidx.interpolator:interpolator:1.0.0
| | | \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | \--- androidx.collection:collection:1.1.0 (*)
| +--- androidx.drawerlayout:drawerlayout:1.0.0
| | +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
| | +--- androidx.core:core:1.0.0 -> 1.3.0 (*)
| | \--- androidx.customview:customview:1.0.0 (*)
| \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
\--- com.google.android.material:material:1.2.1
+--- androidx.annotation:annotation:1.0.1 -> 1.1.0
+--- androidx.appcompat:appcompat:1.1.0 -> 1.2.0 (*)
+--- androidx.cardview:cardview:1.0.0
| \--- androidx.annotation:annotation:1.0.0 -> 1.1.0
+--- androidx.coordinatorlayout:coordinatorlayout:1.1.0
| +--- androidx.annotation:annotation:1.1.0
| +--- androidx.core:core:1.1.0 -> 1.3.0 (*)
| +--- androidx.customview:customview:1.0.0 (*)
| \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
+--- androidx.core:core:1.2.0 -> 1.3.0 (*)
+--- androidx.annotation:annotation-experimental:1.0.0
+--- androidx.fragment:fragment:1.0.0 -> 1.1.0 (*)
+--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.1.0 (*)
+--- androidx.recyclerview:recyclerview:1.0.0 -> 1.1.0
| +--- androidx.annotation:annotation:1.1.0
| +--- androidx.core:core:1.1.0 -> 1.3.0 (*)
| +--- androidx.customview:customview:1.0.0 (*)
| \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
+--- androidx.transition:transition:1.2.0
| +--- androidx.annotation:annotation:1.1.0
| +--- androidx.core:core:1.0.1 -> 1.3.0 (*)
| \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
+--- androidx.vectordrawable:vectordrawable:1.1.0 (*)
\--- androidx.viewpager2:viewpager2:1.0.0
+--- androidx.annotation:annotation:1.1.0
+--- androidx.fragment:fragment:1.1.0 (*)
+--- androidx.recyclerview:recyclerview:1.1.0 (*)
+--- androidx.core:core:1.1.0 -> 1.3.0 (*)
\--- androidx.collection:collection:1.1.0 (*)
(*) - dependencies omitted (listed previously)
A web-based, searchable dependency report is available by adding the --scan option.
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
";
[Fact]
public void Test1()
{
var deps = GradleUtil.ParseDependenciesTree(dependenciesTree.Split(Environment.NewLine));
var tree = GradleUtil.PrintTree(deps);
Console.WriteLine(tree);
Assert.NotEmpty(deps);
}
[Theory]
[InlineData("androidx.collection", "collection", "1.0.0", "1.1.0", "Xamarin.AndroidX.Collection", "1.1.0")]
[InlineData("androidx.vectordrawable", "vectordrawable-animated", "1.1.0", null, "Xamarin.AndroidX.VectorDrawable.Animated", "1.1.0")]
[InlineData("com.google.android.gms", "play-services-basement", "17.0.0", "17.1.0", "Xamarin.GooglePlayServices.Basement", "117.2.1")]
[InlineData("com.squareup.okhttp3", "okhttp", "3.12.3", null, "Square.OkHttp3", "3.12.3")]
[InlineData("com.squareup.okio", "okio", "1.15.0", null, "Square.OkIO", "1.15.0")]
public async Task Test2(string groupId, string artifactId, string reqVersion, string resolvedVersion, string packageId, string nugetVerison)
{
var r = await MavenNuGetSomelier.SuggestNuget(new LocalMavenArtifact
{
GroupId = groupId,
ArtifactId = artifactId,
RequestedVersion = reqVersion,
ResolvedVersion = resolvedVersion
},
new AndroidXMavenNugetResolver(),
new GooglePlayServicesMavenNugetResolver(),
new FirebaseMavenNugetResolver(),
new ExplicitMavenNugetResolver(
new ExplicitMavenNugetMapping("com.squareup.okhttp3", "okhttp", "3.12.3", "Square.OkHttp3", "3.12.3"),
new ExplicitMavenNugetMapping("com.squareup.okio", "okio", "1.15.0", "Square.OkIO", "1.15.0")));
Assert.Equal(packageId, r.PackageId, true, true);
var atLeastVersion = SemanticVersion.Parse(nugetVerison);
Assert.True(NuGetVersion.Parse(r.Version) >= atLeastVersion);
}
[Fact]
public async Task Test3()
{
var r = await GradleUtil.RunGradleProjectCommand(
@"C:\Users\jondi\Downloads\DuoNativeSamples\MyApplication",
"mylibrary:dependencies", "--configuration", "implementation");
Assert.NotNull(r);
}
[Fact]
public async Task Test4()
{
var androidProject = @"C:\Users\jondi\Downloads\DuoNativeSamples\MyApplication";
var depTreeText = await GradleUtil.RunGradleProjectCommand(androidProject, "mylibrary:dependencies", "--configuration", "implementation");
var resolvedDepText = await GradleUtil.RunGradleProjectCommand(androidProject, "mylibrary:fetchXamarinBindingInfo");
var deps = GradleUtil.ParseDependenciesTree(depTreeText);
var bindingDeps = await MavenNuGetSomelier.MapNuGets(deps,
new AndroidXMavenNugetResolver(),
new GooglePlayServicesMavenNugetResolver(),
new FirebaseMavenNugetResolver(),
new ExplicitMavenNugetResolver(
new ExplicitMavenNugetMapping("com.squareup.okhttp3", "okhttp", "3.12.3", "Square.OkHttp3", "3.12.3"),
new ExplicitMavenNugetMapping("com.squareup.okio", "okio", "1.15.0", "Square.OkIO", "1.15.0"),
new ExplicitMavenNugetMapping("com.google.code.gson", "gson", "2.8.5", "GoogleGson", "2.8.5"),
new ExplicitMavenNugetMapping("com.google.android.material", "material", "1.2.1", "Xamarin.Google.Android.Material", "1.2.1-rc1")));
var mavenArtifactLocalFiles = new Dictionary<string, string>();
const string xamGradleArtifactPrefix = "XAMARIN.GRADLE.ARTIFACT|";
var localArtifacts = new List<string>();
foreach (var line in resolvedDepText)
{
if (!line.StartsWith(xamGradleArtifactPrefix))
continue;
var parts = line.Substring(xamGradleArtifactPrefix.Length).Split('|', 2, StringSplitOptions.RemoveEmptyEntries);
if ((parts?.Length ?? 0) != 2)
continue;
if (parts[0] == "LOCAL")
localArtifacts.Add(parts[1]);
else
{
var bindingDep = bindingDeps.FirstOrDefault(bd =>
$"{bd.MavenDependency.GroupId}:{bd.MavenDependency.ArtifactId}".Equals(parts[0], StringComparison.OrdinalIgnoreCase));
if (bindingDep != null)
bindingDep.MavenDependency.File = parts[1];
}
}
var text = new StringBuilder();
text.AppendLine("<ItemGroup>");
foreach(var bd in bindingDeps.Where(b => b.NuGet != null))
{
text.AppendLine($" <PackageReference Include=\"{bd.NuGet.PackageId}\" Version=\"{bd.NuGet.Version}\" />");
}
text.AppendLine("</ItemGroup>");
text.AppendLine("<ItemGroup>");
foreach (var bd in bindingDeps.Where(b => b.NuGet == null))
{
var ext = System.IO.Path.GetExtension(bd.MavenDependency.File);
var isAar = ext?.Equals(".aar", StringComparison.OrdinalIgnoreCase) ?? false;
if (isAar)
text.AppendLine($" <AndroidAarLibrary Include=\"{bd.MavenDependency.File}\" />");
else
text.AppendLine($" <AndroidExternalJavaLibrary Include=\"{bd.MavenDependency.File}\" />");
}
text.AppendLine("</ItemGroup>");
Assert.NotNull(text.ToString());
Assert.NotEmpty(bindingDeps);
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NuGet.Protocol" Version="5.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Binding.Helpers\Xamarin.Binding.Helpers.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,45 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30711.63
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Binding.Helpers", "Xamarin.Binding.Helpers\Xamarin.Binding.Helpers.csproj", "{AA7C4773-1CB4-4226-A34D-CA5D9A5136F0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Binding.Helpers.Tests", "Xamarin.Binding.Helpers.Tests\Xamarin.Binding.Helpers.Tests.csproj", "{1A242704-924D-4072-93D0-FDAF4A9F0C26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleAndroidBinding", "Samples\SampleAndroidBinding\SampleAndroidBinding.csproj", "{A4D2280B-C68C-4835-A930-BE03D64809BC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleAndroidApp", "Samples\SampleAndroidApp\SampleAndroidApp.csproj", "{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AA7C4773-1CB4-4226-A34D-CA5D9A5136F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA7C4773-1CB4-4226-A34D-CA5D9A5136F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA7C4773-1CB4-4226-A34D-CA5D9A5136F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA7C4773-1CB4-4226-A34D-CA5D9A5136F0}.Release|Any CPU.Build.0 = Release|Any CPU
{1A242704-924D-4072-93D0-FDAF4A9F0C26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A242704-924D-4072-93D0-FDAF4A9F0C26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A242704-924D-4072-93D0-FDAF4A9F0C26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A242704-924D-4072-93D0-FDAF4A9F0C26}.Release|Any CPU.Build.0 = Release|Any CPU
{A4D2280B-C68C-4835-A930-BE03D64809BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4D2280B-C68C-4835-A930-BE03D64809BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4D2280B-C68C-4835-A930-BE03D64809BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4D2280B-C68C-4835-A930-BE03D64809BC}.Release|Any CPU.Build.0 = Release|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Release|Any CPU.Build.0 = Release|Any CPU
{F5FED1BB-5BCF-4323-AAE5-E0232E15E4E5}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C256DFCD-0CFF-411A-B930-DA1851859201}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Binding.Helpers.NugetResolvers;
namespace Xamarin.Binding.Helpers
{
public class AndroidStudioProjectInfo
{
public string ModuleArtifact { get; set; }
public List<MavenArtifactNuGetPairing> AllDependencies { get; set; }
public IEnumerable<NuGetSuggestion> NuGetDependencies =>
AllDependencies
.Where(nd => !string.IsNullOrEmpty(nd.NuGet?.Version) && !string.IsNullOrEmpty(nd.NuGet?.PackageId))
.Select(nd => nd.NuGet);
public IEnumerable<LocalMavenArtifact> MavenArtifacts =>
AllDependencies
.Where(ma => !string.IsNullOrEmpty(ma.MavenDependency?.File))
.Select(ma => ma.MavenDependency);
}
public class AndroidStudioProject
{
public AndroidStudioProject(string projectPath)
{
ProjectPath = projectPath;
}
public string ProjectPath { get; set; }
public async Task<AndroidStudioProjectInfo> GetDependencies(string module, IEnumerable<ExplicitMavenNugetMapping> mavenNugetMappings)
{
var depTreeText = await GradleUtil.RunGradleProjectCommand(ProjectPath, $"{module}:dependencies", "--configuration", "implementation");
var resolvedDepText = await GradleUtil.RunGradleProjectCommand(ProjectPath, $"{module}:fetchXamarinBindingInfo");
await GradleUtil.RunGradleProjectCommand(ProjectPath, $"{module}:bundleReleaseAar");
var deps = GradleUtil.ParseDependenciesTree(depTreeText);
var bindingDeps = await MavenNuGetSomelier.MapNuGets(deps,
new ExplicitMavenNugetResolver(mavenNugetMappings),
new AndroidXMavenNugetResolver(),
new GooglePlayServicesMavenNugetResolver(),
new FirebaseMavenNugetResolver(),
new KnownMavenNugetResolver());
var mavenArtifactLocalFiles = new Dictionary<string, string>();
const string xamGradleArtifactPrefix = "XAMARIN.GRADLE.ARTIFACT|";
var localArtifacts = new List<string>();
string libraryLocalAar = null;
foreach (var line in resolvedDepText)
{
if (!line.StartsWith(xamGradleArtifactPrefix))
continue;
var parts = line.Substring(xamGradleArtifactPrefix.Length).Split(new [] { '|' }, 2, StringSplitOptions.RemoveEmptyEntries);
if ((parts?.Length ?? 0) != 2)
continue;
if (parts[0] == "LOCAL")
localArtifacts.Add(parts[1]);
else if (parts[0] == "LIBRARY")
libraryLocalAar = parts[1];
else
{
var bindingDep = bindingDeps.FirstOrDefault(bd =>
$"{bd.MavenDependency.GroupId}:{bd.MavenDependency.ArtifactId}".Equals(parts[0], StringComparison.OrdinalIgnoreCase));
if (bindingDep != null)
bindingDep.MavenDependency.File = parts[1];
}
}
return new AndroidStudioProjectInfo { AllDependencies = bindingDeps.ToList(), ModuleArtifact = libraryLocalAar };
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
configurations.implementation.canBeResolved = true
task fetchXamarinBindingInfo() {
doLast {
println("<!--BEGIN XAMARIN.GRADLE.ARTIFACT-->")
def config = configurations.implementation
config.files.each { ff ->
if (!config.resolvedConfiguration.resolvedArtifacts.any { art -> art.file.absolutePath == ff.absolutePath })
{
println "XAMARIN.GRADLE.ARTIFACT|LOCAL|${ff.absolutePath}"
}
}
config.resolvedConfiguration.resolvedArtifacts.each { art ->
println "XAMARIN.GRADLE.ARTIFACT|${art.moduleVersion.id.group}:${art.moduleVersion.id.name}|${art.file.absolutePath}"
}
def psep = File.separatorChar
println "XAMARIN.GRADLE.ARTIFACT|LIBRARY|${project.projectDir}${psep}build${psep}outputs${psep}aar${psep}${project.name}-release.aar";
println("<!--END XAMARIN.GRADLE.ARTIFACT-->")
}
}

Просмотреть файл

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers
{
public class GradleUtil
{
static bool IsWindows => Environment.OSVersion.Platform == PlatformID.Win32NT;
public static async Task<IEnumerable<string>> RunGradleProjectCommand(string projectPath, params string[] args)
{
var parg = new ProcessArgumentBuilder();
foreach (var a in args)
parg.Append(a);
var r = await ProcessRunner.RunAsync(new FileInfo(Path.Combine(projectPath, "gradlew" + (IsWindows ? ".bat" : string.Empty))), parg, new DirectoryInfo(projectPath));
return r.StandardOutput;
}
const string rxpTreeDepth = @"(?<depth>\| |\+--- |\\--- | ){1,}(?<group>[^:]+):(?<artifact>[^:]+):(?<requestedVersion>[0-9\.]+)(\s?->\s?(?<resolvedVersion>[0-9.]+))?";
public static List<LocalMavenArtifact> ParseDependenciesTree(IEnumerable<string> lines)
{
var rxDepth = new Regex(rxpTreeDepth, RegexOptions.Singleline | RegexOptions.Compiled);
var rootDependencies = new List<LocalMavenArtifact>();
LocalMavenArtifact parentDependency = null;
foreach (var line in lines)
{
var match = rxDepth.Match(line);
if (!match.Success)
continue;
var depth = match.Groups?["depth"]?.Captures?.Count ?? 0;
var groupId = match.Groups?["group"]?.Value;
var artifactId = match.Groups?["artifact"]?.Value;
var reqVersion = match.Groups?["requestedVersion"]?.Value;
var resVersion = match.Groups?["resolvedVersion"]?.Value;
if (string.IsNullOrEmpty(groupId) || string.IsNullOrEmpty(artifactId) || string.IsNullOrEmpty(reqVersion))
continue;
var dep = new LocalMavenArtifact
{
GroupId = groupId,
ArtifactId = artifactId,
RequestedVersion = reqVersion,
ResolvedVersion = resVersion,
Depth = depth
};
if (dep.Depth == 1)
{
// No parent, this is a root level dependency
rootDependencies.Add(dep);
}
else if (dep.Depth > parentDependency.Depth)
{
// item is a dependency of hte parent
dep.Parent = parentDependency;
parentDependency.Dependencies.Add(dep);
}
else if (dep.Depth < parentDependency.Depth)
{
// This is up a level and a sibling of the parent
var climbUp = parentDependency.Depth - dep.Depth;
var actualParent = parentDependency.Parent;
for (int i = 0; i < climbUp; i++)
actualParent = actualParent.Parent;
dep.Parent = actualParent;
actualParent.Dependencies.Add(dep);
}
else if (dep.Depth == parentDependency.Depth)
{
// This is a sibling of the current parent
dep.Parent = parentDependency.Parent;
parentDependency.Parent.Dependencies.Add(dep);
}
parentDependency = dep;
}
return rootDependencies;
}
public static string PrintTree(List<LocalMavenArtifact> dependencies)
{
var text = new StringBuilder();
foreach (var d in dependencies)
PrintDependency(0, text, d);
return text.ToString();
}
static void PrintDependency(int depth, StringBuilder text, LocalMavenArtifact dependency)
{
text.Append(new string(' ', depth * 4));
text.Append($"{dependency.GroupId}:{dependency.ArtifactId}:{dependency.RequestedVersion}");
if (!string.IsNullOrEmpty(dependency.ResolvedVersion))
text.Append($" -> {dependency.ResolvedVersion}");
text.AppendLine();
if (dependency.Dependencies != null && dependency.Dependencies.Count > 0)
{
foreach (var d in dependency.Dependencies)
PrintDependency(depth + 1, text, d);
}
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Binding.Helpers.NugetResolvers;
namespace Xamarin.Binding.Helpers
{
public class MavenNuGetSomelier
{
public static async Task<NuGetSuggestion> SuggestNuget(LocalMavenArtifact dependency, params MavenNugetResolver[] resolvers)
{
foreach (var r in resolvers)
{
var n = await r.Resolve(dependency.GroupId, dependency.ArtifactId, dependency.RequestedVersion, dependency.ResolvedVersion);
if (n != null)
return n;
}
return null;
}
public static async Task<IEnumerable<MavenArtifactNuGetPairing>> MapNuGets(IEnumerable<LocalMavenArtifact> mavenDependencies, params MavenNugetResolver[] resolvers)
{
var results = new List<MavenArtifactNuGetPairing>();
foreach (var mavenDep in mavenDependencies)
await MapNuGets(mavenDep, results, resolvers);
return results;
}
static async Task MapNuGets(LocalMavenArtifact mavenDep, List<MavenArtifactNuGetPairing> bindingDeps, params MavenNugetResolver[] resolvers)
{
var nuget = await SuggestNuget(mavenDep, resolvers);
// Did we already add one?
if (!bindingDeps.Any(bd => bd.MavenDependency.GroupId.Equals(mavenDep.GroupId, StringComparison.OrdinalIgnoreCase) && bd.MavenDependency.ArtifactId.Equals(mavenDep.ArtifactId, StringComparison.OrdinalIgnoreCase)))
{
bindingDeps.Add(new MavenArtifactNuGetPairing
{
NuGet = await SuggestNuget(mavenDep, resolvers),
MavenDependency = mavenDep
});
if (nuget == null)
{
foreach (var child in mavenDep.Dependencies)
{
await MapNuGets(child, bindingDeps, resolvers);
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Xamarin.Binding.Helpers
{
public class LocalMavenArtifact
{
public string GroupId { get; set; }
public string ArtifactId { get; set; }
public string RequestedVersion { get; set; }
public string ResolvedVersion { get; set; }
public string File { get; set; }
bool? isAar;
public bool IsAar
{
get
{
if (!isAar.HasValue)
isAar = !string.IsNullOrEmpty(File) && Path.GetExtension(File).Equals(".aar", StringComparison.OrdinalIgnoreCase);
return isAar.Value;
}
}
bool? isJar;
public bool IsJar
{
get
{
if (!isJar.HasValue)
isJar = !string.IsNullOrEmpty(File) && Path.GetExtension(File).Equals(".jar", StringComparison.OrdinalIgnoreCase);
return isJar.Value;
}
}
public LocalMavenArtifact Parent { get; set; } = null;
public int Depth { get; set; } = 0;
public List<LocalMavenArtifact> Dependencies { get; set; } = new List<LocalMavenArtifact>();
public override string ToString()
=> $"{GroupId}:{ArtifactId} -> {RequestedVersion} ({ResolvedVersion}) -> {Depth}";
}
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace Xamarin.Binding.Helpers
{
public class MavenArtifactNuGetPairing
{
public NuGetSuggestion NuGet { get; set; }
public LocalMavenArtifact MavenDependency { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class AndroidXMavenNugetResolver : MavenNugetResolver
{
public override async Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion)
{
if (!mavenGroupId.StartsWith("androidx."))
{
// Material design is a different pattern
if (mavenGroupId.Equals("com.google.android.material", StringComparison.OrdinalIgnoreCase)
&& mavenArtifactId.Equals("material", StringComparison.OrdinalIgnoreCase))
{
var materialPkgId = "Xamarin.Google.Android.Material";
var materialNugetVersion = await NuGetUtil.FindBestVersion(materialPkgId, mavenRequestedVersion, mavenResolvedVersion, true);
if (materialNugetVersion != null)
return new NuGetSuggestion { PackageId = materialPkgId, Version = materialNugetVersion.ToNormalizedString() };
}
return null;
}
var firstDashIndex = mavenArtifactId.IndexOf('-');
var packageId = mavenGroupId + "." + mavenArtifactId.Replace("-", ".");
if (firstDashIndex > 0 && mavenGroupId.EndsWith(mavenArtifactId.Substring(0, firstDashIndex)))
packageId = mavenGroupId + "." + mavenArtifactId.Substring(firstDashIndex + 1).Replace("-", ".");
else if (mavenGroupId.EndsWith(mavenArtifactId, StringComparison.OrdinalIgnoreCase))
packageId = mavenGroupId;
packageId = "xamarin." + packageId;
var nugetVersion = await NuGetUtil.FindBestVersion(packageId, mavenRequestedVersion, mavenResolvedVersion);
if (nugetVersion != null)
return new NuGetSuggestion { PackageId = packageId, Version = nugetVersion.ToNormalizedString() };
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class ExplicitMavenNugetMapping
{
public ExplicitMavenNugetMapping(string mavenGroupId, string mavenArtifactId, string mavenVersion, string nugetPackageId, string nugetVersion)
{
MavenGroupId = mavenGroupId;
MavenArtifactId = mavenArtifactId;
MavenVersion = mavenVersion;
NuGetPackageId = nugetPackageId;
NuGetVersion = nugetVersion;
}
public string MavenGroupId { get; set; }
public string MavenArtifactId { get; set; }
public string MavenVersion { get; set; }
public string NuGetPackageId { get; set; }
public string NuGetVersion { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,78 @@
using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class ExplicitMavenNugetResolver : MavenNugetResolver
{
public List<ExplicitMavenNugetMapping> Mappings { get; set; } = new List<ExplicitMavenNugetMapping>();
public ExplicitMavenNugetResolver()
{
}
public ExplicitMavenNugetResolver(IEnumerable<ExplicitMavenNugetMapping> mappings)
{
Mappings.AddRange(mappings);
}
public ExplicitMavenNugetResolver(params ExplicitMavenNugetMapping[] mappings)
{
Mappings.AddRange(mappings);
}
public override async Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion)
{
foreach (var m in Mappings)
{
// Empty nuget package id means don't resolve
if (string.IsNullOrEmpty(m.NuGetPackageId))
return null;
// If no nuget version specified, try latest
if (string.IsNullOrEmpty(m.NuGetVersion))
{
m.NuGetVersion = (await NuGetUtil.GetVersions(m.NuGetPackageId))?.LastOrDefault()?.ToNormalizedString();
if (string.IsNullOrEmpty(m.NuGetVersion))
return null;
}
// Are group and artifact id's equal?
if (m.MavenGroupId.Equals(mavenGroupId, StringComparison.OrdinalIgnoreCase)
&& m.MavenArtifactId.Equals(mavenArtifactId, StringComparison.OrdinalIgnoreCase))
{
// make sure we can parse the maven version of the mapping
if (SemanticVersion.TryParse(m.MavenVersion, out var mapMavenSemVer))
{
// Check two possibilities:
// 1. The map version is >= resolved maven version
// 2. The map version is >= than the requested maven version
if ((SemanticVersion.TryParse(mavenResolvedVersion, out var mavenResSemver)
&& mapMavenSemVer >= mavenResSemver)
|| (SemanticVersion.TryParse(mavenRequestedVersion, out var mavenReqSemver)
&& mapMavenSemVer >= mavenReqSemver))
return new NuGetSuggestion
{
PackageId = m.NuGetPackageId,
Version = m.NuGetVersion
};
}
else
{
return new NuGetSuggestion
{
PackageId = m.NuGetPackageId,
Version = m.NuGetVersion
};
}
}
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class FirebaseMavenNugetResolver : MavenNugetResolver
{
public override async Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion)
{
if (!mavenGroupId.StartsWith("com.google.firebase"))
return null;
var packageId = "Xamarin.Firebase." + mavenArtifactId.Replace("firebase-", string.Empty).Replace("-", ".");
var nugetVersion = await NuGetUtil.FindBestVersion(packageId, "1" + mavenRequestedVersion, "1" + mavenResolvedVersion);
if (nugetVersion != null)
return new NuGetSuggestion { PackageId = packageId, Version = nugetVersion.ToNormalizedString() };
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class GooglePlayServicesMavenNugetResolver : MavenNugetResolver
{
public override async Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion)
{
if (!mavenGroupId.StartsWith("com.google.android.gms"))
return null;
var packageId = "Xamarin.GooglePlayServices." + mavenArtifactId.Replace("play-services-", string.Empty).Replace("-", ".");
var nugetVersion = await NuGetUtil.FindBestVersion(packageId, "1" + mavenRequestedVersion, "1" + mavenResolvedVersion);
if (nugetVersion != null)
return new NuGetSuggestion { PackageId = packageId, Version = nugetVersion.ToNormalizedString() };
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public class KnownMavenNugetResolver : MavenNugetResolver
{
static Dictionary<string, string> map = new Dictionary<string, string>
{
{ "com.squareup.okio.okio", "Square.OkIO" },
{ "com.squareup.okhttp3.okhttp", "Square.OkHttp3" },
{ "com.squareup.okhttp3.okhttp-ws", "Square.OkHttp3.WS" },
{ "com.squareup.okhttp3.okhttp-urlconnection", "Square.OkHttp.UrlConnection" },
{ "com.squareup.okhttp.okhttp", "Square.OkHttp" },
{ "com.squareup.okhttp.okhttp-ws", "Square.OkHttp.WS" },
{ "com.squareup.okhttp.okhttp-urlconnection", "Square.OkHttp.UrlConnection" },
{ "com.squareup.picasso.picasso", "Square.Picasso" },
{ "com.squareup.retrofit2.retrofit", "Square.Retrofit2" },
{ "com.squareup.retrofit2.converter-gson", "Square.Retrofit2.ConverterGson" },
{ "com.squareup.retrofit2.adapter-rxjava", "Square.Retrofit2.AdapterRxJava2" },
{ "com.squareup.moshi.moshi", "Square.Moshi" },
{ "com.squareup.seismic", "Square.Seismic" },
{ "com.jakewharton.picasso.picasso2-okhttp3-downloader", "JakeWharton.Picasso2OkHttp3Downloader" },
{ "com.jakewharton.threetenabp.threetenabp", "Xamarin.Android.JakeWharton.ThreeTenAbp" },
{ "com.jakewharton.timber.timber", "Xamarin.JakeWharton.Timber" },
{ "com.github.bumptech.glide.glide", "Xamarin.Android.Glide" },
{ "com.github.bumptech.glide.disklrucache", "Xamarin.Android.Glide.DiskLruCache" },
{ "com.github.bumptech.glide.gifdecoder", "Xamarin.Android.Glide.GifDecoder" },
{ "com.github.bumptech.glide.recyclerview-integration", "Xamarin.Android.Glide.RecyclerViewIntegration" },
{ "org.reactivestreams.reactive-streams", "Xamarin.Android.ReactiveStreams" },
{ "io.reactivex.rxjava2.rxandroid", "Xamarin.Android.ReactiveX.RxAndroid" },
{ "io.reactivex.rxjava2.rxjava", "Xamarin.Android.ReactiveX.RxJava" },
{ "com.android.volley.volley", "Xamarin.Android.Volley" },
{ "com.facebook.android.facebook-android-sdk", "Xamarin.Facebook.Android" },
{ "com.facebook.android.account-kit-sdk", "Xamarin.Facebook.AccountKit.Android" },
{ "com.facebook.android.facebook-applinks", "Xamarin.Facebook.AppLinks.Android" },
{ "com.facebook.android.audience-network-sdk", "Xamarin.Facebook.AudienceNetwork.Android" },
{ "com.facebook.android.facebook-common", "Xamarin.Facebook.Common.Android" },
{ "com.facebook.android.facebook-core", "Xamarin.Facebook.Core.Android" },
{ "com.facebook.android.facebook-livestreaming", "Xamarin.Facebook.LiveStreaming.Android" },
{ "com.facebook.android.facebook-login", "Xamarin.Facebook.Login.Android" },
{ "com.facebook.android.facebook-loginkit", "Xamarin.Facebook.LoginKit.Android" },
{ "com.facebook.android.facebook-marketing", "Xamarin.Facebook.Marketing.Android" },
{ "com.facebook.android.notifications", "Xamarin.Facebook.Notifications.Android" },
{ "com.facebook.android.facebook-places", "Xamarin.Facebook.Places.Android" },
{ "com.facebook.android.facebook-share", "Xamarin.Facebook.Share.Android" },
{ "com.google.android.datatransport.transport-api", "Xamarin.Google.Android.DataTransport.TransportApi" },
{ "com.google.android.datatransport.transport-backend-cct", "Xamarin.Google.Android.DataTransport.TransportBackendCct" },
{ "com.google.android.datatransport.transport-runtime", "Xamarin.Google.Android.DataTransport.TransportRuntime" },
{ "com.google.android.libraries.places", "Xamarin.Google.Android.Places" },
{ "com.google.android.play.core", "Xamarin.Google.Android.Play.Core" },
{ "com.google.auto.value.auto-value-annotations", "Xamarin.Google.AutoValue.Annotations" },
{ "com.google.dagger.dagger", "Xamarin.Google.Dagger" },
{ "com.google.guava.guava", "Xamarin.Google.Guava" },
{ "com.google.guava.failureaccess", "Xamarin.Google.Guava.FailureAccess" },
{ "com.google.guava.listenablefuture", "Xamarin.Google.Guava.ListenableFuture" },
{ "com.googlecode.libphonenumber.libphonenumber", "Xamarin.Google.LibPhoneNumber" },
{ "com.google.zxing.core", "Xamarin.Google.ZXing.Core" },
{ "io.grpc.grpc-android", "Xamarin.Grpc.Android" },
{ "io.grpc.grpc-context", "Xamarin.Grpc.Context" },
{ "io.grpc.grpc-core", "Xamarin.Grpc.Core" },
{ "io.grpc.grpc-okhttp", "Xamarin.Grpc.OkHttp" },
{ "io.grpc.grpc-protobuf-lite", "Xamarin.Grpc.Protobuf.Lite" },
{ "io.grpc.grpc-stub", "Xamarin.Grpc.Stub" },
{ "io.opencensus.opencensus-api", "Xamarin.Io.OpenCensus.OpenCensusApi" },
{ "io.opencensus.opencensus-contrib-grpc-metrics", "Xamarin.Io.OpenCensus.OpenCensusContribGrpcMetrics" },
{ "io.perfmark.perfmark-api", "Xamarin.Io.PerfMark.PerfMarkApi" },
{ "javax.inject.inject", "Xamarin.JavaX.Inject" },
{ "org.jetbrains.annotations", "Xamarin.Jetbrains.Annotations" },
{ "org.jetbrains.kotlin.kotlin-reflect", "Xamarin.Kotlin.Reflect" },
{ "org.jetbrains.kotlin.kotlin-stdlib", "Xamarin.Kotlin.StdLib" },
{ "org.jetbrains.kotlin.kotlin-stdlib-common", "Xamarin.Kotlin.StdLib.Common" },
{ "org.jetbrains.kotlin.kotlin-stdlib-jdk7", "Xamarin.Kotlin.StdLib.Jdk7" },
{ "org.jetbrains.kotlin.kotlin-stdlib-jdk8", "Xamarin.Kotlin.StdLib.Jdk8" },
{ "org.jetbrains.kotlin.kotlin-stdlib-jre7", "Xamarin.Kotlin.StdLib.Jre7" },
{ "org.jetbrains.kotlin.kotlin-stdlib-jre8", "Xamarin.Kotlin.StdLib.Jre8" },
{ "org.tensorflow.tensorflow-lite", "Xamarin.TensorFlow.Lite" },
{ "org.tensorflow.tensorflow-lite-gpu", "Xamarin.TensorFlow.Lite.Gpu" },
};
public override async Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion)
{
var id = $"{mavenGroupId}.{mavenArtifactId}";
var v = await NuGetUtil.FindBestVersion(id, mavenRequestedVersion, mavenResolvedVersion, true);
if (v != null)
return new NuGetSuggestion { Version = v.ToNormalizedString(), PackageId = id };
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers.NugetResolvers
{
public abstract class MavenNugetResolver
{
public abstract Task<NuGetSuggestion> Resolve(string mavenGroupId, string mavenArtifactId, string mavenRequestedVersion, string mavenResolvedVersion);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using NuGet.Frameworks;
namespace Xamarin.Binding.Helpers
{
public class NuGetSuggestion
{
public string PackageId { get; set; }
public string Version { get; set; }
public NuGetFramework Framework { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
using NuGet.Protocol;
using NuGet.Packaging;
using NuGet.Repositories;
using NuGet.Protocol.Core.Types;
using NuGet.Common;
using System.Threading.Tasks;
using System.Threading;
using NuGet.Versioning;
using System.Linq;
namespace Xamarin.Binding.Helpers
{
public class NuGetUtil
{
public static async Task<IEnumerable<NuGetVersion>> GetVersions(string packageId)
{
var cache = new SourceCacheContext();
var repository = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
FindPackageByIdResource resource = await repository.GetResourceAsync<FindPackageByIdResource>();
var versions = await resource.GetAllVersionsAsync(
packageId,
cache,
NullLogger.Instance,
CancellationToken.None);
return versions;
}
public static async Task<NuGetVersion> FindBestVersion(string packageId, string minVersion, string idealVersion = null, bool allowPrerelease = false)
{
var versions = await GetVersions(packageId);
if (versions != null)
{
SemanticVersion.TryParse(minVersion, out var semMinVer);
SemanticVersion.TryParse(idealVersion, out var semIdealVer);
//foreach (var version in versions)
//{
// if (version == semIdealVer)
// return version;
//}
foreach (var version in versions.Reverse())
{
if (!allowPrerelease && version.IsPrerelease)
continue;
if (semIdealVer != null && version >= semIdealVer)
return version;
if (semMinVer != null && version >= semMinVer)
return version;
}
return versions.FirstOrDefault();
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xamarin.Binding.Helpers
{
internal class ProcessArgumentBuilder
{
public List<string> args = new List<string>();
public ProcessArgumentBuilder Append(string arg)
{
args.Add(arg);
return this;
}
public ProcessArgumentBuilder AppendQuoted(string arg)
{
args.Add($"\"{arg}\"");
return this;
}
public override string ToString()
=> string.Join(" ", args);
}
internal class ProcessRunner
{
public static ProcessResult Run(FileInfo exe, ProcessArgumentBuilder builder, DirectoryInfo workingDirectory = null)
{
var p = new ProcessRunner(exe, builder, workingDirectory);
return p.WaitForExit();
}
public static Task<ProcessResult> RunAsync(FileInfo exe, ProcessArgumentBuilder builder, DirectoryInfo workingDirectory = null)
{
var p = new ProcessRunner(exe, builder, workingDirectory);
return p.WaitForExitAsync();
}
readonly List<string> standardOutput;
readonly List<string> standardError;
readonly Process process;
public ProcessRunner(FileInfo executable, ProcessArgumentBuilder builder, DirectoryInfo workingDirectory = null)
: this(executable, builder, System.Threading.CancellationToken.None, false, workingDirectory)
{ }
public ProcessRunner(FileInfo executable, ProcessArgumentBuilder builder, System.Threading.CancellationToken cancelToken, bool redirectStandardInput = false, DirectoryInfo workingDirectory = null)
{
standardOutput = new List<string>();
standardError = new List<string>();
//* Create your Process
process = new Process();
process.StartInfo.FileName = executable.FullName;
process.StartInfo.Arguments = builder.ToString();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
if (workingDirectory != null && workingDirectory.Exists)
process.StartInfo.WorkingDirectory = workingDirectory.FullName;
if (redirectStandardInput)
process.StartInfo.RedirectStandardInput = true;
process.OutputDataReceived += (s, e) =>
{
if (e.Data != null)
standardOutput.Add(e.Data);
};
process.ErrorDataReceived += (s, e) =>
{
if (e.Data != null)
standardError.Add(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (cancelToken != System.Threading.CancellationToken.None)
{
cancelToken.Register(() =>
{
try { process.Kill(); }
catch { }
});
}
}
public int ExitCode
=> process.HasExited ? process.ExitCode : -1;
public bool HasExited
=> process?.HasExited ?? false;
public void Kill()
=> process?.Kill();
public void StandardInputWrite(string input)
{
if (!process.StartInfo.RedirectStandardInput)
throw new InvalidOperationException();
process.StandardInput.Write(input);
}
public void StandardInputWriteLine(string input)
{
if (!process.StartInfo.RedirectStandardInput)
throw new InvalidOperationException();
process.StandardInput.WriteLine(input);
}
public ProcessResult WaitForExit()
{
process.WaitForExit();
if (standardError?.Any(l => l?.Contains("error: more than one device/emulator") ?? false) ?? false)
throw new Exception("More than one Device/Emulator detected, you must specify which Serial to target.");
return new ProcessResult(standardOutput, standardError, process.ExitCode);
}
public Task<ProcessResult> WaitForExitAsync()
{
var tcs = new TaskCompletionSource<ProcessResult>();
Task.Run(() =>
{
var r = WaitForExit();
tcs.TrySetResult(r);
});
return tcs.Task;
}
}
public class ProcessResult
{
public readonly List<string> StandardOutput;
public readonly List<string> StandardError;
public readonly int ExitCode;
public bool Success
=> ExitCode == 0;
internal ProcessResult(List<string> stdOut, List<string> stdErr, int exitCode)
{
StandardOutput = stdOut;
StandardError = stdErr;
ExitCode = exitCode;
}
}
}

Просмотреть файл

@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using NuGet.Frameworks;
using Xamarin.Build;
namespace Xamarin.Binding.Helpers.Tasks
{
public class XbhAddDependenciesToNupkgTask : AsyncTask
{
public ITaskItem[] NuGetPackOutput { get; set; }
public ITaskItem[] TargetFrameworks { get; set; }
[Required]
public string IntermediateOutputPath { get; set; }
public override bool Execute()
{
Task.Run(async () =>
{
try
{
await DoExecute();
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
finally
{
Complete();
}
});
return base.Execute();
}
async Task DoExecute()
{
var fullIntermediateOutputPath = new System.IO.DirectoryInfo(IntermediateOutputPath);
if (!fullIntermediateOutputPath.Exists)
fullIntermediateOutputPath.Create();
// Find package refs for any tfm's
var packageRefFiles = new Dictionary<string, NuGetFramework>();
foreach (var tfm in TargetFrameworks)
{
var nugetFramework = NuGetFramework.Parse(tfm.ItemSpec);
var pkgRefFile = Path.Combine(fullIntermediateOutputPath.FullName, nugetFramework?.GetShortFolderName() ?? ".", "xbh", "_xbhpackagerefs.txt");
if (File.Exists(pkgRefFile))
packageRefFiles.Add(pkgRefFile, nugetFramework);
LogMessage($"Found: {tfm.ItemSpec} -> {pkgRefFile}");
}
var pkgRefs = new List<NuGetSuggestion>();
foreach (var pkgRefFile in packageRefFiles)
{
var lines = File.ReadAllLines(pkgRefFile.Key);
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line))
continue;
var parts = line?.Split(new[] { '|' }, 2);
if ((parts?.Length ?? 0) == 2)
pkgRefs.Add(new NuGetSuggestion
{
PackageId = parts[0],
Version = parts[1],
Framework = pkgRefFile.Value
});
}
}
foreach (var ns in pkgRefs)
LogMessage($"NuGet Suggestion: {ns.PackageId} ({ns.Version}) for {ns.Framework}");
foreach (var item in NuGetPackOutput)
{
var file = new FileInfo(item.ItemSpec);
if (file.Exists && file.Extension.Equals(".nupkg", StringComparison.OrdinalIgnoreCase))
{
LogMessage($"Adding nuget deps to: {file.FullName}");
AddPackageReferencesToNupkg(file.FullName, pkgRefs);
}
}
}
void AddPackageReferencesToNupkg(string nupkg, IEnumerable<NuGetSuggestion> pkgRefs)
{
var pkgRefsByTfm = pkgRefs.GroupBy(p => p.Framework);
using (var zipa = new ZipArchive(new FileStream(nupkg, FileMode.Open), ZipArchiveMode.Update))
{
string nuspecEntryName = zipa.Entries.FirstOrDefault(e => Path.GetExtension(e.Name).Equals(".nuspec", StringComparison.OrdinalIgnoreCase))?.FullName;
var nuspecEntry = zipa.GetEntry(nuspecEntryName);
var updatedNuspec = new MemoryStream();
XNamespace xmlns = null;
using (var entryStream = nuspecEntry.Open())
{
var xdoc = XDocument.Load(entryStream);
xmlns = xdoc.Root.GetDefaultNamespace();
var depsElem = xdoc.Descendants().FirstOrDefault(d => d.Name.LocalName == "dependencies");
// It's possible dependencies element doesn't exist yet, so we may need to add it
if (depsElem == null)
{
LogMessage("dependencies element missing, creating...");
var metadataElem = xdoc.Descendants().FirstOrDefault(d => d.Name?.LocalName == "metadata");
depsElem = new XElement(XName.Get("dependencies", xmlns.NamespaceName));
metadataElem.Add(depsElem);
}
// Find existing dependency->group elements
var depGroupElems = depsElem.Descendants().Where(d2 => d2.Name.LocalName == "group");
// Parse out frameworks and keep the element so we can match existing ones later
var existingDepGroups = new List<(NuGetFramework, XElement)>();
foreach (var depGroupElem in depGroupElems)
{
var tfm = depGroupElem?.Attributes().FirstOrDefault(a => a?.Name?.LocalName == "targetFramework")?.Value;
if (!string.IsNullOrEmpty(tfm))
existingDepGroups.Add((NuGetFramework.Parse(tfm), depGroupElem));
}
// Go through each tfm we have package refs for
// try and find the existing element to add to, otherwise create a new one
foreach (var tfmGrp in pkgRefsByTfm)
{
var depGrp = existingDepGroups.FirstOrDefault(d => d.Item1.Equals(tfmGrp.Key));
// Add the dependency group for this TFM if it doesn't exist
if (depGrp == default || depGrp.Item1 == null || depGrp.Item2 == null)
{
LogMessage($"Dependency Group Missing, creating: {tfmGrp.Key.Framework}...");
var newDepGrpElem = new XElement(XName.Get("group", xmlns.NamespaceName),
new XAttribute("targetFramework", tfmGrp.Key.Framework));
depsElem.Add(newDepGrpElem);
depGrp = (tfmGrp.Key, newDepGrpElem);
}
// Add all the dependencies to the group
foreach (var pkgRef in tfmGrp)
{
depGrp.Item2.Add(new XElement(XName.Get("dependency", xmlns.NamespaceName),
new XAttribute("id", pkgRef.PackageId),
new XAttribute("version", pkgRef.Version),
new XAttribute("include", "All")));
}
}
using (var xmlWriter = XmlWriter.Create(updatedNuspec))
{
xdoc.WriteTo(xmlWriter);
}
}
// Remove old entry, add new one
nuspecEntry.Delete();
var newEntry = zipa.CreateEntry(nuspecEntryName);
using (var newStream = newEntry.Open())
{
updatedNuspec.Position = 0;
updatedNuspec.CopyTo(newStream);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,215 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Framework;
using NuGet.Packaging;
using Xamarin.Binding.Helpers.NugetResolvers;
using Xamarin.Build;
using MSBuildTaskItem = Microsoft.Build.Utilities.TaskItem;
namespace Xamarin.Binding.Helpers.Tasks
{
public class XbhAndroidStudioProjectTask : AsyncTask
{
[Required]
public string IntermediateOutputPath { get; set; }
public ITaskItem[] Projects { get; set; }
public ITaskItem[] MavenNugetPairings { get; set; }
[Output]
public ITaskItem[] ResolvedArtifacts { get; set; }
[Output]
public ITaskItem[] NugetReferences { get; set; }
[Output]
public ITaskItem[] LocalAarArtifacts { get; set; }
[Output]
public ITaskItem[] LocalJarArtifacts { get; set; }
[Output]
public ITaskItem[] BindableLocalAars { get;set; }
[Required]
public string TargetFrameworkPath { get; set; }
public override bool Execute()
{
Task.Run(async () =>
{
try
{
await DoExecute();
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
finally
{
Complete();
}
});
return base.Execute();
}
async Task DoExecute()
{
var mappings = new List<ExplicitMavenNugetMapping>();
if (MavenNugetPairings != null)
{
foreach (var m in MavenNugetPairings)
{
var gid = m.GetMetadata("MavenGroupId");
var aid = m.GetMetadata("MavenArtifactId");
var mv = m.GetMetadata("MavenVersion");
var nid = m.GetMetadata("NuGetPackageId");
var nv = m.GetMetadata("NuGetVersion");
if (string.IsNullOrEmpty(gid))
throw new ArgumentNullException("MavenNuGetMapping item is missing the 'MavenGroupId' attribute.");
if (string.IsNullOrEmpty(aid))
throw new ArgumentNullException("MavenNuGetMapping item is missing the 'MavenArtifactId' attribute.");
if (string.IsNullOrEmpty(nid))
throw new ArgumentNullException("MavenNuGetMapping item is missing the 'NuGetPackageId' attribute.");
if (string.IsNullOrEmpty(nv))
throw new ArgumentNullException("MavenNuGetMapping item is missing the 'NuGetVersion' attribute.");
mappings.Add(new ExplicitMavenNugetMapping(gid, aid, mv, nid, nv));
}
}
var bindableAars = new List<ITaskItem>();
var allDeps = new List<MavenArtifactNuGetPairing>();
foreach (var p in Projects)
{
var projectPath = p.ItemSpec;
var module = p.GetMetadata("Module");
if (string.IsNullOrEmpty(module))
throw new ArgumentNullException("AndroidStudioProject item is missing the 'Module' attribute.");
var ap = new AndroidStudioProject(projectPath);
var projInfo = await ap.GetDependencies(module, mappings);
allDeps.AddRange(projInfo.AllDependencies);
if (!string.IsNullOrEmpty(projInfo.ModuleArtifact))
{
bindableAars.Add(new MSBuildTaskItem(projInfo.ModuleArtifact, new Dictionary<string, string> {
{
"MavenIdentityHash",
Convert.ToBase64String(System.Security.Cryptography.SHA256.Create().ComputeHash(
Encoding.UTF8.GetBytes(projInfo.ModuleArtifact))).Substring(0, 8)
}
}));
}
}
BindableLocalAars = bindableAars.ToArray();
var resolvedArtifacts = new List<MSBuildTaskItem>();
var nugetReferences = new List<MSBuildTaskItem>();
var localAarArtifacts = new List<MSBuildTaskItem>();
var localJarArtifacts = new List<MSBuildTaskItem>();
var targetsArtifacts = new List<string>();
foreach (var d in allDeps)
{
var attr = new Dictionary<string, string>();
string itemSpec = $"{d.MavenDependency.GroupId}:{d.MavenDependency.ArtifactId}:{d.MavenDependency.ResolvedVersion}";
var artifactType = string.Empty;
if (!string.IsNullOrEmpty(d.MavenDependency.GroupId))
attr.Add("MavenGroupId", d.MavenDependency.GroupId);
if (!string.IsNullOrEmpty(d.MavenDependency.ArtifactId))
attr.Add("MavenArtifactId", d.MavenDependency.ArtifactId);
if (!string.IsNullOrEmpty(d.MavenDependency.ArtifactId) && !string.IsNullOrEmpty(d.MavenDependency.GroupId))
attr.Add("MavenIdentity", $"{d.MavenDependency.GroupId}.{d.MavenDependency.ArtifactId}");
if (!string.IsNullOrEmpty(d.MavenDependency.ResolvedVersion))
attr.Add("MavenVersion", d.MavenDependency.ResolvedVersion);
if (!string.IsNullOrEmpty(d.MavenDependency.RequestedVersion))
attr.Add("MavenRequestedVersion", d.MavenDependency.RequestedVersion);
if (!string.IsNullOrEmpty(d.MavenDependency.File))
{
attr.Add("Path", d.MavenDependency.File);
if (d.MavenDependency.IsAar || d.MavenDependency.IsJar)
attr.Add("ArtifactType", d.MavenDependency.IsAar ? "aar" : "jar");
}
if (d.NuGet != null)
{
if (!string.IsNullOrEmpty(d.NuGet.PackageId))
attr.Add("NuGetPackageId", d.NuGet.PackageId);
if (!string.IsNullOrEmpty(d.NuGet.Version))
attr.Add("NuGetVersion", d.NuGet.Version);
nugetReferences.Add(new MSBuildTaskItem(itemSpec, attr));
}
else
{
if (d.MavenDependency.IsAar)
{
localAarArtifacts.Add(new MSBuildTaskItem(itemSpec, attr));
if (File.Exists(d.MavenDependency.File))
targetsArtifacts.Add(Path.GetFileName(d.MavenDependency.File));
}
else if (d.MavenDependency.IsJar)
localJarArtifacts.Add(new MSBuildTaskItem(itemSpec, attr));
}
resolvedArtifacts.Add(new MSBuildTaskItem(itemSpec, attr));
}
ResolvedArtifacts = resolvedArtifacts.ToArray();
NugetReferences = nugetReferences.ToArray();
LocalAarArtifacts = localAarArtifacts.ToArray();
LocalJarArtifacts = localJarArtifacts.ToArray();
var fullIntermediateOutputPath = new DirectoryInfo(IntermediateOutputPath);
if (!fullIntermediateOutputPath.Exists)
fullIntermediateOutputPath.Create();
using (var w = new StreamWriter(Path.Combine(fullIntermediateOutputPath.FullName, "package.targets"), false))
{
w.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
w.WriteLine(@"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">");
w.WriteLine(" <ItemGroup>");
foreach (var a in targetsArtifacts)
w.WriteLine(@" <AndroidAarLibrary Include=""$(MSBuildThisFileDirectory)..\..\build\" + TargetFrameworkPath + "\\" + a + "\" />");
w.WriteLine(" </ItemGroup>");
w.WriteLine(@"</Project>");
}
using (var w = new StreamWriter(Path.Combine(fullIntermediateOutputPath.FullName, "_xbhpackagerefs.txt")))
{
foreach (var d in allDeps)
{
if (d.NuGet != null && !string.IsNullOrEmpty(d.NuGet.PackageId) && !string.IsNullOrEmpty(d.NuGet.Version))
w.WriteLine($"{d.NuGet.PackageId}|{d.NuGet.Version}");
}
}
using (var w = new StreamWriter(Path.Combine(fullIntermediateOutputPath.FullName, "_xbhartifacts.txt"), false))
{
foreach (var d in allDeps)
{
if (d.NuGet == null && d.MavenDependency != null && d.MavenDependency.IsAar)
w.WriteLine($"{d.MavenDependency.File}");
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,93 @@
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Build;
using MSBuildTaskItem = Microsoft.Build.Utilities.TaskItem;
namespace Xamarin.Binding.Helpers.Tasks
{
public class XbhFetchBindingSuggestionsTask : AsyncTask
{
public ITaskItem[] Projects { get; set; }
[Output]
public ITaskItem[] AndroidAars { get; set; }
public override bool Execute()
{
Task.Run(async () =>
{
try
{
await DoExecute();
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
finally
{
Complete();
}
});
return base.Execute();
}
async Task DoExecute()
{
var aars = new List<MSBuildTaskItem>();
foreach (var proj in Projects)
{
var intermediateOutputPath = proj.GetMetadata("IntermediateOutputPath");
var packageRefs = Path.Combine(intermediateOutputPath, "xbh", "_xbhpackagerefs.txt");
var pkgRefs = new List<NuGetSuggestion>();
// PackageId|Version
if (File.Exists(packageRefs))
{
var lines = File.ReadAllLines(packageRefs) ?? new string[0];
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line))
continue;
var parts = line?.Split(new[] { '|' }, 2);
if ((parts?.Length ?? 0) == 2)
pkgRefs.Add(new NuGetSuggestion
{
PackageId = parts[0],
Version = parts[1]
});
}
}
var artifacts = Path.Combine(intermediateOutputPath, "_xbhartifacts.txt");
if (File.Exists(artifacts))
{
var lines = File.ReadAllLines(artifacts) ?? new string[0];
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line))
continue;
aars.Add(new MSBuildTaskItem(line));
}
}
}
AndroidAars = aars.ToArray();
}
}
}

Просмотреть файл

@ -0,0 +1,87 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Xamarin.Binding.Helpers</PackageId>
<Title>Xamarin Binding Helpers</Title>
<Version>0.1</Version>
<Authors>Redth</Authors>
<Owners>Redth</Owners>
<summary>Add helpful functionality to your Xamarin.iOS and Xamarin.Android binding projects.</summary>
<PackageDescription>
Add helpful functionality to your Xamarin.iOS and Xamarin.Android binding projects.
</PackageDescription>
<Copyright>Copyright © Redth</Copyright>
<PackageProjectUrl>https://github.com/redth/Resizetizer</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/redth/ResizetizerNT</RepositoryUrl>
<PackageOutputPath>..\output</PackageOutputPath>
<IncludeBuildOutput>False</IncludeBuildOutput>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NuGet.Protocol" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="NuGet.Packaging" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="NuGet.Configuration" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="NuGet.Versioning" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="NuGet.Common" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="NuGet.Frameworks" Version="5.8.0" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" PrivateAssets="all" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="16.6.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.6.0" PrivateAssets="all" />
<PackageReference Include="Xamarin.Build.AsyncTask" Version="0.3.4" PrivateAssets="all" GeneratePathProperty="true" />
</ItemGroup>
<ItemGroup>
<None Include="$(TargetPath)" Pack="True" PackagePath="build\" />
<None Include="$(TargetPath)" Pack="True" PackagePath="buildMultitargeting\" />
<Content Include="Xamarin.Binding.Helpers.targets" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Xamarin.Binding.Helpers.multitargeting.targets" Pack="True" PackagePath="buildMultitargeting\Xamarin.Binding.Helpers.targets">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="$(PkgNuGet_Protocol)\lib\netstandard2.0\NuGet.Protocol.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNuGet_Packaging)\lib\netstandard2.0\NuGet.Packaging.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNuGet_Configuration)\lib\netstandard2.0\NuGet.Configuration.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNuGet_Versioning)\lib\netstandard2.0\NuGet.Versioning.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNuGet_Common)\lib\netstandard2.0\NuGet.Common.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNuGet_Frameworks)\lib\netstandard2.0\NuGet.Frameworks.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgXamarin_Build_AsyncTask)\lib\netstandard2.0\Xamarin.Build.AsyncTask.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" Visible="False" Pack="True" PackagePath="build\">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="$(TargetPath)" Pack="True" PackagePath="buildTransitive\" />
<Content Include="Xamarin.Binding.Helpers.targets" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Protocol)\lib\netstandard2.0\NuGet.Protocol.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Packaging)\lib\netstandard2.0\NuGet.Packaging.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Configuration)\lib\netstandard2.0\NuGet.Configuration.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Versioning)\lib\netstandard2.0\NuGet.Versioning.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Common)\lib\netstandard2.0\NuGet.Common.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNuGet_Frameworks)\lib\netstandard2.0\NuGet.Frameworks.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgXamarin_Build_AsyncTask)\lib\netstandard2.0\Xamarin.Build.AsyncTask.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
<None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" Visible="False" Pack="True" PackagePath="buildTransitive\" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask
AssemblyFile="Xamarin.Binding.Helpers.dll"
TaskName="Xamarin.Binding.Helpers.Tasks.XbhAddDependenciesToNupkgTask" />
<Target Name="_XbhAddDependenciesToNupkgTask"
AfterTargets="GenerateNuspec">
<XbhAddDependenciesToNupkgTask
IntermediateOutputPath="$(IntermediateOutputPath)"
NuGetPackOutput="@(NuGetPackOutput)"
TargetFrameworks="@(_TargetFrameworks)"
/>
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AvailableItemName Include="AndroidStudioProject" />
<AvailableItemName Include="MavenNuGetMapping" />
</ItemGroup>
<UsingTask
AssemblyFile="Xamarin.Binding.Helpers.dll"
TaskName="Xamarin.Binding.Helpers.Tasks.XbhAndroidStudioProjectTask" />
<UsingTask
AssemblyFile="Xamarin.Binding.Helpers.dll"
TaskName="Xamarin.Binding.Helpers.Tasks.XbhFetchBindingSuggestionsTask" />
<PropertyGroup>
<CleanDependsOn>
$(CleanDependsOn);
_CleanXbh;
</CleanDependsOn>
<_XbhIntermediateOutputPath>$(IntermediateOutputPath)xbh\</_XbhIntermediateOutputPath>
</PropertyGroup>
<PropertyGroup>
<!-- Hack to include our tasks -->
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);_XbhBuildAndroidStudioProjects</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<Target Name="_XbhBuildAndroidStudioProjects"
BeforeTargets="_ResolveLibraryProjectImports;Pack"
Condition="'@(AndroidStudioProject)' != ''">
<GetNuGetShortFolderName
TargetFrameworkMoniker="$(TargetFrameworkMoniker)"
TargetPlatformMoniker="$(TargetPlatformMoniker)">
<Output TaskParameter="NuGetShortFolderName" PropertyName="_NuGetShortFolderName" />
</GetNuGetShortFolderName>
<!--
Executes several gradle tasks for the given project and module:
1. bundleReleaseAar
2. dependencies configuration implementation
3. fetchXamarinBindingInfo
This parses out the dependency tree, finds the built aar, and tries to
match up which nugets we can use, or pulls the .aar/.jar locally if we can't find one
-->
<XbhAndroidStudioProjectTask
Projects="@(AndroidStudioProject)"
IntermediateOutputPath="$(_XbhIntermediateOutputPath)"
MavenNugetPairings="@(MavenNugetMapping)"
TargetFrameworkPath="$(_NuGetShortFolderName)">
<Output TaskParameter="ResolvedArtifacts" ItemName="_XbhAndroidStudioProjectResolvedArtifacts" />
<Output TaskParameter="NugetReferences" ItemName="_XbhAndroidStudioProjectNugetReferences" />
<Output TaskParameter="LocalAarArtifacts" ItemName="_XbhAndroidStudioProjectLocalAarArtifacts" />
<Output TaskParameter="LocalJarArtifacts" ItemName="_XbhAndroidStudioProjectLocalJarArtifacts" />
<Output TaskParameter="BindableLocalAars" ItemName="_XbhAndroidStudioProjectBindableLocalAars" />
</XbhAndroidStudioProjectTask>
<!-- Copy all the .jar artifacts to an obj intermediate dir -->
<Copy
SourceFiles="@(_XbhAndroidStudioProjectLocalJarArtifacts->'%(Path)')"
DestinationFolder="$(_XbhIntermediateOutputPath)\artifacts\"
SkipUnchangedFiles="True" />
<!-- Copy all the .aar artifacts to an obj intermediate dir -->
<Copy
SourceFiles="@(_XbhAndroidStudioProjectLocalAarArtifacts->'%(Path)')"
DestinationFolder="$(_XbhIntermediateOutputPath)\artifacts\"
SkipUnchangedFiles="True" />
<!-- Copy all the bindable .aar artifacts to an obj intermediate dir -->
<Copy
SourceFiles="@(_XbhAndroidStudioProjectBindableLocalAars->'%(Identity)')"
DestinationFolder="$(_XbhIntermediateOutputPath)\artifacts\"
SkipUnchangedFiles="True" />
<!-- Unzip all of the .aar's -->
<Microsoft.Build.Tasks.Unzip
Condition="'@_XbhAndroidStudioProjectLocalAarArtifacts' != ''"
SourceFiles="%(_XbhAndroidStudioProjectLocalAarArtifacts.Path)"
DestinationFolder="$(_XbhIntermediateOutputPath)\artifacts\%(_XbhAndroidStudioProjectLocalAarArtifacts.MavenIdentity)"
SkipUnchangedFiles="True" />
<!-- Unzip all of the bindable .aar's -->
<Microsoft.Build.Tasks.Unzip
Condition="'@_XbhAndroidStudioProjectBindableLocalAars' != ''"
SourceFiles="%(_XbhAndroidStudioProjectBindableLocalAars.Identity)"
DestinationFolder="$(_XbhIntermediateOutputPath)\artifacts\%(_XbhAndroidStudioProjectBindableLocalAars.MavenIdentityHash)"
SkipUnchangedFiles="True" />
<ItemGroup>
<!-- Add the .jar's for the bindable .aar's to actually have bindings generated for -->
<InputJar Include="$(_XbhIntermediateOutputPath)\artifacts\%(_XbhAndroidStudioProjectBindableLocalAars.MavenIdentityHash)\*.jar" />
<!-- Add the .jar's from all the other .aar's to have their .jar's available for the binding generator -->
<ReferenceJar Include="$(_XbhIntermediateOutputPath)\artifacts\%(_XbhAndroidStudioProjectLocalAarArtifacts.MavenIdentity)\*.jar" />
<!-- We can simply embed the .jar's that are also to be referenced by the .aar we are binding -->
<!-- Eventually we should package these just like .aar's in the nuget and use ReferenceJar instead here -->
<EmbeddedReferenceJar Include="$(_XbhIntermediateOutputPath)\artifacts\*.jar" />
<!-- Add all the artifacts to the nuget package generated -->
<TfmSpecificPackageFile Include="$(_XbhIntermediateOutputPath)\artifacts\*.aar" Pack="True" PackagePath="build\$(_NuGetShortFolderName)" />
<!-- Add the .targets file we generate with AndroidAarLibrary items into the nupkg -->
<TfmSpecificPackageFile Include="$(_XbhIntermediateOutputPath)\package.targets" Pack="True" PackagePath="build\$(_NuGetShortFolderName)\$(PackageId).targets" />
<TfmSpecificPackageFile Include="$(_XbhIntermediateOutputPath)\package.targets" Pack="True" PackagePath="buildTransitive\$(_NuGetShortFolderName)\$(PackageId).targets" />
</ItemGroup>
</Target>
<Target Name="_XbhFetchXamarinAndroidBindingHelperSuggestions"
Condition="'@(ProjectReference)' != ''"
BeforeTargets="_ResolveLibraryProjectImports">
<MSBuild
Targets="_XbhGetProjectIntermediateOutputPath"
Projects="@(ProjectReference)"
SkipNonexistentProjects="true"
SkipNonexistentTargets="true">
<Output
TaskParameter="TargetOutputs"
ItemName="_XbhPackageRefsFile" />
</MSBuild>
<XbhFetchBindingSuggestionsTask
Projects="@(ProjectReference)">
<Output TaskParameter="AndroidAars" ItemName="AndroidAarLibrary" />
</XbhFetchBindingSuggestionsTask>
</Target>
<Target Name="_XbhGetProjectIntermediateOutputPath" Outputs="@(_XbhPackageRefsFile)">
<ItemGroup>
<_XbhPackageRefsFile Include="$(IntermediateOutputPath)\xbh\_xbhpackagerefs.txt" />
</ItemGroup>
<Message Text="Project Intermediate Output Path: $(IntermediateOutputPath)" />
</Target>
<Target Name="_CleanXbh">
<PropertyGroup>
<_XbhIntermediateOutputPath>$(IntermediateOutputPath)xbh\</_XbhIntermediateOutputPath>
</PropertyGroup>
<RemoveDir Directories="$(_XbhIntermediateOutputPath)" Condition="Exists ('$(_XbhIntermediateOutputPath)' )" />
</Target>
</Project>

15
test-helper.ps1 Normal file
Просмотреть файл

@ -0,0 +1,15 @@
New-Item -ItemType Directory -Path .\logs\ -Force
New-Item -ItemType Directory -Path .\output\ -Force
& msbuild /t:Restore .\Xamarin.Binding.Helpers\Xamarin.Binding.Helpers.csproj
& msbuild /t:Rebuild .\Xamarin.Binding.Helpers\Xamarin.Binding.Helpers.csproj /bl:logs\xbh.binlog
Remove-Item .\Samples\packages\xamarin.binding.helpers -Force -Recurse
# Run restore/rebuilds
& msbuild /t:Restore .\Samples\SampleAndroidBinding\SampleAndroidBinding.csproj
& msbuild /t:Rebuild .\Samples\SampleAndroidBinding\SampleAndroidBinding.csproj /bl:logs\android.binlog
& msbuild /t:Pack .\Samples\SampleAndroidBinding\SampleAndroidBinding.csproj /bl:logs\android-pack.binlog
& msbuild /r /t:Rebuild .\Samples\SampleAndroidApp\SampleAndroidApp.csproj /bl:logs\android-app.binlog