コード例 #1
0
        /// <summary>
        /// Explodes a single aar file.  This is done by calling the
        /// JDK "jar" command, then moving the classes.jar file.
        /// </summary>
        /// <param name="dir">the parent directory of the plugin.</param>
        /// <param name="aarFile">Aar file to explode.</param>
        /// <returns>The path to the exploded aar.
        internal virtual string ProcessAar(string dir, string aarFile)
        {
            string workingDir = Path.Combine(dir, Path.GetFileNameWithoutExtension(aarFile));

            PlayServicesSupport.DeleteExistingFileOrDirectory(workingDir, includeMetaFiles: true);
            Directory.CreateDirectory(workingDir);
            if (!ExtractAar(aarFile, null, workingDir))
            {
                return(workingDir);
            }

            // Create the libs directory to store the classes.jar and non-Java shared libraries.
            string libDir = Path.Combine(workingDir, "libs");

            Directory.CreateDirectory(libDir);

            // Move the classes.jar file to libs.
            string classesFile = Path.Combine(workingDir, "classes.jar");

            if (File.Exists(classesFile))
            {
                string targetClassesFile = Path.Combine(libDir, Path.GetFileName(classesFile));
                if (File.Exists(targetClassesFile))
                {
                    File.Delete(targetClassesFile);
                }
                File.Move(classesFile, targetClassesFile);
            }

            // Copy non-Java shared libraries (.so) files from the "jni" directory into the
            // lib directory so that Unity's legacy (Ant-like) build system includes them in the
            // built APK.
            string jniLibDir = Path.Combine(workingDir, "jni");

            if (Directory.Exists(jniLibDir))
            {
                PlayServicesSupport.CopyDirectory(jniLibDir, libDir);
                PlayServicesSupport.DeleteExistingFileOrDirectory(jniLibDir,
                                                                  includeMetaFiles: true);
            }

            // Create the project.properties file which indicates to
            // Unity that this directory is a plugin.
            string projectProperties = Path.Combine(workingDir, "project.properties");

            if (!File.Exists(projectProperties))
            {
                File.WriteAllLines(projectProperties, new [] {
                    "# Project target.",
                    "target=android-9",
                    "android.library=true"
                });
            }

            // Clean up the aar file.
            File.Delete(Path.GetFullPath(aarFile));
            Debug.Log(aarFile + " expanded successfully");
            return(workingDir);
        }
コード例 #2
0
 /// <summary>
 /// Delete the full set of assets managed from this plugin.
 /// This is used for uninstalling or switching between resolvers which maintain a different
 /// set of assets.
 /// </summary>
 internal static void DeleteLabeledAssets()
 {
     foreach (var assetPath in PlayServicesResolver.FindLabeledAssets())
     {
         PlayServicesSupport.DeleteExistingFileOrDirectory(assetPath,
                                                           includeMetaFiles: true);
     }
     AssetDatabase.Refresh();
 }
コード例 #3
0
        /// <summary>
        /// Determined whether an aar file should be exploded (extracted).
        ///
        /// This is required for some aars so that the Unity Jar Resolver can perform variable
        /// expansion on manifests in the package before they're merged by aapt.
        /// </summary>
        /// <returns><c>true</c>, if the aar should be exploded, <c>false</c> otherwise.</returns>
        /// <param name="aarFile">The aar file.</param>
        internal virtual bool ShouldExplode(string aarFile)
        {
            AarExplodeData aarData = null;

            if (!aarExplodeData.TryGetValue(aarFile, out aarData))
            {
                aarData = new AarExplodeData();
            }
            bool explode = !SupportsAarFiles;

            if (!explode)
            {
                System.DateTime modificationTime = File.GetLastWriteTime(aarFile);
                if (modificationTime.CompareTo(aarData.modificationTime) <= 0)
                {
                    explode = aarData.explode;
                }
            }
            if (!explode)
            {
                string temporaryDirectory = CreateTemporaryDirectory();
                if (temporaryDirectory == null)
                {
                    return(false);
                }
                string manifestFilename = "AndroidManifest.xml";
                try
                {
                    if (ExtractAar(aarFile, new string[] { manifestFilename },
                                   temporaryDirectory))
                    {
                        string manifestPath = Path.Combine(temporaryDirectory,
                                                           manifestFilename);
                        if (File.Exists(manifestPath))
                        {
                            string manifest = File.ReadAllText(manifestPath);
                            explode = manifest.IndexOf("${applicationId}") >= 0;
                        }
                        aarData.modificationTime = File.GetLastWriteTime(aarFile);
                    }
                }
                catch (System.Exception e)
                {
                    Debug.Log("Unable to examine AAR file " + aarFile + ", err: " + e);
                    throw e;
                }
                finally
                {
                    PlayServicesSupport.DeleteExistingFileOrDirectory(temporaryDirectory);
                }
            }
            aarData.explode         = explode;
            aarExplodeData[aarFile] = aarData;
            return(explode);
        }
