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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 84 additions & 33 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Xamarin.Android.Build.Utilities;
using ThreadingTasks = System.Threading.Tasks;

namespace Xamarin.Android.Tasks
{
public class Aapt : ToolTask
public class Aapt : AsyncTask
{
private const string error_regex_string = @"(?<file>.*)\s*:\s*(?<line>\d*)\s*:\s*error:\s*(?<error>.+)";
private Regex error_regex = new Regex (error_regex_string, RegexOptions.Compiled);
Expand All @@ -28,7 +29,7 @@ public class Aapt : ToolTask
public string AssetDirectory { get; set; }

[Required]
public string ManifestFile { get; set; }
public ITaskItem[] ManifestFiles { get; set; }

[Required]
public string ResourceDirectory { get; set; }
Expand All @@ -55,7 +56,11 @@ public class Aapt : ToolTask

public string ExtraArgs { get; set; }

protected override string ToolName { get { return OS.IsWindows ? "aapt.exe" : "aapt"; } }
protected string ToolName { get { return OS.IsWindows ? "aapt.exe" : "aapt"; } }

public string ToolPath { get; set; }

public string ToolExe { get; set; }

public string ApiLevel { get; set; }

Expand All @@ -73,7 +78,6 @@ public class Aapt : ToolTask

public bool ExplicitCrunch { get; set; }

string currentAbi;
string currentResourceOutputFile;
Dictionary<string,string> resource_name_case_map = new Dictionary<string,string> ();

Expand All @@ -84,10 +88,43 @@ bool ManifestIsUpToDate (string manifestFile)
File.GetLastWriteTime (AndroidComponentResgenFlagFile) > File.GetLastWriteTime (manifestFile);
}

bool ExecuteForAbi (string abi)
bool RunAapt (string commandLine)
{
var psi = new ProcessStartInfo () {
FileName = GenerateFullPathToTool (),
Arguments = commandLine,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
};

var proc = new Process ();
proc.OutputDataReceived += (sender, e) => {
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
};
proc.ErrorDataReceived += (sender, e) => {
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
};
proc.StartInfo = psi;
proc.Start ();
proc.BeginOutputReadLine ();
proc.BeginErrorReadLine ();
Token.Register (() => {
try {
proc.Kill ();
} catch (Exception) {
}
});
LogDebugMessage ("Executing {0}", commandLine);
proc.WaitForExit ();
return proc.ExitCode == 0;
}

bool ExecuteForAbi (string cmd)
{
currentAbi = abi;
var ret = base.Execute ();
var ret = RunAapt (cmd);
if (ret && !string.IsNullOrEmpty (currentResourceOutputFile)) {
var tmpfile = currentResourceOutputFile + ".bk";
MonoAndroidHelper.CopyIfZipChanged (tmpfile, currentResourceOutputFile);
Expand All @@ -96,11 +133,39 @@ bool ExecuteForAbi (string abi)
return ret;
}

int DoExecute (ITaskItem manifestFile, ThreadingTasks.ParallelLoopState state, int loop)
{
if (!File.Exists (manifestFile.ItemSpec)) {
LogDebugMessage ("{0} does not exists. Skipping", manifestFile.ItemSpec);
return 0;
}

bool upToDate = ManifestIsUpToDate (manifestFile.ItemSpec);

if (AdditionalAndroidResourcePaths != null)
foreach (var dir in AdditionalAndroidResourcePaths)
if (!string.IsNullOrEmpty (dir.ItemSpec))
upToDate = upToDate && ManifestIsUpToDate (string.Format ("{0}{1}{2}{3}{4}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml"));

if (upToDate) {
LogMessage (" Additional Android Resources manifsets files are unchanged. Skipping.");
return 0;
}

var defaultAbi = new string [] { null };
var abis = SupportedAbis?.Split (new char [] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var abi in (CreatePackagePerAbi && abis?.Length > 1) ? defaultAbi.Concat (abis) : defaultAbi) {
ExecuteForAbi (GenerateCommandLineCommands (manifestFile.ItemSpec, abi));
}

return 0;
}

public override bool Execute ()
{
Log.LogDebugMessage ("Aapt Task");
Log.LogDebugMessage (" AssetDirectory: {0}", AssetDirectory);
Log.LogDebugMessage (" ManifestFile: {0}", ManifestFile);
Log.LogDebugTaskItems (" ManifestFiles: ", ManifestFiles);
Log.LogDebugMessage (" ResourceDirectory: {0}", ResourceDirectory);
Log.LogDebugMessage (" JavaDesignerOutputDirectory: {0}", JavaDesignerOutputDirectory);
Log.LogDebugMessage (" PackageName: {0}", PackageName);
Expand All @@ -115,34 +180,18 @@ public override bool Execute ()
if (CreatePackagePerAbi)
Log.LogDebugMessage (" SupportedAbis: {0}", SupportedAbis);

bool upToDate = ManifestIsUpToDate (ManifestFile);

if (ResourceNameCaseMap != null)
foreach (var arr in ResourceNameCaseMap.Split (';').Select (l => l.Split ('|')).Where (a => a.Length == 2))
resource_name_case_map [arr [1]] = arr [0]; // lowercase -> original

if (AdditionalAndroidResourcePaths != null)
foreach (var dir in AdditionalAndroidResourcePaths)
if (!string.IsNullOrEmpty (dir.ItemSpec))
upToDate = upToDate && ManifestIsUpToDate (string.Format ("{0}{1}{2}", dir, Path.DirectorySeparatorChar, "manifest", Path.DirectorySeparatorChar, "AndroidManifest.xml"));

if (upToDate) {
Log.LogMessage (MessageImportance.Normal, " Additional Android Resources manifsets files are unchanged. Skipping.");
return true;
}
ThreadingTasks.Parallel.ForEach (ManifestFiles, () => 0, DoExecute, (obj) => { Complete (); });

ExecuteForAbi (null);
base.Execute ();

if (CreatePackagePerAbi) {
var abis = SupportedAbis.Split (new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
if (abis.Length > 1)
foreach (var abi in abis)
ExecuteForAbi (abi);
}
return !Log.HasLoggedErrors;
}

protected override string GenerateCommandLineCommands ()
protected string GenerateCommandLineCommands (string ManifestFile, string currentAbi)
{
// For creating Resource.Designer.cs:
// Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt
Expand Down Expand Up @@ -260,17 +309,19 @@ string ExpandString (string s)
return s;
}

protected override string GenerateFullPathToTool ()
protected string GenerateFullPathToTool ()
{
return Path.Combine (ToolPath, ToolExe);
return Path.Combine (ToolPath, string.IsNullOrEmpty (ToolExe) ? ToolName : ToolExe);
}

protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
protected void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
{
// Aapt errors looks like this:
// C:\Users\Jonathan\Documents\Visual Studio 2010\Projects\AndroidMSBuildTest\AndroidMSBuildTest\obj\Debug\res\layout\main.axml:7: error: No resource identifier found for attribute 'id2' in package 'android' (TaskId:22)
// Look for them and convert them to MSBuild compatible errors.

if (string.IsNullOrEmpty (singleLine))
return;

var match = error_regex.Match (singleLine);

if (match.Success) {
Expand All @@ -296,11 +347,11 @@ protected override void LogEventsFromTextOutput (string singleLine, MessageImpor

// Handle additional error that doesn't match the regex
if (singleLine.Trim ().StartsWith ("invalid resource directory name:")) {
Log.LogError ("", "", "", ToolName, -1, -1, -1, -1, "Invalid resource directory name: \"{0}\".", singleLine.Substring (singleLine.LastIndexOfAny (new char[] { '\\', '/' }) + 1));
LogError ("", "", "", ToolName, -1, -1, -1, -1, "Invalid resource directory name: \"{0}\".", singleLine.Substring (singleLine.LastIndexOfAny (new char[] { '\\', '/' }) + 1));
messageImportance = MessageImportance.High;
}

base.LogEventsFromTextOutput (singleLine, messageImportance);
LogMessage (singleLine, messageImportance);
}
}
}
24 changes: 4 additions & 20 deletions src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1187,35 +1187,19 @@ because xbuild doesn't support framework reference assemblies.
Outputs="$(_AndroidComponentResgenFlagFile)"
DependsOnTargets="$(_GenerateJavaDesignerForComponentDependsOnTargets)">

<!--
This copy is required because the Aapt statement below will be Batched.
Aapt will be called for each Path in _AdditonalAndroidResourceCachePaths
this is beause of the ManifestFile and Contition properties being set to

"%(_AdditonalAndroidResourceCachePaths.Identity)\AndroidManifest.xml"

the use of .Identify will cause the batch. However we do need ALL of the
resource cache paths to be passed in to correctly resolve resources. If
we don't do this only the current "batched" path will be included.
-->
<ItemGroup>
<_AdditionalAndroidResourceCachePathsCopy Include="@(_AdditonalAndroidResourceCachePaths)"/>
</ItemGroup>

<!-- Run aapt to generate R.java for additional Android resources-->
<Aapt
Condition="Exists('%(_AdditonalAndroidResourceCachePaths.Identity)\AndroidManifest.xml')"
ImportsDirectory="$(_LibraryProjectImportsDirectoryName)"
OutputImportDirectory="$(IntermediateOutputPath)__library_projects__\"
UseShortFileNames="$(UseShortFileNames)"
ManifestFile="%(_AdditonalAndroidResourceCachePaths.Identity)\AndroidManifest.xml"
ManifestFiles="@(_AdditonalAndroidResourceCachePaths->'%(Identity)\AndroidManifest.xml')"
ApplicationName="$(_AndroidPackage)"
JavaPlatformJarPath="$(JavaPlatformJarPath)"
NonConstantId="true"
JavaDesignerOutputDirectory="$(IntermediateOutputPath)android\src"
ResourceDirectory="$(MonoAndroidResDirIntermediate)"
AdditionalResourceDirectories="@(LibraryResourceDirectories)"
AdditionalAndroidResourcePaths="@(_AdditionalAndroidResourceCachePathsCopy)"
AdditionalAndroidResourcePaths="@(_AdditonalAndroidResourceCachePaths)"
AndroidComponentResgenFlagFile="$(_AndroidComponentResgenFlagFile)"
ToolPath="$(AaptToolPath)"
ToolExe="$(AaptToolExe)"
Expand Down Expand Up @@ -1273,7 +1257,7 @@ because xbuild doesn't support framework reference assemblies.
OutputImportDirectory="$(IntermediateOutputPath)__library_projects__\"
UseShortFileNames="$(UseShortFileNames)"
JavaPlatformJarPath="$(JavaPlatformJarPath)"
ManifestFile="$(ResgenTemporaryDirectory)\AndroidManifest.xml"
ManifestFiles="$(ResgenTemporaryDirectory)\AndroidManifest.xml"
PackageName="$(_AndroidPackage)"
ApplicationName="$(_AndroidPackage)"
ResourceDirectory="$(MonoAndroidResDirIntermediate)"
Expand Down Expand Up @@ -1777,7 +1761,7 @@ because xbuild doesn't support framework reference assemblies.
OutputImportDirectory="$(IntermediateOutputPath)__library_projects__\"
UseShortFileNames="$(UseShortFileNames)"
JavaPlatformJarPath="$(JavaPlatformJarPath)"
ManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml"
ManifestFiles="$(IntermediateOutputPath)android\AndroidManifest.xml"
ResourceDirectory="$(MonoAndroidResDirIntermediate)"
JavaDesignerOutputDirectory="$(AaptTemporaryDirectory)"
ResourceOutputFile="$(_PackagedResources)"
Expand Down