Play services support is a helper class for managing the Google play services and Android support libraries in a Unity project. This is done by using the Maven repositories that are part of the Android SDK. This class implements the logic of version checking, transitive dependencies, and updating a a directory to make sure that there is only one version of a dependency present.
 /// <summary>
 /// Initializes the <see cref="GooglePlayServices.PlayServicesResolver"/> class.
 /// </summary>
 static PlayServicesResolver()
 {
     svcSupport = PlayServicesSupport.CreateInstance(
         "PlayServicesResolver",
         EditorPrefs.GetString("AndroidSdkRoot"),
         "ProjectSettings");
 }
Exemple #2
0
        /// <summary>
        /// Initializes the <see cref="GooglePlayGames.BackgroundResolution"/> class.
        /// </summary>
        static BackgroundResolution()
        {
            svcSupport = PlayServicesSupport.CreateInstance(
                "Google.GPGS",
                EditorPrefs.GetString("AndroidSdkRoot"),
                "ProjectSettings");

            AddDependencies();
        }
        /// <summary>
        /// Initializes static members of the <see cref="SampleDependencies"/> class.
        /// </summary>
        static GPGSDependencies()
        {
            svcSupport = PlayServicesSupport.CreateInstance(
                                             PluginName,
                                             EditorPrefs.GetString("AndroidSdkRoot"),
                                             "ProjectSettings");

            RegisterDependencies();
        }
 /// <summary>
 /// Initializes static members of the <see cref="FuseSDKDependencies"/> class.
 /// </summary>
 static FuseSDKDependencies()
 {
     svcSupport = PlayServicesSupport.CreateInstance(PluginName, EditorPrefs.GetString("AndroidSdkRoot"), "ProjectSettings");
     svcSupport.ClearDependencies();
     svcSupport.DependOn("com.google.android.gms", "play-services-basement", "8.4.0");
     svcSupport.DependOn("com.android.support", "support-annotations", "23.4.0");
     svcSupport.DependOn("com.android.support", "support-v4", "23.4.0");
     svcSupport.DependOn("com.android.support", "recyclerview-v7", "23.4.0");
 }
        /// <summary>
        /// Initializes the <see cref="GooglePlayServices.PlayServicesResolver"/> class.
        /// </summary>
        static PlayServicesResolver()
        {
            svcSupport = PlayServicesSupport.CreateInstance(
                "PlayServicesResolver",
                EditorPrefs.GetString("AndroidSdkRoot"),
                "ProjectSettings",
                logger: UnityEngine.Debug.Log);

            EditorApplication.update -= AutoResolve;
            EditorApplication.update += AutoResolve;
            EditorApplication.update -= PollBundleId;
            EditorApplication.update += PollBundleId;
        }
        /// <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 =
                svcSupport.ResolveDependencies(true);

            // 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);
        }
Exemple #7
0
        /// <summary>
        /// Creates an instance of PlayServicesSupport.  This instance is
        /// used to add dependencies for the calling client and invoke the resolution.
        /// </summary>
        /// <returns>The instance.</returns>
        /// <param name="clientName">Client name.  Must be a valid filename.
        /// This is used to uniquely identify
        /// the calling client so that dependencies can be associated with a specific
        /// client to help in resetting dependencies.</param>
        /// <param name="sdkPath">Sdk path for Android SDK.</param>
        /// <param name="additionalRepositories">Array of additional repository paths. can be
        /// null</param>
        /// <param name="settingsDirectory">This parameter is obsolete.</param>
        /// <param name="logger">Delegate used to write messages to the log.</param>
        internal static PlayServicesSupport CreateInstance(
            string clientName,
            string sdkPath,
            string[] additionalRepositories,
            string settingsDirectory,
            LogMessage logger = null)
        {
            PlayServicesSupport instance = new PlayServicesSupport();

            PlayServicesSupport.logger = PlayServicesSupport.logger ?? logger;
            PlayServicesSupport.sdk    =
                String.IsNullOrEmpty(sdkPath) ? PlayServicesSupport.sdk : sdkPath;
            string badchars = new string(Path.GetInvalidFileNameChars());

            foreach (char ch in clientName)
            {
                if (badchars.IndexOf(ch) >= 0)
                {
                    throw new Exception("Invalid clientName: " + clientName);
                }
            }
            instance.clientName = clientName;

            var repoPaths = new List <string>();

            repoPaths.AddRange(additionalRepositories ?? new string[] {});
            // Add the standard repo paths from the Android SDK
            string sdkExtrasDir = Path.Combine(SdkVariable, "extras");

            repoPaths.AddRange(
                new string [] {
                Path.Combine(sdkExtrasDir, Path.Combine("android", "m2repository")),
                Path.Combine(sdkExtrasDir, Path.Combine("google", "m2repository"))
            });
            instance.repositoryPaths       = UniqueList(repoPaths);
            instances[instance.clientName] = instance;
            return(instance);
        }