コード例 #4
0
 /// <summary>
 /// Delete the specified array of files and directories.
 /// </summary>
 /// <param name="filenames">Array of files or directories to delete.</param>
 /// <returns>true if files are deleted, false otherwise.</returns>
 private static bool DeleteFiles(string[] filenames)
 {
     if (filenames == null)
     {
         return(false);
     }
     foreach (string artifact in filenames)
     {
         PlayServicesSupport.DeleteExistingFileOrDirectory(artifact);
     }
     AssetDatabase.Refresh();
     return(true);
 }
コード例 #5
0
        /// <summary>
        /// Delete the specified array of files and directories.
        /// </summary>
        /// <param name="filenames">Array of files or directories to delete.</param>
        /// <returns>true if files are deleted, false otherwise.</returns>
        private static bool DeleteFiles(string[] filenames)
        {
            if (filenames == null)
            {
                return(false);
            }
            bool deletedFiles = false;

            foreach (string artifact in filenames)
            {
                deletedFiles |= PlayServicesSupport.DeleteExistingFileOrDirectory(
                    artifact, includeMetaFiles: true);
            }
            if (deletedFiles)
            {
                AssetDatabase.Refresh();
            }
            return(deletedFiles);
        }
コード例 #6
0
 /// <summary>
 /// Processes the aars.
 /// </summary>
 /// <remarks>Each aar copied is inspected and determined if it should be
 /// exploded into a directory or not. Unneeded exploded directories are
 /// removed.
 /// <para>
 /// Exploding is needed if the version of Unity is old, or if the artifact
 /// has been explicitly flagged for exploding.  This allows the subsequent
 /// processing of variables in the AndroidManifest.xml file which is not
 /// supported by the current versions of the manifest merging process that
 /// Unity uses.
 /// </para>
 /// <param name="dir">The directory to process.</param>
 void ProcessAars(string dir)
 {
     string[] files = Directory.GetFiles(dir, "*.aar");
     foreach (string f in files)
     {
         string dirPath    = Path.Combine(dir, Path.GetFileNameWithoutExtension(f));
         string targetPath = Path.Combine(dir, Path.GetFileName(f));
         if (ShouldExplode(f))
         {
             ReplaceVariables(ProcessAar(Path.GetFullPath(dir), f));
             targetPath = dirPath;
         }
         else
         {
             // Clean up previously expanded / exploded versions of the AAR.
             PlayServicesSupport.DeleteExistingFileOrDirectory(dirPath,
                                                               includeMetaFiles: true);
         }
         aarExplodeData[f].path     = targetPath;
         aarExplodeData[f].bundleId = PlayerSettings.bundleIdentifier;
     }
 }
