//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected override bool ValidateParameters() { // // This tool should really only expect 'AndroidManifest.xml' input. But people might change the names of these, so we can't rely on that to validate. // bool validParameters = true; if (Sources.Length != 1) { Log.LogError("Expected single input, got: " + Sources.Length + "'."); validParameters = false; } if (validParameters) { string sourcePath = Path.GetFullPath(Sources [0].GetMetadata("FullPath")); if (string.IsNullOrEmpty(sourcePath) || !File.Exists(sourcePath)) { Log.LogError("Could locate expected input: '" + sourcePath + "'."); validParameters = false; } try { if (validParameters) { AndroidManifestDocument sourceManifest = new AndroidManifestDocument(); sourceManifest.Load(sourcePath); } } catch (Exception e) { Log.LogError("Could not successfully parse '" + sourcePath + "'. Check this is a valid AndroidManifest.xml document. Reason: " + e, MessageImportance.High); Log.LogErrorFromException(e, true); validParameters = false; } } return(validParameters && base.ValidateParameters()); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected override int TrackedExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) { // // Use default implementation, but ensure that any generated sources and dependency files get flagged as output appropriately. // int retCode = -1; Dictionary <string, ITaskItem> processedManifestFiles = new Dictionary <string, ITaskItem> (); List <ITaskItem> outputApkFileList = new List <ITaskItem> (); List <ITaskItem> outputFilesList = new List <ITaskItem> (); try { foreach (ITaskItem source in Sources) { string sourcePath = Path.GetFullPath(source.GetMetadata("FullPath")); if (!processedManifestFiles.ContainsKey(sourcePath)) { retCode = base.TrackedExecuteTool(pathToTool, responseFileCommands, commandLineCommands); processedManifestFiles.Add(sourcePath, source); if (retCode == 0) { AndroidManifestDocument sourceManifest = new AndroidManifestDocument(); sourceManifest.Load(sourcePath); // // Determine if this manifest requested APK generation, add to output list. // if (!string.IsNullOrWhiteSpace(source.GetMetadata("ApkOutputFile"))) { string apkOutputFile = source.GetMetadata("ApkOutputFile"); if (!File.Exists(apkOutputFile)) { throw new FileNotFoundException("Requested APK output file does not exist. Error during packaging?"); } ITaskItem outputApkItem = new TaskItem(Path.GetFullPath(apkOutputFile)); outputApkFileList.Add(outputApkItem); outputFilesList.Add(outputApkItem); } if (source.GetMetadata("GenerateDependencies") == "true") { // // Evaluate which resource constant source files have been exported. 'ExtraPackages' lists additional package names that also have resource ids. // List <string> resourceConstantSourceFiles = new List <string> (); string resourcesDirectory = source.GetMetadata("ResourceConstantsOutputDirectory"); if (File.Exists(Path.Combine(resourcesDirectory, "R.java"))) { resourceConstantSourceFiles.Add(Path.Combine(resourcesDirectory, "R.java")); } if (File.Exists(Path.Combine(resourcesDirectory, sourceManifest.PackageName.Replace('.', '\\'), "R.java"))) { resourceConstantSourceFiles.Add(Path.Combine(resourcesDirectory, sourceManifest.PackageName.Replace('.', '\\'), "R.java")); } if (!string.IsNullOrWhiteSpace(source.GetMetadata("ExtraPackages"))) { string [] extraPackages = source.GetMetadata("ExtraPackages").Split(':'); foreach (string package in extraPackages) { if (File.Exists(Path.Combine(resourcesDirectory, package.Replace('.', '\\'), "R.java"))) { resourceConstantSourceFiles.Add(Path.Combine(resourcesDirectory, package.Replace('.', '\\'), "R.java")); } } } // // When exporting an APK the R.java.d file will not properly list dependencies. Copy from ??.apk.d to solve this. // string dependencyFileSource = Path.Combine(resourcesDirectory, "R.java.d"); if (!string.IsNullOrWhiteSpace(source.GetMetadata("ApkOutputFile"))) { string apkDependencyFileSource = source.GetMetadata("ApkOutputFile") + ".d"; GccUtilities.DependencyParser.ConvertJavaDependencyFileToGcc(apkDependencyFileSource); File.Copy(apkDependencyFileSource, dependencyFileSource, true); // overwrite invalid R.java.d export } // // R.java.d dependency files are not placed alongside its master file if exported using package directories. Fix this. // foreach (string master in resourceConstantSourceFiles) { string masterDependencyFile = master + ".d"; Directory.CreateDirectory(Path.GetDirectoryName(masterDependencyFile)); if (File.Exists(masterDependencyFile)) { File.Delete(masterDependencyFile); } File.Copy(dependencyFileSource, masterDependencyFile); } // // Finally ensure all resource constant export files are added to the output list. // foreach (string file in resourceConstantSourceFiles) { ITaskItem outputResourceFileItem = new TaskItem(Path.GetFullPath(file)); outputFilesList.Add(outputResourceFileItem); } } if (retCode != 0) { break; } } } } } catch (Exception e) { Log.LogErrorFromException(e, true); retCode = -1; } finally { OutputApk = outputApkFileList.ToArray(); OutputFiles = outputFilesList.ToArray(); } return(retCode); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override bool Execute() { try { if (PrimaryManifest.Length == 0) { Log.LogError("No 'PrimaryManifest' file(s) specified."); return(false); } if (PrimaryManifest.Length > 1) { Log.LogError("Too many 'PrimaryManifest' files specified. Expected one."); return(false); } if (ProjectManifests.Length == 0) { Log.LogError("No 'ProjectManifests' file(s) specified."); return(false); } // // Identify which is the primary AndroidManifest.xml provided. // MergedManifest = null; string primaryManifestFullPath = PrimaryManifest [0].GetMetadata("FullPath"); foreach (ITaskItem manifestItem in ProjectManifests) { string manifestItemFullPath = manifestItem.GetMetadata("FullPath"); if (primaryManifestFullPath.Equals(manifestItemFullPath)) { MergedManifest = manifestItem; break; } } if (MergedManifest == null) { Log.LogError("Could not find 'primary' manifest in provided list of project manifests. Expected: " + primaryManifestFullPath); return(false); } // // Sanity check all manifests to ensure that there's not another which defines <application> that's not 'primary'. // ITaskItem applicationManifest = null; foreach (ITaskItem manifestItem in ProjectManifests) { AndroidManifestDocument androidManifestDocument = new AndroidManifestDocument(); androidManifestDocument.Load(manifestItem.GetMetadata("FullPath")); if (androidManifestDocument.IsApplication) { if (applicationManifest == null) { applicationManifest = manifestItem; break; } else { Log.LogError("Found multiple AndroidManifest files which define an <application> node."); return(false); } } } if ((applicationManifest != null) && (applicationManifest != MergedManifest)) { Log.LogError("Specified project manifest does not define an <application> node."); return(false); } // // Process other 'third-party' manifests merging required metadata. // if (MergedManifest != null) { HashSet <string> extraPackages = new HashSet <string> (); HashSet <string> extraResourcePaths = new HashSet <string> (); extraResourcePaths.Add(MergedManifest.GetMetadata("IncludeResourceDirectories")); foreach (ITaskItem item in ProjectManifests) { AndroidManifestDocument androidManifestDocument = new AndroidManifestDocument(); androidManifestDocument.Load(item.GetMetadata("FullPath")); if (item == MergedManifest) { PackageName = androidManifestDocument.PackageName; } else { if (!extraPackages.Contains(androidManifestDocument.PackageName)) { extraPackages.Add(androidManifestDocument.PackageName); } if (!extraResourcePaths.Contains(item.GetMetadata("IncludeResourceDirectories"))) { extraResourcePaths.Add(item.GetMetadata("IncludeResourceDirectories")); } } } MergedManifest.SetMetadata("ExtraPackages", String.Join(":", extraPackages.ToArray())); MergedManifest.SetMetadata("IncludeResourceDirectories", String.Join(";", extraResourcePaths.ToArray())); return(true); } } catch (Exception e) { Log.LogErrorFromException(e, true); } return(false); }