/// <summary> /// Initializes the <see cref="GooglePlayGames.BackgroundResolution"/> class. /// </summary> static BackgroundResolution() { svcSupport = PlayServicesSupport.CreateInstance( "Google.GPGS", EditorPrefs.GetString("AndroidSdkRoot"), "ProjectSettings"); AddDependencies(); }
public void TestNonActiveClient() { PlayServicesSupport client1 = TestData.CreateInstance(instanceName: "client1"); PlayServicesSupport client2 = TestData.CreateInstance(instanceName: "client2"); client1.DependOn(TestData.PackageId.Artifact, "1+"); client2.DependOn(TestData.PackageId.SubDep, "1.1.0"); // now make a third client with no dependencies and make sure it // sees client1 & 2 PlayServicesSupport client3 = TestData.CreateInstance(instanceName: "client3"); // now check that client 2 sees them also Dictionary <string, Dependency> deps = client3.ResolveDependencies(true); Assert.NotNull(deps); Dependency d = deps[TestData.PackageId.Artifact.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.SubDep.VersionlessKey()]; Assert.AreEqual("1.1.0", d.BestVersion); }
/// <summary> /// Find a tool in the Android SDK. /// </summary> /// <param name="svcSupport">PlayServicesSupport instance used to retrieve the SDK /// path. </param> /// <param name="toolName">Name of the tool to search for.</param> /// <returns>String with the path to the tool if found, null otherwise.</returns> internal static string FindAndroidSdkTool(PlayServicesSupport svcSupport, string toolName) { string toolPath = null; string sdkPath = svcSupport.SDK; if (sdkPath == null || sdkPath == "") { Debug.LogWarning(PlayServicesSupport.AndroidSdkConfigurationError + " Will fallback to searching for " + toolName + " in the system path."); } else { toolPath = Path.Combine( sdkPath, Path.Combine( "tools", toolName + CommandLine.GetExecutableExtension())); } if (toolPath == null || !File.Exists(toolPath)) { toolPath = CommandLine.FindExecutable(toolName); } return(toolPath); }
public void TestUseLatest() { PlayServicesSupport support = PlayServicesSupport.CreateInstance( "testInstance", "../../testData", Path.GetTempPath()); Assert.True(Directory.Exists(support.SDK)); support.DependOn("test", "artifact", "1+"); support.DependOn("test", "subdep", "1.1.0"); support.DependOn("test", "transdep", "LATEST"); Dictionary <string, Dependency> deps = support.ResolveDependencies(true); Assert.NotNull(deps); Dependency d = deps["test:artifact"]; Assert.True(d.BestVersion == "8.1.0"); d = deps["test:subdep"]; Assert.True(d.BestVersion == "1.1.0"); }
public void TestCustomRepoPath() { string[] repos = { Path.Combine(TestData.PATH, "extras/google/m2repository") }; PlayServicesSupport support = TestData.CreateInstance( sdkPath: "..", additionalRepositories: repos); Assert.True(Directory.Exists(support.SDK)); support.ClearDependencies(); support.DependOn(TestData.PackageId.Artifact, "LATEST"); Dictionary <string, Dependency> deps = support.ResolveDependencies(false); Assert.NotNull(deps); // Verify one dependency is returned at the expected version. Assert.AreEqual(1, deps.Count); IEnumerator <Dependency> iter = deps.Values.GetEnumerator(); iter.MoveNext(); Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, iter.Current.BestVersion); }
public void TestNonActiveClient() { PlayServicesSupport client1 = PlayServicesSupport.CreateInstance( "client1", "../../testData", Path.GetTempPath()); PlayServicesSupport client2 = PlayServicesSupport.CreateInstance( "client2", "../../testData", Path.GetTempPath()); client1.ResetDependencies(); client2.ResetDependencies(); client1.DependOn("test", "artifact", "1+"); client2.DependOn("test", "subdep", "1.1.0"); // now make a third client with no dependencies and make sure it // sees client1 & 2 PlayServicesSupport client3 = PlayServicesSupport.CreateInstance( "client3", "../../testData", Path.GetTempPath()); // now check that client 2 sees them also Dictionary <string, Dependency> deps = client3.ResolveDependencies(true); Assert.NotNull(deps); Dependency d = deps["test:artifact"]; Assert.True(d.BestVersion == "8.1.0"); d = deps["test:subdep"]; Assert.True(d.BestVersion == "1.1.0"); }
/// <summary> /// Perform the resolution and the exploding/cleanup as needed. /// </summary> public override void DoResolution(PlayServicesSupport svcSupport, string destinationDirectory, PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation) { // Get the collection of dependencies that need to be copied. Dictionary <string, Dependency> deps; try { deps = svcSupport.ResolveDependencies(true); } catch (ResolutionException) { return; } // Copy the list svcSupport.CopyDependencies(deps, destinationDirectory, handleOverwriteConfirmation); // we want to look at all the .aars to decide to explode or not. // Some aars have variables in their AndroidManifest.xml file, // e.g. ${applicationId}. Unity does not understand how to process // these, so we handle it here. ProcessAars(destinationDirectory); }
/// <summary> /// Find a tool in the Android SDK. /// </summary> /// <param name="toolName">Name of the tool to search for.</param> /// <param name="sdkPath">SDK path to search for the tool. If this is null or empty, the // system path is searched instead.</param> /// <returns>String with the path to the tool if found, null otherwise.</returns> private static string FindAndroidSdkTool(string toolName, string sdkPath = null) { if (String.IsNullOrEmpty(sdkPath)) { PlayServicesSupport.Log(String.Format( "{0}\n" + "Falling back to searching for the Android SDK tool {1} in the system path.", PlayServicesSupport.AndroidSdkConfigurationError, toolName)); } else { var extensions = new List <string> { CommandLine.GetExecutableExtension() }; if (UnityEngine.RuntimePlatform.WindowsEditor == UnityEngine.Application.platform) { extensions.AddRange(new [] { ".bat", ".cmd" }); } foreach (var dir in new [] { "tools", Path.Combine("tools", "bin") }) { foreach (var extension in extensions) { var currentPath = Path.Combine(sdkPath, Path.Combine(dir, toolName + extension)); if (File.Exists(currentPath)) { return(currentPath); } } } } var toolPath = CommandLine.FindExecutable(toolName); return(toolPath != null && File.Exists(toolPath) ? toolPath : null); }
public void TestSimpleResolveDependencies() { PlayServicesSupport support = PlayServicesSupport.CreateInstance( "testInstance", "../../testData", Path.GetTempPath()); Assert.True(Directory.Exists(support.SDK)); // happy path support.ResetDependencies(); support.DependOn("test", "artifact", "LATEST"); Dictionary <string, Dependency> deps = support.ResolveDependencies(false); Assert.NotNull(deps); // should be only 1 and version 8.1 Assert.True(deps.Count == 1); IEnumerator <Dependency> iter = deps.Values.GetEnumerator(); iter.MoveNext(); Assert.True(iter.Current.BestVersion == "8.1.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. if (Directory.Exists(dirPath)) { PlayServicesSupport.DeleteExistingFileOrDirectory(dirPath); } } aarExplodeData[f].path = targetPath; aarExplodeData[f].bundleId = PlayerSettings.bundleIdentifier; } }
public void TestLatestResolution() { PlayServicesSupport client1 = PlayServicesSupport.CreateInstance( "client1", "../../testData", Path.GetTempPath()); client1.ResetDependencies(); //trans dep needs subdep 0.9 client1.DependOn("test", "transdep", "1.0.0"); // so top level require subdep 1.0 or greater client1.DependOn("test", "subdep", "1.0+"); Dictionary <string, Dependency> deps = null; // this should fail since we need 0.9 and 1.1.0 ResolutionException ex = null; try { deps = client1.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex, "Expected exception, but got none"); // now try with useLatest == true, should have no exception ex = null; try { deps = client1.ResolveDependencies(true); } catch (ResolutionException e) { ex = e; } Assert.Null(ex, "unexpected exception"); Assert.NotNull(deps); Assert.IsTrue(deps.Count == 2, "Expected 2 dependencies, got " + deps.Count); // now check that that all the dependencies have the correct // best version Dependency d = deps["test:transdep"]; Assert.NotNull(d, "could not find transdep"); Assert.IsTrue(d.BestVersion == "1.0.0", "Expected version 1.0.0, got " + d.BestVersion); d = deps["test:subdep"]; Assert.NotNull(d, "could not find subdep"); Assert.IsTrue(d.BestVersion == "1.1.0", "Expected version 1.1.0, got " + d.BestVersion); // try without wildcard client1.ResetDependencies(); //trans dep needs subdep 0.9 client1.DependOn("test", "transdep", "1.0.0"); // so top level requires exactly subdep 1.1.0. client1.DependOn("test", "subdep", "1.1.0"); ex = null; try { deps = client1.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex, "Expected exception, but got none"); ex = null; try { deps = client1.ResolveDependencies(true); } catch (ResolutionException e) { ex = e; } Assert.Null(ex, "unexpected exception"); Assert.NotNull(deps); Assert.IsTrue(deps.Count == 2, "Expected 2 dependencies, got " + deps.Count); // now check that that all the dependencies have the correct // best version d = deps["test:transdep"]; Assert.NotNull(d, "could not find transdep"); Assert.IsTrue(d.BestVersion == "1.0.0", "Expected version 1.0.0, got " + d.BestVersion); d = deps["test:subdep"]; Assert.NotNull(d, "could not find subdep"); Assert.IsTrue(d.BestVersion == "1.1.0", "Expected version 1.1.0, got " + d.BestVersion); }
/// <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); }
// 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()); }
/// <summary> /// Resolve dependencies. /// </summary> /// <param name="resolutionComplete">Delegate called when resolution is complete /// with a parameter that indicates whether it succeeded or failed.</param> /// <param name="forceResolution">Whether resolution should be executed when no dependencies /// have changed. This is useful if a dependency specifies a wildcard in the version /// expression.</param> private static void ResolveUnsafe(Action <bool> resolutionComplete = null, bool forceResolution = false) { JavaUtilities.CheckJdkForApiLevel(); if (!buildConfigChanged) { DeleteFiles(Resolver.OnBuildSettings()); } xmlDependencies.ReadAll(logger); if (forceResolution) { DeleteLabeledAssets(); } else { // Only resolve if user specified dependencies changed or the output files // differ to what is present in the project. var currentState = DependencyState.GetState(); var previousState = DependencyState.ReadFromFile(); if (previousState != null) { if (currentState.Equals(previousState)) { if (resolutionComplete != null) { resolutionComplete(true); } return; } // Delete all labeled assets to make sure we don't leave any stale transitive // dependencies in the project. DeleteLabeledAssets(); } } System.IO.Directory.CreateDirectory(GooglePlayServices.SettingsDialog.PackageDir); PlayServicesSupport.Log("Resolving...", verbose: true); lastError = ""; Resolver.DoResolution(svcSupport, GooglePlayServices.SettingsDialog.PackageDir, (oldDependency, newDependency) => { return(Resolver.ShouldReplaceDependency(oldDependency, newDependency)); }, () => { System.Action complete = () => { bool succeeded = String.IsNullOrEmpty(lastError); AssetDatabase.Refresh(); DependencyState.GetState().WriteToFile(); PlayServicesSupport.Log(String.Format( "Resolution {0}.\n\n{1}", succeeded ? "Succeeded" : "Failed", lastError), verbose: true); if (resolutionComplete != null) { resolutionComplete(succeeded); } }; updateQueue.Enqueue(complete); }); }
/// <summary> /// Programmatically add dependencies. /// NOTE: This is the deprecated way of adding dependencies and will likely be removed in /// future. /// </summary> private static void SetupDependencies() { PlayServicesSupport.CreateInstance("Test", null, "ProjectSettings").DependOn( "com.google.firebase", "firebase-common", "16.0.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); PlayServicesResolver.Log( String.Format("TargetSDK is set to Auto-detect, and the latest Platform has " + "been detected as: android-{0}", targetSdkVersion), level: LogLevel.Verbose); 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) { PlayServicesResolver.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: LogLevel.Error); return; } else { PlayServicesResolver.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: 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 = PlayServicesSupport.GetAllDependencies(); 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)) { FileUtils.DeleteExistingFileOrDirectory(directory); } } } if (Directory.Exists(outDir)) { PlayServicesResolver.LabelAssets(new [] { outDir }, true, true); } AssetDatabase.Refresh(); resolutionComplete(); } }); }
/// <summary> /// Does the resolution of the play-services aars. /// </summary> /// <param name="svcSupport">Svc support.</param> /// <param name="destinationDirectory">Destination directory.</param> /// <param name="handleOverwriteConfirmation">Handle overwrite confirmation.</param> /// <param name="resolutionComplete">Delegate called when resolution is complete.</param> public override void DoResolution(PlayServicesSupport svcSupport, string destinationDirectory, PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation, System.Action resolutionComplete) { string targetSdkVersion = UnityCompat.GetAndroidPlatform().ToString(); string minSdkVersion = UnityCompat.GetAndroidMinSDKVersion().ToString(); string buildToolsVersion = UnityCompat.GetAndroidBuildToolsVersion(); var config = new Dictionary <string, string>() { { "app_id", UnityCompat.ApplicationId }, { "sdk_version", targetSdkVersion }, { "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)); System.IO.File.WriteAllText(GENERATE_CONFIG_PATH, json_config); RunGenGradleScript( " -c \"" + GENERATE_CONFIG_PATH + "\"" + " -b \"" + GENERATE_GRADLE_BUILD_PATH + "\"" + " -o \"" + Path.Combine(destinationDirectory, GENERATE_GRADLE_OUTPUT_DIR) + "\""); }
/// <summary> /// Perform the resolution and the exploding/cleanup as needed. /// </summary> public override void DoResolution( PlayServicesSupport svcSupport, string destinationDirectory, PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation, System.Action resolutionComplete) { System.Action resolve = () => { DoResolutionNoAndroidPackageChecks(svcSupport, destinationDirectory, handleOverwriteConfirmation); resolutionComplete(); }; // Set of packages that need to be installed. Dictionary <string, bool> installPackages = new Dictionary <string, bool>(); // Retrieve the set of required packages and whether they're installed. Dictionary <string, Dictionary <string, bool> > requiredPackages = new Dictionary <string, Dictionary <string, bool> >(); foreach (Dependency dependency in svcSupport.LoadDependencies(true, keepMissing: true).Values) { if (dependency.PackageIds != null) { foreach (string packageId in dependency.PackageIds) { Dictionary <string, bool> dependencySet; if (!requiredPackages.TryGetValue(packageId, out dependencySet)) { dependencySet = new Dictionary <string, bool>(); } dependencySet[dependency.Key] = false; requiredPackages[packageId] = dependencySet; // If the dependency is missing, add it to the set that needs to be // installed. if (System.String.IsNullOrEmpty(dependency.BestVersionPath)) { installPackages[packageId] = false; } } } } // If no packages need to be installed or Android SDK package installation is disabled. if (installPackages.Count == 0 || !AndroidPackageInstallationEnabled()) { // Report missing packages as warnings and try to resolve anyway. foreach (string pkg in requiredPackages.Keys) { string depString = System.String.Join( ", ", CollectionToArray(requiredPackages[pkg].Keys)); if (installPackages.ContainsKey(pkg) && depString.Length > 0) { Debug.LogWarning(pkg + " not installed or out of date! This is " + "required by the following dependencies " + depString); } } // Attempt resolution. resolve(); return; } // Find the Android SDK manager. string sdkPath = svcSupport.SDK; string androidTool = FindAndroidSdkTool(svcSupport, "android"); if (androidTool == null || sdkPath == null || sdkPath == "") { Debug.LogError("Unable to find the Android SDK manager tool. " + "Required Android packages (" + System.String.Join(", ", CollectionToArray(installPackages.Keys)) + ") can not be installed. " + PlayServicesSupport.AndroidSdkConfigurationError); return; } // Get the set of available and installed packages. GetAvailablePackages( androidTool, svcSupport, (Dictionary <string, bool> packageInfo) => { if (packageInfo == null) { return; } // Filter the set of packages to install by what is available. foreach (string pkg in requiredPackages.Keys) { bool installed = false; string depString = System.String.Join( ", ", CollectionToArray(requiredPackages[pkg].Keys)); if (packageInfo.TryGetValue(pkg, out installed)) { if (!installed) { installPackages[pkg] = false; Debug.LogWarning(pkg + " not installed or out of date! " + "This is required by the following " + "dependencies " + depString); } } else { Debug.LogWarning(pkg + " referenced by " + depString + " not available in the Android SDK. This " + "package will not be installed."); installPackages.Remove(pkg); } } if (installPackages.Count == 0) { resolve(); return; } // Start installation. string installPackagesString = System.String.Join( ",", CollectionToArray(installPackages.Keys)); string packagesCommand = "update sdk -a -u -t " + installPackagesString; CommandLineDialog window = CommandLineDialog.CreateCommandLineDialog( "Install Android SDK packages"); window.summaryText = "Retrieving licenses..."; window.modal = false; window.progressTitle = window.summaryText; window.RunAsync( androidTool, packagesCommand, (CommandLine.Result getLicensesResult) => { // Get the start of the license text. int licenseTextStart = getLicensesResult.stdout.IndexOf("--------"); if (getLicensesResult.exitCode != 0 || licenseTextStart < 0) { window.Close(); Debug.LogError("Unable to retrieve licenses for packages " + installPackagesString); return; } // Remove the download output from the string. string licenseText = getLicensesResult.stdout.Substring( licenseTextStart); window.summaryText = ("License agreement(s) required to install " + "Android SDK packages"); window.bodyText = licenseText; window.yesText = "agree"; window.noText = "decline"; window.result = false; window.Repaint(); window.buttonClicked = (TextAreaDialog dialog) => { if (!dialog.result) { window.Close(); return; } window.summaryText = "Installing Android SDK packages..."; window.bodyText = ""; window.yesText = ""; window.noText = ""; window.buttonClicked = null; window.progressTitle = window.summaryText; window.autoScrollToBottom = true; window.Repaint(); // Kick off installation. ((CommandLineDialog)window).RunAsync( androidTool, packagesCommand, (CommandLine.Result updateResult) => { window.Close(); if (updateResult.exitCode == 0) { resolve(); } else { Debug.LogError("Android SDK update failed. " + updateResult.stderr + "(" + updateResult.exitCode.ToString() + ")"); } }, ioHandler: (new LicenseResponder(true)).AggregateLine, maxProgressLines: 500); }; }, ioHandler: (new LicenseResponder(false)).AggregateLine, maxProgressLines: 250); }); }
/// <summary> /// Registers the dependencies. /// </summary> public static void RegisterDependencies() { // Setup the resolver using reflection as the module may not be // available at compile time. Type playServicesSupport = VersionHandler.FindClass( "Google.JarResolver", "Google.JarResolver.PlayServicesSupport"); if (playServicesSupport == null) { return; } if (svcSupport == null) { svcSupport = (PlayServicesSupport)VersionHandler.InvokeStaticMethod( playServicesSupport, "CreateInstance", new object[] { "GooglePlayGames", EditorPrefs.GetString("AndroidSdkRoot"), "ProjectSettings" }); } VersionHandler.InvokeInstanceMethod( svcSupport, "DependOn", new object[] { "com.google.android.gms", "play-services-games", PluginVersion.PlayServicesVersionConstraint }, new Dictionary <string, object> { { "packageIds", new[] { "extra-google-m2repository" } } }); VersionHandler.InvokeInstanceMethod( svcSupport, "DependOn", new object[] { "com.google.android.gms", "play-services-nearby", PluginVersion.PlayServicesVersionConstraint }, new Dictionary <string, object> { { "packageIds", new[] { "extra-google-m2repository" } } }); // Auth is needed for getting the token and email. VersionHandler.InvokeInstanceMethod( svcSupport, "DependOn", new object[] { "com.google.android.gms", "play-services-auth", PluginVersion.PlayServicesVersionConstraint }, new Dictionary <string, object> { { "packageIds", new[] { "extra-google-m2repository" } } }); // if google+ is needed, add it if (GameInfo.RequireGooglePlus()) { VersionHandler.InvokeInstanceMethod( svcSupport, "DependOn", new object[] { "com.google.android.gms", "play-services-plus", PluginVersion.PlayServicesVersionConstraint }, new Dictionary <string, object> { { "packageIds", new[] { "extra-google-m2repository" } } }); } VersionHandler.InvokeInstanceMethod( svcSupport, "DependOn", new object[] { "com.android.support", "support-v4", "23.1+" }, new Dictionary <string, object> { { "packageIds", new[] { "extra-android-m2repository" } } }); }
/// <summary> /// Compatibility method for synchronous implementations of DoResolution(). /// </summary> /// <param name="svcSupport">Svc support.</param> /// <param name="destinationDirectory">Destination directory.</param> public virtual void DoResolution(PlayServicesSupport svcSupport, string destinationDirectory) { DoResolution(svcSupport, destinationDirectory, () => {}); }
public void TestResolveDependencies() { PlayServicesSupport support = PlayServicesSupport.CreateInstance( "testInstance", "../../testData", Path.GetTempPath()); Assert.True(Directory.Exists(support.SDK)); support.ResetDependencies(); // happy path support.DependOn("test", "artifact", "LATEST"); Dictionary <string, Dependency> deps = support.ResolveDependencies(false); Assert.NotNull(deps); // should be only 1 and version 8.1 Assert.True(deps.Count == 1); IEnumerator <Dependency> iter = deps.Values.GetEnumerator(); iter.MoveNext(); Assert.True(iter.Current.BestVersion == "8.1.0"); // check dependency that has transitive dependencies support.DependOn("test", "transdep", "1.0"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); // 1 is the previous test, then 2 for transdep and subdep. Assert.True(deps.Count == 3); Dependency d = deps["test:artifact"]; Assert.True(d.BestVersion == "8.1.0"); d = deps["test:transdep"]; Assert.AreEqual(d.BestVersion, "1.0.0"); d = deps["test:subdep"]; Assert.True(d.BestVersion == "0.9"); // check constraining down to a later version - the LATEST // will make this fail. support.DependOn("test", "artifact", "7.0.0"); ResolutionException ex = null; try { deps = support.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex); // Now add it as 7+ and LATEST and it will work. support.ResetDependencies(); support.DependOn("test", "artifact", "LATEST"); support.DependOn("test", "artifact", "7+"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps["test:artifact"]; Assert.True(d.BestVersion == "8.1.0"); // Test downversioning. support.ResetDependencies(); support.DependOn("test", "artifact", "1+"); support.DependOn("test", "artifact", "2+"); support.DependOn("test", "artifact", "7.0.0"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps["test:artifact"]; Assert.True(d.BestVersion == "7.0.0"); // test the transitive dep influencing a top level support.ResetDependencies(); support.DependOn("test", "artifact", "1+"); support.DependOn("test", "subdep", "0+"); support.DependOn("test", "transdep", "LATEST"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps["test:artifact"]; Assert.True(d.BestVersion == "8.1.0"); d = deps["test:subdep"]; Assert.True(d.BestVersion == "0.9"); }
public void TestLatestResolution() { PlayServicesSupport client1 = TestData.CreateInstance(); // TransDep needs SubDep 0.9. client1.DependOn(TestData.PackageId.TransDep, "1.0.0"); // We'll set the top level dependency to require SubDep 1.0 or greater. client1.DependOn(TestData.PackageId.SubDep, "1.0+"); Dictionary <string, Dependency> deps = null; // The following should fail since we need SubDep 0.9 and SubDep 1.1.0. ResolutionException ex = null; try { deps = client1.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex, "Expected exception, but got none"); // now try with useLatest == true, should have no exception ex = null; try { deps = client1.ResolveDependencies(true); } catch (ResolutionException e) { ex = e; } Assert.Null(ex, "unexpected exception"); Assert.NotNull(deps); // Should have TransDep and SubDep. Assert.AreEqual(2, deps.Count, String.Join(", ", new List <string>(deps.Keys).ToArray())); // Now check that that all the dependencies have the correct best version. Dependency d = deps[TestData.PackageId.TransDep.VersionlessKey()]; Assert.NotNull(d, "could not find transdep"); Assert.AreEqual(TestData.PackageId.TransDep.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.SubDep.VersionlessKey()]; Assert.NotNull(d, "could not find subdep"); Assert.AreEqual("1.1.0", d.BestVersion); // Try without version wildcard. client1.ClearDependencies(); // TransDep needs subdep 0.9. client1.DependOn(TestData.PackageId.TransDep, "1.0.0"); // Configure top level dependency to require exactly subdep 1.1.0. client1.DependOn(TestData.PackageId.SubDep, "1.1.0"); ex = null; try { deps = client1.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex, "Expected exception, but got none"); ex = null; try { deps = client1.ResolveDependencies(true); } catch (ResolutionException e) { ex = e; } Assert.Null(ex, "unexpected exception"); Assert.NotNull(deps); // Should contain TransDep and SubDep. Assert.AreEqual(2, deps.Count); // now check that that all the dependencies have the correct // best version d = deps[TestData.PackageId.TransDep.VersionlessKey()]; Assert.NotNull(d, "could not find transdep"); Assert.AreEqual(TestData.PackageId.TransDep.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.SubDep.VersionlessKey()]; Assert.NotNull(d, "could not find subdep"); Assert.AreEqual("1.1.0", d.BestVersion); }
public void TestResolveDependencies() { PlayServicesSupport support = TestData.CreateInstance(); Assert.True(Directory.Exists(support.SDK)); support.DependOn(TestData.PackageId.Artifact, "LATEST"); Dictionary <string, Dependency> deps = support.ResolveDependencies(false); Assert.NotNull(deps); // Verify one dependency is returned at the expected version. Assert.AreEqual(1, deps.Count); IEnumerator <Dependency> iter = deps.Values.GetEnumerator(); iter.MoveNext(); Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, iter.Current.BestVersion); // Check dependency with has transitive dependencies. support.DependOn(TestData.PackageId.TransDep, "1.0"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); // One dependency should be present from the previous test and an additional two // for the transdep and subdep. Assert.AreEqual(3, deps.Count); Dependency d = deps[TestData.PackageId.Artifact.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.TransDep.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.TransDep.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.SubDep.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.SubDep.Info().bestVersion, d.BestVersion); // check constraining down to a later version - the LATEST // will make this fail. support.DependOn(TestData.PackageId.Artifact, "7.0.0"); ResolutionException ex = null; try { deps = support.ResolveDependencies(false); } catch (ResolutionException e) { ex = e; } Assert.NotNull(ex); // Now add it as 7+ and LATEST and it will work. support.ClearDependencies(); support.DependOn(TestData.PackageId.Artifact, "LATEST"); support.DependOn(TestData.PackageId.Artifact, "7+"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps[TestData.PackageId.Artifact.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, d.BestVersion); // Test downversioning. support.ClearDependencies(); support.DependOn(TestData.PackageId.Artifact, "1+"); support.DependOn(TestData.PackageId.Artifact, "2+"); support.DependOn(TestData.PackageId.Artifact, "7.0.0"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps[TestData.PackageId.Artifact.VersionlessKey()]; Assert.AreEqual("7.0.0", d.BestVersion); // test the transitive dep influencing a top level support.ClearDependencies(); support.DependOn(TestData.PackageId.Artifact, "1+"); support.DependOn(TestData.PackageId.SubDep, "0+"); support.DependOn(TestData.PackageId.TransDep, "LATEST"); deps = support.ResolveDependencies(false); Assert.NotNull(deps); d = deps[TestData.PackageId.Artifact.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.Artifact.Info().bestVersion, d.BestVersion); d = deps[TestData.PackageId.SubDep.VersionlessKey()]; Assert.AreEqual(TestData.PackageId.SubDep.Info().bestVersion, d.BestVersion); }
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()); }
public void SetUp() { PlayServicesSupport.ResetDependencies(); }
/// <summary> /// Does the resolution of the play-services aars. /// </summary> /// <param name="svcSupport">Svc support.</param> /// <param name="destinationDirectory">Destination directory.</param> /// <param name="resolutionComplete">Delegate called when resolution is complete.</param> public virtual void DoResolution(PlayServicesSupport svcSupport, string destinationDirectory, System.Action resolutionComplete) { resolutionComplete(); }
/// <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); }
/// <summary> /// Does the resolution of the play-services aars. /// </summary> /// <param name="svcSupport">Svc support.</param> /// <param name="destinationDirectory">Destination directory.</param> /// <param name="handleOverwriteConfirmation">Handle overwrite confirmation.</param> public abstract void DoResolution(PlayServicesSupport svcSupport, string destinationDirectory, PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation);
/// <summary> /// Registers the android dependencies. /// </summary> public static void RegisterAndroidDependencies() { svcSupport = PlayServicesSupport.CreateInstance("FuseSDK", EditorPrefs.GetString("AndroidSdkRoot"), "ProjectSettings"); svcSupport.ClearDependencies(); svcSupport.DependOn("com.google.android.gms", "play-services-basement", "10+", packageIds: new string[] { "extra-google-m2repository" }); }