コード例 #7
0
        // Implementation of OnPostProcessUpdateProjectDeps().
        // NOTE: This is separate from the post-processing method to prevent the
        // Mono runtime from loading the Xcode API before calling the post
        // processing step.
        public static void UpdateProjectDeps(
            BuildTarget buildTarget, string pathToBuiltProject)
        {
            // If the Pods directory does not exist, the pod download step
            // failed.
            var podsDir = Path.Combine(pathToBuiltProject, PODS_DIR);

            if (!Directory.Exists(podsDir))
            {
                return;
            }

            Directory.CreateDirectory(Path.Combine(pathToBuiltProject,
                                                   "Frameworks"));
            Directory.CreateDirectory(Path.Combine(pathToBuiltProject,
                                                   "Resources"));

            string pbxprojPath = GetProjectPath(pathToBuiltProject);
            var    project     = new UnityEditor.iOS.Xcode.PBXProject();

            project.ReadFromString(File.ReadAllText(pbxprojPath));
            string target = project.TargetGuidByName(TARGET_NAME);

            HashSet <string> frameworks = new HashSet <string>();
            HashSet <string> linkFlags  = new HashSet <string>();

            foreach (var frameworkFullPath in
                     Directory.GetDirectories(podsDir, "*.framework",
                                              SearchOption.AllDirectories))
            {
                string frameworkName     = new DirectoryInfo(frameworkFullPath).Name;
                string destFrameworkPath = Path.Combine("Frameworks",
                                                        frameworkName);
                string destFrameworkFullPath = Path.Combine(pathToBuiltProject,
                                                            destFrameworkPath);
                // Only move this framework if it contains a library.
                // Skip frameworks that consist of just resources, they're handled
                // in a separate import step.
                if (!File.Exists(Path.Combine(
                                     frameworkFullPath,
                                     Path.GetFileName(frameworkFullPath)
                                     .Replace(".framework", ""))))
                {
                    continue;
                }

                PlayServicesSupport.DeleteExistingFileOrDirectory(
                    destFrameworkFullPath);
                Directory.Move(frameworkFullPath, destFrameworkFullPath);
                project.AddFileToBuild(
                    target,
                    project.AddFile(destFrameworkPath,
                                    destFrameworkPath,
                                    UnityEditor.iOS.Xcode.PBXSourceTree.Source));

                string moduleMapPath =
                    Path.Combine(Path.Combine(destFrameworkFullPath, "Modules"),
                                 "module.modulemap");

                if (File.Exists(moduleMapPath))
                {
                    // Parse the modulemap, format spec here:
                    // http://clang.llvm.org/docs/Modules.html#module-map-language
                    using (StreamReader moduleMapFile =
                               new StreamReader(moduleMapPath)) {
                        string line;
                        char[] delim = { ' ' };
                        while ((line = moduleMapFile.ReadLine()) != null)
                        {
                            string[] items = line.TrimStart(delim).Split(delim, 2);
                            if (items.Length > 1)
                            {
                                if (items[0] == "link")
                                {
                                    if (items[1].StartsWith("framework"))
                                    {
                                        items = items[1].Split(delim, 2);
                                        frameworks.Add(items[1].Trim(
                                                           new char[] { '\"' }) + ".framework");
                                    }
                                    else
                                    {
                                        linkFlags.Add("-l" + items[1]);
                                    }
                                }
                            }
                        }
                    }
                }

                string resourcesFolder = Path.Combine(destFrameworkFullPath,
                                                      "Resources");
                if (Directory.Exists(resourcesFolder))
                {
                    string[] resFiles   = Directory.GetFiles(resourcesFolder);
                    string[] resFolders =
                        Directory.GetDirectories(resourcesFolder);
                    foreach (var resFile in resFiles)
                    {
                        string destFile = Path.Combine("Resources",
                                                       Path.GetFileName(resFile));
                        File.Copy(resFile, Path.Combine(pathToBuiltProject,
                                                        destFile), true);
                        project.AddFileToBuild(
                            target, project.AddFile(
                                destFile, destFile,
                                UnityEditor.iOS.Xcode.PBXSourceTree.Source));
                    }
                    foreach (var resFolder in resFolders)
                    {
                        string destFolder =
                            Path.Combine("Resources",
                                         new DirectoryInfo(resFolder).Name);
                        string destFolderFullPath =
                            Path.Combine(pathToBuiltProject, destFolder);
                        PlayServicesSupport.DeleteExistingFileOrDirectory(
                            destFolderFullPath);
                        Directory.Move(resFolder, destFolderFullPath);
                        project.AddFileToBuild(
                            target, project.AddFile(
                                destFolder, destFolder,
                                UnityEditor.iOS.Xcode.PBXSourceTree.Source));
                    }
                }
            }

            foreach (var framework in frameworks)
            {
                project.AddFrameworkToProject(target, framework, false);
            }
            foreach (var linkFlag in linkFlags)
            {
                project.AddBuildProperty(target, "OTHER_LDFLAGS", linkFlag);
            }

            // Add all source files found under the pods directory to the project.
            // This is a very crude way of partially supporting source pods.
            var podPathToProjectPaths = new Dictionary <string, string>();

            // Find pod source files and map them to paths relative to the target
            // Xcode project.
            foreach (var filename in
                     FindFilesWithExtensions(podsDir, SOURCE_FILE_EXTENSIONS))
            {
                // Save the path relative to the target project for each path
                // relative to the generated pods Xcode project.
                // +1 in the following expressions to strip the file separator.
                podPathToProjectPaths[filename.Substring(podsDir.Length + 1)] =
                    filename.Substring(pathToBuiltProject.Length + 1);
            }
            // Add a reference to each source file in the target project.
            foreach (var podPathProjectPath in podPathToProjectPaths)
            {
                project.AddFileToBuild(
                    target,
                    project.AddFile(podPathProjectPath.Value,
                                    podPathProjectPath.Value,
                                    UnityEditor.iOS.Xcode.PBXSourceTree.Source));
            }

            // Attempt to read per-file compile / build settings from the Pods
            // project.
            var podsProjectPath = GetProjectPath(podsDir, PODS_PROJECT_NAME);
            var podsProject     = new UnityEditor.iOS.Xcode.PBXProject();

            podsProject.ReadFromString(File.ReadAllText(podsProjectPath));
            foreach (var directory in Directory.GetDirectories(podsDir))
            {
                // Each pod will have a top level directory under the pods dir
                // named after the pod.  Also, some pods have build targets in the
                // xcode project where each build target has the same name as the
                // pod such that pod Foo is in directory Foo with build target Foo.
                // Since we can't read the build targets from the generated Xcode
                // project using Unity's API, we scan the Xcode project for targets
                // to optionally retrieve build settings for each source file
                // the settings can be applied in the target project.
                var podTargetName = Path.GetFileName(directory);
                var podTargetGuid = podsProject.TargetGuidByName(podTargetName);
                Log(String.Format("Looking for target: {0} guid: {1}",
                                  podTargetName, podTargetGuid ?? "null"),
                    verbose: true);
                if (podTargetGuid == null)
                {
                    continue;
                }
                foreach (var podPathProjectPath in podPathToProjectPaths)
                {
                    var podSourceFileGuid = podsProject.FindFileGuidByRealPath(
                        podPathProjectPath.Key);
                    if (podSourceFileGuid == null)
                    {
                        continue;
                    }
                    var podSourceFileCompileFlags =
                        podsProject.GetCompileFlagsForFile(podTargetGuid,
                                                           podSourceFileGuid);
                    if (podSourceFileCompileFlags == null)
                    {
                        continue;
                    }
                    var targetSourceFileGuid = project.FindFileGuidByProjectPath(
                        podPathProjectPath.Value);
                    if (targetSourceFileGuid == null)
                    {
                        Log("Unable to find " + podPathProjectPath.Value +
                            " in generated project", level: LogLevel.Warning);
                        continue;
                    }
                    Log(String.Format(
                            "Setting {0} compile flags to ({1})",
                            podPathProjectPath.Key,
                            String.Join(", ",
                                        podSourceFileCompileFlags.ToArray())),
                        verbose: true);
                    project.SetCompileFlagsForFile(target, targetSourceFileGuid,
                                                   podSourceFileCompileFlags);
                }
            }

            File.WriteAllText(pbxprojPath, project.WriteToString());
        }
