//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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; }