Exemple #8
0
        /// <summary>
        /// Creates an instance of PlayServicesSupport.  This instance is
        /// used to add dependencies for the calling client and invoke the resolution.
        /// </summary>
        /// <returns>The instance.</returns>
        /// <param name="clientName">Client name.  Must be a valid filename.
        /// This is used to uniquely identify
        /// the calling client so that dependencies can be associated with a specific
        /// client to help in resetting dependencies.</param>
        /// <param name="sdkPath">Sdk path for Android SDK.</param>
        /// <param name="settingsDirectory">The relative path to the directory
        /// to save the settings.  For Unity projects this is "ProjectSettings"</param>
        public static PlayServicesSupport CreateInstance(
            string clientName,
            string sdkPath,
            string settingsDirectory)
        {
            PlayServicesSupport instance = new PlayServicesSupport();

            instance.sdk = sdkPath;
            string badchars = new string(Path.GetInvalidFileNameChars());

            foreach (char ch in clientName)
            {
                if (badchars.IndexOf(ch) >= 0)
                {
                    throw new Exception("Invalid clientName: " + clientName);
                }
            }

            instance.clientName            = clientName;
            instance.settingsDirectory     = settingsDirectory;
            instance.clientDependenciesMap = instance.LoadDependencies(false);
            return(instance);
        }