コード例 #8
0
        /// <summary>
        /// Explodes a single aar file.  This is done by calling the
        /// JDK "jar" command, then moving the classes.jar file.
        /// </summary>
        /// <param name="dir">the parent directory of the plugin.</param>
        /// <param name="aarFile">Aar file to explode.</param>
        /// <param name="antProject">true to explode into an Ant style project or false
        /// to repack the processed AAR as a new AAR.</param>
        /// <param name="abi">ABI of the AAR or null if it's universal.</param>
        /// <returns>true if successful, false otherwise.</returns>
        internal virtual bool ProcessAar(string dir, string aarFile, bool antProject,
                                         out string abi)
        {
            PlayServicesSupport.Log(String.Format("ProcessAar {0} {1} antProject={2}",
                                                  dir, aarFile, antProject), verbose: true);
            abi = null;
            string workingDir = Path.Combine(dir, Path.GetFileNameWithoutExtension(aarFile));

            PlayServicesSupport.DeleteExistingFileOrDirectory(workingDir, includeMetaFiles: true);
            Directory.CreateDirectory(workingDir);
            if (!ExtractAar(aarFile, null, workingDir))
            {
                return(false);
            }
            ReplaceVariables(workingDir);

            string nativeLibsDir = null;

            if (antProject)
            {
                // Create the libs directory to store the classes.jar and non-Java shared
                // libraries.
                string libDir = Path.Combine(workingDir, "libs");
                nativeLibsDir = libDir;
                Directory.CreateDirectory(libDir);

                // Move the classes.jar file to libs.
                string classesFile       = Path.Combine(workingDir, "classes.jar");
                string targetClassesFile = Path.Combine(libDir, Path.GetFileName(classesFile));
                if (File.Exists(targetClassesFile))
                {
                    File.Delete(targetClassesFile);
                }
                if (File.Exists(classesFile))
                {
                    File.Move(classesFile, targetClassesFile);
                }
                else
                {
                    // Generate an empty classes.jar file.
                    string temporaryDirectory = CreateTemporaryDirectory();
                    if (temporaryDirectory == null)
                    {
                        return(false);
                    }
                    ArchiveAar(targetClassesFile, temporaryDirectory);
                }
            }

            // Copy non-Java shared libraries (.so) files from the "jni" directory into the
            // lib directory so that Unity's legacy (Ant-like) build system includes them in the
            // built APK.
            string jniLibDir = Path.Combine(workingDir, "jni");

            nativeLibsDir = nativeLibsDir ?? jniLibDir;
            if (Directory.Exists(jniLibDir))
            {
                if (jniLibDir != nativeLibsDir)
                {
                    PlayServicesSupport.CopyDirectory(jniLibDir, nativeLibsDir);
                    PlayServicesSupport.DeleteExistingFileOrDirectory(jniLibDir,
                                                                      includeMetaFiles: true);
                }
                // Remove shared libraries for all ABIs that are not required for the selected
                // target ABI.
                var currentAbi = PlayServicesResolver.AndroidTargetDeviceAbi;
                var activeAbis = GetSelectedABIDirs(currentAbi);
                foreach (var directory in Directory.GetDirectories(nativeLibsDir))
                {
                    var abiDir = Path.GetFileName(directory);
                    if (!activeAbis.Contains(abiDir))
                    {
                        PlayServicesSupport.DeleteExistingFileOrDirectory(
                            directory, includeMetaFiles: true);
                    }
                }
                abi = currentAbi;
            }

            if (antProject)
            {
                // Create the project.properties file which indicates to
                // Unity that this directory is a plugin.
                string projectProperties = Path.Combine(workingDir, "project.properties");
                if (!File.Exists(projectProperties))
                {
                    File.WriteAllLines(projectProperties, new [] {
                        "# Project target.",
                        "target=android-9",
                        "android.library=true"
                    });
                }
                // Clean up the aar file.
                PlayServicesSupport.DeleteExistingFileOrDirectory(Path.GetFullPath(aarFile),
                                                                  includeMetaFiles: true);
                // Add a tracking label to the exploded files.
                PlayServicesResolver.LabelAssets(new [] { workingDir });
            }
            else
            {
                // Add a tracking label to the exploded files just in-case packaging fails.
                PlayServicesResolver.LabelAssets(new [] { workingDir });
                // Create a new AAR file.
                PlayServicesSupport.DeleteExistingFileOrDirectory(Path.GetFullPath(aarFile),
                                                                  includeMetaFiles: true);
                if (!ArchiveAar(aarFile, workingDir))
                {
                    return(false);
                }
                // Clean up the exploded directory.
                PlayServicesSupport.DeleteExistingFileOrDirectory(workingDir,
                                                                  includeMetaFiles: true);
            }
            return(true);
        }
