This will allow AndroidAppBuilder to be packaged without having unnecessary dependencies.
AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)" />
<Target Condition="'$(TargetOS)' == 'Android'" Name="BundleTestAndroidApp">
+ <Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
+
+ <!-- TEMP: consume OpenSSL binaries from external sources via env. variables.-->
<PropertyGroup>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm64'">arm64-v8a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm'">armeabi-v7a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x86'">x86</AndroidAbi>
</PropertyGroup>
- <Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
-
- <!-- TEMP: consume OpenSSL binaries from external sources via env. variables -->
<Copy Condition="'$(ANDROID_OPENSSL_AAR)' != ''"
SourceFiles="$(ANDROID_OPENSSL_AAR)\prefab\modules\crypto\libs\android.$(AndroidAbi)\libcrypto.so"
DestinationFolder="$(PublishDir)" SkipUnchangedFiles="true"/>
<RemoveDir Directories="$(BundleDir)" />
<AndroidAppBuilderTask
- Abi="$(AndroidAbi)"
+ RuntimeIdentifier="$(RuntimeIdentifier)"
ProjectName="$(AssemblyName)"
MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackNativeDir)include\mono-2.0"
MainLibraryFileName="AndroidTestRunner.dll"
-->
<PropertyGroup>
- <MonoEnableCMake Condition="'$(TargetsBrowser)' == 'true' or '$(TargetsOSX)' == 'true' or '$(TargetsAndroid)' == 'true'">true</MonoEnableCMake>
+ <MonoEnableCMake Condition="'$(TargetsBrowser)' == 'true' or '$(TargetsOSX)' == 'true'">true</MonoEnableCMake>
<MonoCrossDir Condition="'$(MonoCrossDir)' == '' and '$(ROOTFS_DIR)' != ''">$(ROOTFS_DIR)</MonoCrossDir>
<MonoEnableInterpreter Condition="'$(MonoEnableInterpreter)' == ''">false</MonoEnableInterpreter>
<ScriptExt Condition="'$(OS)' == 'Windows_NT'">.cmd</ScriptExt>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<TargetArchitecture Condition="'$(TargetArchitecture)'==''">x64</TargetArchitecture>
- <TargetOS>Android</TargetOS>
- <MicrosoftNetCoreAppRuntimePackDir>$(ArtifactsBinDir)microsoft.netcore.app.runtime.android-$(TargetArchitecture)\$(Configuration)\runtimes\android-$(TargetArchitecture)\</MicrosoftNetCoreAppRuntimePackDir>
+ <EnableTargetingPackDownload>false</EnableTargetingPackDownload>
+ <RuntimeIdentifier>android-$(TargetArchitecture)</RuntimeIdentifier>
+ <PublishTrimmed Condition="'$(Configuration)' == 'Release'">true</PublishTrimmed>
+ <_TrimmerDefaultAction Condition="'$(Configuration)' == 'Release'">link</_TrimmerDefaultAction>
+ <Optimized Condition="'$(Configuration)' == 'Release'">True</Optimized>
+ <MicrosoftNetCoreAppRuntimePackDir>$(ArtifactsBinDir)microsoft.netcore.app.runtime.$(RuntimeIdentifier)\$(Configuration)\runtimes\android-$(TargetArchitecture)\</MicrosoftNetCoreAppRuntimePackDir>
<NoWarn>$(NoWarn),CA1050</NoWarn>
</PropertyGroup>
- <Target Name="RebuildAndroidAppBuilder">
+ <!-- Redirect 'dotnet publish' to in-tree runtime pack -->
+ <Target Name="TrickRuntimePackLocation" AfterTargets="ProcessFrameworkReferences">
<ItemGroup>
- <AndroidAppBuilderProject Include="$(RepoTasksDir)mobile.tasks\AndroidAppBuilder\AndroidAppBuilder.csproj" />
+ <RuntimePack>
+ <PackageDirectory>$(ArtifactsBinDir)microsoft.netcore.app.runtime.$(RuntimeIdentifier)\$(Configuration)</PackageDirectory>
+ </RuntimePack>
</ItemGroup>
- <MSBuild Projects="@(AndroidAppBuilderProject)"
- Properties="Configuration=$(Configuration);MSBuildRestoreSessionId=$([System.Guid]::NewGuid())"
- Targets="Restore"/>
- <MSBuild Projects="@(AndroidAppBuilderProject)"
- Properties="Configuration=$(Configuration)"
- Targets="Build;Publish"/>
+ <Message Text="Packaged ID: %(RuntimePack.PackageDirectory)" Importance="high" />
</Target>
<UsingTask TaskName="AndroidAppBuilderTask" AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)"/>
- <Target Name="BuildApp" DependsOnTargets="RebuildAndroidAppBuilder;Build">
+ <Target Name="BuildApp" AfterTargets="CopyFilesToPublishDirectory">
<PropertyGroup>
- <AndroidAbi Condition="'$(Platform)'=='arm64'">arm64-v8a</AndroidAbi>
- <AndroidAbi Condition="'$(Platform)'=='arm'">armeabi-v7a</AndroidAbi>
- <AndroidAbi Condition="'$(Platform)'=='x64'">x86_64</AndroidAbi>
- <AndroidAbi Condition="'$(AndroidAbi)'==''">$(Platform)</AndroidAbi>
<StripDebugSymbols>False</StripDebugSymbols>
<StripDebugSymbols Condition="'$(Configuration)' == 'Release'">True</StripDebugSymbols>
<AdbTool>$(ANDROID_SDK_ROOT)\platform-tools\adb</AdbTool>
<ApkDir>$(OutputPath)apk\</ApkDir>
</PropertyGroup>
- <ItemGroup>
- <AssemblySearchPaths Include="$(OutputPath)" />
- <AssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackDir)native"/>
- <AssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackDir)lib\$(NetCoreAppCurrent)"/>
- </ItemGroup>
-
<RemoveDir Directories="$(ApkDir)" />
<AndroidAppBuilderTask
+ RuntimeIdentifier="$(RuntimeIdentifier)"
SourceDir="$(OutputPath)"
- Abi="$(AndroidAbi)"
ProjectName="HelloAndroid"
MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackDir)\native\include\mono-2.0"
MainLibraryFileName="$(AssemblyName).dll"
StripDebugSymbols="$(StripDebugSymbols)"
- AssemblySearchPaths="@(AssemblySearchPaths)"
OutputDir="$(ApkDir)">
<Output TaskParameter="ApkBundlePath" PropertyName="ApkBundlePath" />
<Output TaskParameter="ApkPackageId" PropertyName="ApkPackageId" />
../../../../.././build.sh Mono+Libs -os Android -arch $(MONO_ARCH) -c $(MONO_CONFIG)
run:
- $(DOTNET) build \
+ $(DOTNET) publish \
/p:TargetArchitecture=$(MONO_ARCH) \
- /p:TargetOS=Android \
/p:Configuration=$(MONO_CONFIG) \
/p:DeployAndRun=true
clean:
- rm -rf bin
+ rm -rf ../../../../../artifacts/bin/AndroidSampleApp
[Required]
public string SourceDir { get; set; } = ""!;
- public ITaskItem[]? AssemblySearchPaths { get; set; }
-
- public ITaskItem[]? ExtraAssemblies { get; set; }
-
[Required]
public string MonoRuntimeHeaders { get; set; } = ""!;
/// </summary>
public string MainLibraryFileName { get; set; } = ""!;
- /// <summary>
- /// Target arch, can be 'x86', 'x86_64', 'armeabi-v7a' or 'arm64-v8a'
- /// </summary>
[Required]
- public string Abi { get; set; } = ""!;
+ public string RuntimeIdentifier { get; set; } = ""!;
public string? ProjectName { get; set; }
{
Utils.Logger = Log;
+ string abi = DetermineAbi();
+
var apkBuilder = new ApkBuilder();
apkBuilder.ProjectName = ProjectName;
apkBuilder.OutputDir = OutputDir;
apkBuilder.BuildApiLevel = BuildApiLevel;
apkBuilder.BuildToolsVersion = BuildToolsVersion;
apkBuilder.StripDebugSymbols = StripDebugSymbols;
- apkBuilder.AssemblySearchPaths = AssemblySearchPaths?.Select(a => a.ItemSpec)?.ToArray();
- apkBuilder.ExtraAssemblies = ExtraAssemblies?.Select(a => a.ItemSpec)?.ToArray();
- (ApkBundlePath, ApkPackageId) = apkBuilder.BuildApk(SourceDir, Abi, MainLibraryFileName, MonoRuntimeHeaders);
+ (ApkBundlePath, ApkPackageId) = apkBuilder.BuildApk(SourceDir, abi, MainLibraryFileName, MonoRuntimeHeaders);
return true;
}
+
+ private string DetermineAbi()
+ {
+ switch (RuntimeIdentifier)
+ {
+ case "android-x86":
+ return "x86";
+ case "android-x64":
+ return "x86_64";
+ case "android-arm":
+ return "armeabi-v7a";
+ case "android-arm64":
+ return "arm64-v8a";
+ default:
+ throw new ArgumentException(RuntimeIdentifier + " is not supported for Android");
+ }
+ }
}
<PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(RefOnlyMicrosoftBuildTasksCoreVersion)" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(RefOnlyMicrosoftBuildUtilitiesCoreVersion)" />
- <PackageReference Include="System.Reflection.MetadataLoadContext" Version="4.7.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="ApkBuilder.cs" />
<Compile Include="AndroidAppBuilder.cs" />
- <Compile Include="AssemblyResolver.cs" />
<Compile Include="Utils.cs" />
</ItemGroup>
public string? BuildToolsVersion { get; set; }
public string? OutputDir { get; set; }
public bool StripDebugSymbols { get; set; }
- public string[]? AssemblySearchPaths { get; set; }
- public string[]? ExtraAssemblies { get; set; }
public (string apk, string packageId) BuildApk(
string sourceDir, string abi, string entryPointLib, string monoRuntimeHeaders)
extensionsToIgnore.Add(".dbg");
}
- var assembliesToResolve = new List<string>();
-
- if (!string.IsNullOrEmpty(entryPointLibPath))
- assembliesToResolve.Add(entryPointLibPath);
-
- if (ExtraAssemblies != null)
- assembliesToResolve.AddRange(ExtraAssemblies);
-
- // try to resolve dependencies of entryPointLib + ExtraAssemblies from AssemblySearchPaths
- // and copy them to sourceDir
- if (AssemblySearchPaths?.Length > 0)
- {
- string[] resolvedDependencies = AssemblyResolver.ResolveDependencies(assembliesToResolve.ToArray(), AssemblySearchPaths, true);
- foreach (string resolvedDependency in resolvedDependencies)
- {
- string destination = Path.Combine(sourceDir, Path.GetFileName(resolvedDependency));
- if (!File.Exists(destination))
- File.Copy(resolvedDependency, destination);
- }
- }
- else
- {
- AssemblySearchPaths = new[] {OutputDir};
- }
-
- // copy all native libs from AssemblySearchPaths to sourceDir
- // TODO: skip some if not used by the app
- string[] allFiles = AssemblySearchPaths.SelectMany(p => Directory.GetFiles(p, "*", SearchOption.AllDirectories)).ToArray();
- foreach (string nativeLib in allFiles.Where(f => f.EndsWith(".a") || f.EndsWith(".so")))
- {
- string destination = Path.Combine(sourceDir, Path.GetFileName(nativeLib));
- if (!File.Exists(destination))
- File.Copy(nativeLib, destination);
- }
-
// Copy sourceDir to OutputDir/assets-tozip (ignore native files)
// these files then will be zipped and copied to apk/assets/assets.zip
Utils.DirectoryCopy(sourceDir, Path.Combine(OutputDir, "assets-tozip"), file =>
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-
-internal class AssemblyResolver : MetadataAssemblyResolver
-{
- private string[] _searchPaths;
-
- public AssemblyResolver(string[] searchPaths) => _searchPaths = searchPaths;
-
- public static string[] ResolveDependencies(
- string[] assembliesToResolve, string[] searchPaths, bool ignoreErrors = true)
- {
- var assemblies = new Dictionary<string, Assembly>();
- var mlc = new MetadataLoadContext(new AssemblyResolver(searchPaths), "System.Private.CoreLib");
- foreach (string assemblyPath in assembliesToResolve)
- {
- try
- {
- AddAssembly(mlc, mlc.LoadFromAssemblyPath(assemblyPath), assemblies, ignoreErrors);
- }
- catch (Exception)
- {
- if (!ignoreErrors)
- {
- throw;
- }
- }
- }
- return assemblies.Values.Select(i => i.Location).Distinct().ToArray();
- }
-
- private static void AddAssembly(MetadataLoadContext mlc, Assembly assembly, Dictionary<string, Assembly> assemblies, bool ignoreErrors)
- {
- if (assemblies.ContainsKey(assembly.GetName().Name!))
- return;
- assemblies[assembly.GetName().Name!] = assembly;
- foreach (AssemblyName name in assembly.GetReferencedAssemblies())
- {
- try
- {
- Assembly refAssembly = mlc.LoadFromAssemblyName(name);
- AddAssembly(mlc, refAssembly, assemblies, ignoreErrors);
- }
- catch (Exception)
- {
- if (!ignoreErrors)
- {
- throw;
- }
- }
- }
- }
-
- public override Assembly? Resolve(MetadataLoadContext context, AssemblyName assemblyName)
- {
- string name = assemblyName.Name!;
- foreach (string dir in _searchPaths)
- {
- string path = Path.Combine(dir, name + ".dll");
- if (File.Exists(path))
- return context.LoadFromAssemblyPath(path);
- }
- return null;
- }
-}