Exemple #9
0
        /// <summary>
        /// Creates an instance of PlayServicesSupport.  This instance is
        /// used to add dependencies for the calling client and invoke the resolution.
        /// </summary>
        /// <returns>The instance.</returns>
        /// <param name="clientName">Client name.  Must be a valid filename.
        /// This is used to uniquely identify
        /// the calling client so that dependencies can be associated with a specific
        /// client to help in resetting dependencies.</param>
        /// <param name="sdkPath">Sdk path for Android SDK.</param>
        /// <param name="additionalRepositories">Array of additional repository paths. can be null</param>
        /// <param name="settingsDirectory">The relative path to the directory
        /// to save the settings.  For Unity projects this is "ProjectSettings"</param>
        internal static PlayServicesSupport CreateInstance(
            string clientName,
            string sdkPath,
            string[] additionalRepositories,
            string settingsDirectory)
        {
            PlayServicesSupport instance = new PlayServicesSupport();

            instance.sdk = sdkPath;
            string badchars = new string(Path.GetInvalidFileNameChars());

            foreach (char ch in clientName)
            {
                if (badchars.IndexOf(ch) >= 0)
                {
                    throw new Exception("Invalid clientName: " + clientName);
                }
            }

            instance.clientName        = clientName;
            instance.settingsDirectory = settingsDirectory;

            // Add the standard repo paths from the Android SDK
            string sdkExtrasDir = Path.Combine("$SDK", "extras");

            instance.repositoryPaths.Add(Path.Combine(sdkExtrasDir,
                                                      Path.Combine("android", "m2repository")));
            instance.repositoryPaths.Add(Path.Combine(sdkExtrasDir,
                                                      Path.Combine("google", "m2repository")));
            if (additionalRepositories != null)
            {
                instance.repositoryPaths.AddRange(additionalRepositories);
            }
            instance.clientDependenciesMap = instance.LoadDependencies(false);
            return(instance);
        }
        /// <summary>
        /// Creates an instance of PlayServicesSupport.  This instance is
        /// used to add dependencies for the calling client and invoke the resolution.
        /// </summary>
        /// <returns>The instance.</returns>
        /// <param name="clientName">Client name.  Must be a valid filename.
        /// This is used to uniquely identify
        /// the calling client so that dependencies can be associated with a specific
        /// client to help in resetting dependencies.</param>
        /// <param name="sdkPath">Sdk path for Android SDK.</param>
        /// <param name="additionalRepositories">Array of additional repository paths. can be null</param>
        /// <param name="settingsDirectory">The relative path to the directory
        /// to save the settings.  For Unity projects this is "ProjectSettings"</param>
        /// <param name="logger">Delegate used to write messages to the log.</param>
        internal static PlayServicesSupport CreateInstance(
            string clientName,
            string sdkPath,
            string[] additionalRepositories,
            string settingsDirectory,
            LogMessage logger = null)
        {
            PlayServicesSupport instance = new PlayServicesSupport();
            instance.logger = logger;
            instance.sdk = sdkPath;
            string badchars = new string(Path.GetInvalidFileNameChars());

            foreach (char ch in clientName)
            {
                if (badchars.IndexOf(ch) >= 0)
                {
                    throw new Exception("Invalid clientName: " + clientName);
                }
            }

            instance.clientName = clientName;
            instance.settingsDirectory = settingsDirectory;

            // Add the standard repo paths from the Android SDK
            string sdkExtrasDir = Path.Combine("$SDK", "extras");
            instance.repositoryPaths[
                Path.Combine(sdkExtrasDir, Path.Combine("android","m2repository"))] = true;
            instance.repositoryPaths[
                Path.Combine(sdkExtrasDir, Path.Combine("google","m2repository"))] = true;
            foreach (string repo in additionalRepositories ?? new string[] {})
            {
                instance.repositoryPaths[repo] = true;
            }
            instance.clientDependenciesMap = instance.LoadDependencies(false,
                                                                       true);
            return instance;
        }
 /// <summary>
 /// Compatibility method for synchronous implementations of DoResolution().
 /// </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>
 /// 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 virtual void DoResolution(
     PlayServicesSupport svcSupport, string destinationDirectory,
     PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation,
     System.Action resolutionComplete)
 {
     DoResolution(svcSupport, destinationDirectory, handleOverwriteConfirmation);
     resolutionComplete();
 }
 /// <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;
 }
 /// <summary>
 /// Get the set of available SDK packages and whether they're installed.
 /// </summary>
 /// <param name="androidTool">Path to the Android SDK manager tool.</param>
 /// <param name="svcSupport">PlayServicesSupport instance used to retrieve the SDK
 /// path.</param>
 /// <param name="packages">Delegate called with a dictionary of package names and whether
 /// they're installed or null if the Android SDK isn't configured correctly.</param>
 internal static void GetAvailablePackages(
     string androidTool, PlayServicesSupport svcSupport,
     GetAvailablePackagesComplete complete)
 {
     CommandLineDialog window = CommandLineDialog.CreateCommandLineDialog(
         "Get Installed Android SDK packages.");
     window.modal = false;
     window.summaryText = "Getting list of installed Android packages.";
     window.progressTitle = window.summaryText;
     window.autoScrollToBottom = true;
     window.RunAsync(
         androidTool, "list sdk -u -e -a",
         (result) => {
             window.Close();
             if (result.exitCode != 0)
             {
                 Debug.LogError("Unable to determine which Android packages are " +
                                "installed.  Failed to run " + androidTool + ".  " +
                                result.stderr + " (" + result.exitCode.ToString() + ")");
                 complete(null);
                 return;
             }
             Dictionary<string, bool> packages = new Dictionary<string, bool>();
             string[] lines = Regex.Split(result.stdout, "\r\n|\r|\n");
             string packageIdentifier = null;
             foreach (string line in lines)
             {
                 // Find the start of a package description.
                 Match match = Regex.Match(line, "^id:\\W+\\d+\\W+or\\W+\"([^\"]+)\"");
                 if (match.Success)
                 {
                     packageIdentifier = match.Groups[1].Value;
                     packages[packageIdentifier] = false;
                     continue;
                 }
                 if (packageIdentifier == null)
                 {
                     continue;
                 }
                 // Parse the install path and record whether the package is installed.
                 match = Regex.Match(line, "^\\W+Install[^:]+:\\W+([^ ]+)");
                 if (match.Success)
                 {
                     packages[packageIdentifier] = File.Exists(
                         Path.Combine(Path.Combine(svcSupport.SDK, match.Groups[1].Value),
                             "source.properties"));
                     packageIdentifier = null;
                 }
             }
             complete(packages);
         },
         maxProgressLines: 50);
     window.Show();
 }
        /// <summary>
        /// Initializes the <see cref="GooglePlayServices.PlayServicesResolver"/> class.
        /// </summary>
        static PlayServicesResolver()
        {
            if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
            {
                svcSupport = PlayServicesSupport.CreateInstance(
                    "PlayServicesResolver",
                    EditorPrefs.GetString("AndroidSdkRoot"),
                    "ProjectSettings",
                    logger: UnityEngine.Debug.Log);

                EditorApplication.update -= AutoResolve;
                EditorApplication.update += AutoResolve;
                BundleIdChanged -= ResolveOnBundleIdChanged;
                BundleIdChanged += ResolveOnBundleIdChanged;
            }
            EditorApplication.update -= PollBundleId;
            EditorApplication.update += PollBundleId;
        }
        /// <summary>
        /// Perform resolution with no Android package dependency checks.
        /// </summary>
        private void DoResolutionNoAndroidPackageChecks(
            PlayServicesSupport svcSupport, string destinationDirectory,
            PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation)
        {
            try
            {
                // Get the collection of dependencies that need to be copied.
                Dictionary<string, Dependency> deps =
                    svcSupport.ResolveDependencies(true);
                // Copy the list
                svcSupport.CopyDependencies(deps,
                                            destinationDirectory,
                                            handleOverwriteConfirmation);

            }
            catch (Google.JarResolver.ResolutionException e)
            {
                Debug.LogError(e.ToString());
                return;
            }

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

            SaveAarExplodeCache();
        }
 public override void DoResolution(
     PlayServicesSupport svcSupport, string destinationDirectory,
     PlayServicesSupport.OverwriteConfirmation handleOverwriteConfirmation)
 {
     DoResolution(svcSupport, destinationDirectory, handleOverwriteConfirmation,
                  () => {});
 }
        /// <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);
                });
        }