コード例 #9
0
        /// <summary>
        /// Determined whether an aar file should be exploded (extracted).
        ///
        /// This is required for some aars so that the Unity Jar Resolver can perform variable
        /// expansion on manifests in the package before they're merged by aapt.
        /// </summary>
        /// <returns><c>true</c>, if the aar should be exploded, <c>false</c> otherwise.</returns>
        /// <param name="aarFile">The aar file.</param>
        internal virtual bool ShouldExplode(string aarFile)
        {
            AarExplodeData aarData = null;

            if (!aarExplodeData.TryGetValue(aarFile, out aarData))
            {
                aarData = new AarExplodeData();
            }
            bool explosionEnabled = true;

            // Unfortunately, as of Unity 5.5.0f3, Unity does not set the applicationId variable
            // in the build.gradle it generates.  This results in non-functional libraries that
            // require the ${applicationId} variable to be expanded in their AndroidManifest.xml.
            // To work around this when Gradle builds are enabled, explosion is enabled for all
            // AARs that require variable expansion unless this behavior is explicitly disabled
            // in the settings dialog.
            if (PlayServicesResolver.GradleBuildEnabled &&
                PlayServicesResolver.ProjectExportEnabled &&
                !SettingsDialog.ExplodeAars)
            {
                explosionEnabled = false;
            }
            bool explode = false;

            if (explosionEnabled)
            {
                explode = !SupportsAarFiles;
                if (!explode)
                {
                    System.DateTime modificationTime = File.GetLastWriteTime(aarFile);
                    if (modificationTime.CompareTo(aarData.modificationTime) <= 0)
                    {
                        explode = aarData.explode;
                    }
                }
                if (!explode)
                {
                    string temporaryDirectory = CreateTemporaryDirectory();
                    if (temporaryDirectory == null)
                    {
                        return(false);
                    }
                    string manifestFilename = "AndroidManifest.xml";
                    try
                    {
                        if (ExtractAar(aarFile, new string[] { manifestFilename },
                                       temporaryDirectory))
                        {
                            string manifestPath = Path.Combine(temporaryDirectory,
                                                               manifestFilename);
                            if (File.Exists(manifestPath))
                            {
                                string manifest = File.ReadAllText(manifestPath);
                                explode = manifest.IndexOf("${applicationId}") >= 0;
                            }
                            aarData.modificationTime = File.GetLastWriteTime(aarFile);
                        }
                    }
                    catch (System.Exception e)
                    {
                        Debug.Log("Unable to examine AAR file " + aarFile + ", err: " + e);
                        throw e;
                    }
                    finally
                    {
                        PlayServicesSupport.DeleteExistingFileOrDirectory(temporaryDirectory);
                    }
                }
            }
            aarData.explode         = explode;
            aarExplodeData[aarFile] = aarData;
            return(explode);
        }
コード例 #10
0
        public static void OnPostProcessUpdateProjectDeps(
            BuildTarget buildTarget, string pathToBuiltProject)
        {
            if (!InjectDependencies())
            {
                return;
            }

            // If the Pods directory does not exist, the pod download step
            // failed.
            var podsDir = Path.Combine(pathToBuiltProject, "Pods");

            if (!Directory.Exists(podsDir))
            {
                return;
            }

            Directory.CreateDirectory(Path.Combine(pathToBuiltProject,
                                                   "Frameworks"));
            Directory.CreateDirectory(Path.Combine(pathToBuiltProject,
                                                   "Resources"));

            string pbxprojPath = GetProjectPath(pathToBuiltProject);
            var    project     = new UnityEditor.iOS.Xcode.PBXProject();

            project.ReadFromString(File.ReadAllText(pbxprojPath));
            string target = project.TargetGuidByName(TARGET_NAME);

            HashSet <string> frameworks = new HashSet <string>();
            HashSet <string> linkFlags  = new HashSet <string>();

            foreach (var frameworkFullPath in
                     Directory.GetDirectories(podsDir, "*.framework",
                                              SearchOption.AllDirectories))
            {
                string frameworkName     = new DirectoryInfo(frameworkFullPath).Name;
                string destFrameworkPath = Path.Combine("Frameworks",
                                                        frameworkName);
                string destFrameworkFullPath = Path.Combine(pathToBuiltProject,
                                                            destFrameworkPath);
                // Only move this framework if it contains a library.
                // Skip frameworks that consist of just resources, they're handled
                // in a separate import step.
                if (!File.Exists(Path.Combine(
                                     frameworkFullPath,
                                     Path.GetFileName(frameworkFullPath)
                                     .Replace(".framework", ""))))
                {
                    continue;
                }

                PlayServicesSupport.DeleteExistingFileOrDirectory(
                    destFrameworkFullPath);
                Directory.Move(frameworkFullPath, destFrameworkFullPath);
                project.AddFileToBuild(
                    target,
                    project.AddFile(destFrameworkPath,
                                    destFrameworkPath,
                                    UnityEditor.iOS.Xcode.PBXSourceTree.Source));

                string moduleMapPath =
                    Path.Combine(Path.Combine(destFrameworkFullPath, "Modules"),
                                 "module.modulemap");

                if (File.Exists(moduleMapPath))
                {
                    // Parse the modulemap, format spec here:
                    // http://clang.llvm.org/docs/Modules.html#module-map-language
                    using (StreamReader moduleMapFile =
                               new StreamReader(moduleMapPath)) {
                        string line;
                        char[] delim = { ' ' };
                        while ((line = moduleMapFile.ReadLine()) != null)
                        {
                            string[] items = line.TrimStart(delim).Split(delim, 2);
                            if (items.Length > 1)
                            {
                                if (items[0] == "link")
                                {
                                    if (items[1].StartsWith("framework"))
                                    {
                                        items = items[1].Split(delim, 2);
                                        frameworks.Add(items[1].Trim(
                                                           new char[] { '\"' }) + ".framework");
                                    }
                                    else
                                    {
                                        linkFlags.Add("-l" + items[1]);
                                    }
                                }
                            }
                        }
                    }
                }

                string resourcesFolder = Path.Combine(destFrameworkFullPath,
                                                      "Resources");
                if (Directory.Exists(resourcesFolder))
                {
                    string[] resFiles   = Directory.GetFiles(resourcesFolder);
                    string[] resFolders =
                        Directory.GetDirectories(resourcesFolder);
                    foreach (var resFile in resFiles)
                    {
                        string destFile = Path.Combine("Resources",
                                                       Path.GetFileName(resFile));
                        File.Copy(resFile, Path.Combine(pathToBuiltProject,
                                                        destFile), true);
                        project.AddFileToBuild(
                            target, project.AddFile(
                                destFile, destFile,
                                UnityEditor.iOS.Xcode.PBXSourceTree.Source));
                    }
                    foreach (var resFolder in resFolders)
                    {
                        string destFolder =
                            Path.Combine("Resources",
                                         new DirectoryInfo(resFolder).Name);
                        string destFolderFullPath =
                            Path.Combine(pathToBuiltProject, destFolder);
                        PlayServicesSupport.DeleteExistingFileOrDirectory(
                            destFolderFullPath);
                        Directory.Move(resFolder, destFolderFullPath);
                        project.AddFileToBuild(
                            target, project.AddFile(
                                destFolder, destFolder,
                                UnityEditor.iOS.Xcode.PBXSourceTree.Source));
                    }
                }
            }

            foreach (var framework in frameworks)
            {
                project.AddFrameworkToProject(target, framework, false);
            }
            foreach (var linkFlag in linkFlags)
            {
                project.AddBuildProperty(target, "OTHER_LDFLAGS", linkFlag);
            }
            File.WriteAllText(pbxprojPath, project.WriteToString());
        }
コード例 #11
0
        // Private method to avoid too deeply nested code in "DoResolution".
        private void GradleResolve(AndroidSdkPackageCollection packages,
                                   PlayServicesSupport svcSupport, string destinationDirectory,
                                   System.Action resolutionComplete)
        {
            string errorOutro = "make sure you have the latest version of this plugin and if you " +
                                "still get this error, report it in a a bug here:\n" +
                                "https://github.com/googlesamples/unity-jar-resolver/issues\n";
            string errorIntro = null;

            int    targetSdkVersion  = UnityCompat.GetAndroidTargetSDKVersion();
            string buildToolsVersion = null;

            if (targetSdkVersion < 0)
            {
                // A value of -1 means the targetSDK Version enum returned "Auto"
                // instead of an actual version, so it's up to us to actually figure it out.
                targetSdkVersion = GetLatestInstalledAndroidPlatformVersion(packages);
                PlayServicesSupport.Log(
                    String.Format("TargetSDK is set to Auto-detect, and the latest Platform has been " +
                                  "detected as: android-{0}", targetSdkVersion),
                    level: PlayServicesSupport.LogLevel.Info, verbose: true);

                errorIntro = String.Format("The Target SDK is set to automatically pick the highest " +
                                           "installed platform in the Android Player Settings, which appears to be " +
                                           "\"android-{0}\". This requires build-tools with at least the same version, " +
                                           "however ", targetSdkVersion);
            }
            else
            {
                errorIntro = String.Format("The target SDK version is set in the Android Player " +
                                           "Settings to \"android-{0}\" which requires build tools with " +
                                           "at least the same version, however ", targetSdkVersion);
            }

            // You can use a higher version of the build-tools than your compileSdkVersion, in order
            // to pick up new/better compiler while not changing what you build your app against. --Xav
            // https://stackoverflow.com/a/24523113
            // Implicitly Xav is also saying, you can't use a build tool version less than the
            // platform level you're building. This is backed up from testing.
            if (targetSdkVersion > TESTED_BUILD_TOOLS_VERSION_MAJOR)
            {
                buildToolsVersion = GetLatestMinorBuildToolsVersion(packages, targetSdkVersion);

                if (buildToolsVersion == null)
                {
                    PlayServicesSupport.Log(errorIntro + String.Format("no build-tools are available " +
                                                                       "at this level in the sdk manager. This plugin has been tested with " +
                                                                       "platforms up to android-{0} using build-tools {0}.{1}.{2}. You can try " +
                                                                       "selecting a lower targetSdkVersion in the Android Player Settings.  Please ",
                                                                       TESTED_BUILD_TOOLS_VERSION_MAJOR, TESTED_BUILD_TOOLS_VERSION_MINOR,
                                                                       TESTED_BUILD_TOOLS_VERSION_REV) + errorOutro,
                                            level: PlayServicesSupport.LogLevel.Error);
                    return;
                }
                else
                {
                    PlayServicesSupport.Log(errorIntro + String.Format("this plugin has only been " +
                                                                       "tested with build-tools up to version {0}.{1}.{2}. Corresponding " +
                                                                       "build-tools version {3} will be used, however this is untested with this " +
                                                                       "plugin and MAY NOT WORK! If you have trouble, please select a target SDK " +
                                                                       "version at or below \"android-{0}\". If you need to get this working with " +
                                                                       "the latest platform, please ",
                                                                       TESTED_BUILD_TOOLS_VERSION_MAJOR,
                                                                       TESTED_BUILD_TOOLS_VERSION_MINOR,
                                                                       TESTED_BUILD_TOOLS_VERSION_REV,
                                                                       buildToolsVersion) + errorOutro, level: PlayServicesSupport.LogLevel.Warning);
                }
            }

            if (buildToolsVersion == null)
            {
                // Use the tested build tools version, which we know will be able to handle
                // this targetSDK version.
                buildToolsVersion = String.Format("{0}.{1}.{2}", TESTED_BUILD_TOOLS_VERSION_MAJOR,
                                                  TESTED_BUILD_TOOLS_VERSION_MINOR,
                                                  TESTED_BUILD_TOOLS_VERSION_REV);
                // We don't have to bother with checking if it's installed because gradle actually
                // does that for us.
            }

            string minSdkVersion = UnityCompat.GetAndroidMinSDKVersion().ToString();

            var config = new Dictionary <string, string>()
            {
                { "app_id", UnityCompat.ApplicationId },
                { "sdk_version", targetSdkVersion.ToString() },
                { "min_sdk_version", minSdkVersion },
                { "build_tools_version", buildToolsVersion },
                { "android_sdk_dir", svcSupport.SDK }
            };

            // This creates an enumerable of strings with the json lines for each dep like this:
            // "[\"namespace\", \"package\", \"version\"]"
            var dependencies = svcSupport.LoadDependencies(true, true, false);
            var depLines     = from d in dependencies
                               select "[" + ToJSONList(DepsVersionAsArray(d.Value)) + "]";
            // Get a flattened list of dependencies, excluding any with the "$SDK" path variable,
            // since those will automatically be included in the gradle build.
            var repoLines = new HashSet <string>(
                dependencies.SelectMany(d => d.Value.Repositories)
                .Where(s => !s.Contains(PlayServicesSupport.SdkVariable)));

            var proguard_config_paths = new List <string>()
            {
                Path.Combine(GRADLE_SCRIPT_LOCATION, PROGUARD_UNITY_CONFIG),
                Path.Combine(GRADLE_SCRIPT_LOCATION, PROGUARD_MSG_FIX_CONFIG)
            };

            // Build the full json config as a string.
            string json_config = @"{{
""config"": {{
{0}
}},
""project_deps"": [
{1}
],
""extra_m2repositories"": [
{2}
],
""extra_proguard_configs"": [
{3}
]
}}";

            json_config = String.Format(json_config, ToJSONDictionary(config),
                                        ToJSONList(depLines, ",\n", 4, true),
                                        ToJSONList(repoLines, ",\n", 4),
                                        ToJSONList(proguard_config_paths, ",\n", 4));

            // Escape any literal backslashes (such as those from paths on windows), since we want to
            // preserve them when reading the config as backslashes and not interpret them
            // as escape characters.
            json_config = json_config.Replace(@"\", @"\\");

            System.IO.File.WriteAllText(GENERATE_CONFIG_PATH, json_config);
            var outDir = Path.Combine(destinationDirectory, GENERATE_GRADLE_OUTPUT_DIR);

            RunGenGradleScript(
                " -c \"" + GENERATE_CONFIG_PATH + "\"" +
                " -b \"" + GENERATE_GRADLE_BUILD_PATH + "\"" +
                " -o \"" + outDir + "\"",
                (result) => {
                if (result.exitCode == 0)
                {
                    var currentAbi = PlayServicesResolver.AndroidTargetDeviceAbi;
                    var activeAbis = GetSelectedABIDirs(currentAbi);
                    var libsDir    = Path.Combine(outDir, "libs");
                    if (Directory.Exists(libsDir))
                    {
                        foreach (var directory in Directory.GetDirectories(libsDir))
                        {
                            var abiDir = Path.GetFileName(directory).ToLower();
                            if (!activeAbis.Contains(abiDir))
                            {
                                PlayServicesSupport.DeleteExistingFileOrDirectory(
                                    directory, includeMetaFiles: true);
                            }
                        }
                    }
                    if (Directory.Exists(outDir))
                    {
                        PlayServicesResolver.LabelAssets(new [] { outDir }, true, true);
                    }
                    AssetDatabase.Refresh();
                    resolutionComplete();
                }
            });
        }