public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_androidBuildTools.Initialize(buildToolLogger) || !_androidSdkPlatform.Initialize(buildToolLogger))
            {
                return(false);
            }

            var newestBuildToolsVersion = _androidBuildTools.GetNewestBuildToolsVersion();

            if (newestBuildToolsVersion == null)
            {
                buildToolLogger.DisplayErrorDialog(string.Format("Failed to locate {0}", BuildToolsDisplayName));
                return(false);
            }

            if (AndroidBuildTools.IsBuildToolsVersionAtLeast(newestBuildToolsVersion, BuildToolsMinimumVersion))
            {
                return(true);
            }

            var message =
                string.Format(
                    "This build requires {0} version {1} or later.", BuildToolsDisplayName, BuildToolsMinimumVersion);

            buildToolLogger.DisplayErrorDialog(message);
            return(false);
        }
예제 #2
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
#if UNITY_2018_1_OR_NEWER
            return(true);
#else
            if (!_androidBuildTools.Initialize(buildToolLogger) || !_javaUtils.Initialize(buildToolLogger))
            {
                return(false);
            }

            var newestBuildToolsPath = _androidBuildTools.GetNewestBuildToolsPath();
            if (newestBuildToolsPath == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Unable to locate an Android SDK \"build-tools\" directory that contains apksigner.");
                return(false);
            }

            _apkSignerJarPath = Path.Combine(newestBuildToolsPath, Path.Combine("lib", "apksigner.jar"));
            if (!File.Exists(_apkSignerJarPath))
            {
                buildToolLogger.DisplayErrorDialog(
                    string.Format("Unable to locate apksigner at the expected path: {0}", _apkSignerJarPath));
                return(false);
            }

            // Cache PlayerSettings on the main thread so they can be accessed from a background thread.
            _keystoreName = PlayerSettings.Android.keystoreName;
            _keystorePass = PlayerSettings.Android.keystorePass;
            _keyaliasName = PlayerSettings.Android.keyaliasName;
            _keyaliasPass = PlayerSettings.Android.keyaliasPass;

            return(true);
#endif
        }
예제 #3
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            var jdkPath = GetJdkPath();

            if (jdkPath == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate the JDK. Check Preferences -> External Tools to set the JDK path.");
                return(false);
            }

            _javaBinaryPath = GetBinaryPath(jdkPath, "java");
            if (_javaBinaryPath == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate Java. Check Preferences -> External Tools to set the JDK path.");
                return(false);
            }

            _jarBinaryPath = GetBinaryPath(jdkPath, "jar");
            if (_jarBinaryPath == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate Java's jar command. Check Preferences -> External Tools to set the JDK path.");
                return(false);
            }

            return(true);
        }
예제 #4
0
        /// <summary>
        /// Builds an APK or AAB based on the specified options and signs it (if necessary) via
        /// <a href="https://source.android.com/security/apksigning/v2">APK Signature Scheme V2</a>.
        /// Displays warning/error dialogs if there are issues during the build.
        /// </summary>
        /// <returns>True if the build succeeded, false if it failed or was cancelled.</returns>
        public virtual bool BuildAndSign(BuildPlayerOptions buildPlayerOptions)
        {
            if (!Build(buildPlayerOptions))
            {
                return(false);
            }

#if UNITY_2018_1_OR_NEWER
            // On Unity 2018.1+ we require Gradle builds. Unity 2018+ Gradle builds always yield a properly signed APK.
            return(true);
#else
            // ApkSigner is fast so we call it synchronously rather than wait for the post build AppDomain reset.
            Debug.Log("Checking for APK Signature Scheme V2...");
            var apkPath = buildPlayerOptions.locationPathName;
            if (_apkSigner.Verify(apkPath))
            {
                return(true);
            }

            Debug.Log("APK must be re-signed for APK Signature Scheme V2...");
            var signingResult = _apkSigner.Sign(apkPath);
            if (signingResult == null)
            {
                Debug.Log("Re-signed with APK Signature Scheme V2.");
                return(true);
            }

            _buildToolLogger.DisplayErrorDialog(
                string.Format("Failed to re-sign the APK using apksigner:\n\n{0}", signingResult));
            return(false);
#endif
        }
        // TODO(b/130759565): add check for PlayerSettings.productName
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            // See https://android-developers.googleblog.com/2019/01/get-your-apps-ready-for-64-bit.html
            if (!AndroidArchitectureHelper.UnityVersionSupported)
            {
                buildToolLogger.DisplayErrorDialog(
                    "This version of Unity doesn't support 64 bit libraries, which are required by Google Play."
                    + " Please upgrade Unity to version 2017.4.16 or later.");
                return(false);
            }

            // Try to determine whether this is intended to be a release build.
            if (_apkSigner.UseDebugKeystore() || EditorUserBuildSettings.development)
            {
                // Seems like a debug build, so no need to do release build checks.
                return(true);
            }

            if (!HasIconForTargetGroup(BuildTargetGroup.Unknown) && !HasIconForTargetGroup(BuildTargetGroup.Android))
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate a Default Icon or an Android Icon for this project. " +
                    "Check Player Settings to set an icon");
                return(false);
            }

            string message;

            switch (AndroidArchitectureHelper.ArchitectureStatus)
            {
            case AndroidArchitectureHelper.Status.Ok:
                return(true);

            case AndroidArchitectureHelper.Status.ArmV7Disabled:
                message = "ARMv7 and " + Arm64RequiredDescription + Il2CppRequiredDescription;
                break;

            case AndroidArchitectureHelper.Status.Il2CppDisabled:
                message = Arm64RequiredDescription + Il2CppRequiredDescription;
                break;

            case AndroidArchitectureHelper.Status.Arm64Disabled:
                message = Arm64RequiredDescription;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            message += "\n\nClick \"OK\" to enable an IL2CPP build for ARMv7 and ARM64 architectures.";
            if (buildToolLogger.DisplayActionableErrorDialog(message))
            {
                AndroidArchitectureHelper.FixTargetArchitectures();
            }

            return(false);
        }
예제 #6
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
#if !UNITY_2019_3_OR_NEWER
            return(SetSdkRoot(buildToolLogger, EditorPrefs.GetString(AndroidSdkRootEditorPrefsKey)));
#elif UNITY_ANDROID
            // Guard with #if UNITY_ANDROID since UnityEditor.Android.Extensions.dll might be unavailable,
            // e.g. on a build machine without the Android platform installed.
            return(SetSdkRoot(buildToolLogger, UnityEditor.Android.AndroidExternalToolsSettings.sdkRootPath));
#else
            // This would be an unexpected and hopefully transient error.
            if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
            {
                buildToolLogger.DisplayErrorDialog("ActiveBuildTarget disagrees with #if UNITY_ANDROID.");
                return(false);
            }

            // Handle the case where the UnityEditor.Android.Extensions.dll file may not be available by requiring that
            // Android be the selected platform on 2019.3+.
            const string message = "The Build Settings > Platform must be set to Android." +
                                   "\n\nClick \"OK\" to switch the active platform to Android.";
            if (buildToolLogger.DisplayActionableErrorDialog(message))
            {
                EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
            }

            return(false);
#endif
        }
예제 #7
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_javaUtils.Initialize(buildToolLogger))
            {
                return(false);
            }

            if (_javaUtils.JarSignerBinaryPath == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Unable to locate jarsigner. Check that a recent version of the JDK " +
                    "is installed and check the Console log for more details on the error.");
                return(false);
            }

            // Cache PlayerSettings on the main thread so they can be accessed from a background thread.
            _keystoreName = PlayerSettings.Android.keystoreName;
            _keystorePass = PlayerSettings.Android.keystorePass;
            _keyaliasName = PlayerSettings.Android.keyaliasName;
            _keyaliasPass = PlayerSettings.Android.keyaliasPass;
#if UNITY_2019_1_OR_NEWER
            _useCustomKeystore = PlayerSettings.Android.useCustomKeystore;
#else
            _useCustomKeystore = !string.IsNullOrEmpty(_keystoreName) && !string.IsNullOrEmpty(_keyaliasName);
#endif

            return(true);
        }
예제 #8
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_androidBuildTools.Initialize(buildToolLogger) || !_androidSdkPlatform.Initialize(buildToolLogger))
            {
                return(false);
            }

            var newestBuildToolsVersion = _androidBuildTools.GetNewestBuildToolsVersion();

            if (newestBuildToolsVersion == null)
            {
                buildToolLogger.DisplayErrorDialog(string.Format("Failed to locate {0}", BuildToolsDisplayName));
                return(false);
            }

            if (AndroidBuildTools.IsBuildToolsVersionAtLeast(newestBuildToolsVersion, BuildToolsMinimumVersion))
            {
                return(true);
            }

            var message = string.Format(
                "App Bundle creation requires {0} version {1} or later.\n\nClick \"OK\" to install {0} version {2}.",
                BuildToolsDisplayName, BuildToolsMinimumVersion, BuildToolsLatestVersion);

            if (buildToolLogger.DisplayActionableErrorDialog(message))
            {
                AndroidSdkPackageInstaller.InstallPackage(BuildToolsPackageName, BuildToolsDisplayName);
            }

            return(false);
        }
예제 #9
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_androidSdk.Initialize(buildToolLogger))
            {
                return(false);
            }

            string ignoredPath;
            var    newestVersion = GetNewestVersionAndPath(out ignoredPath);

            if (newestVersion == null)
            {
                // Being unable to find any existing SDK may indicate a config issue, so don't try to install a new SDK.
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate any Android SDK Platform version. Check that the Android SDK specified "
                    + "through Preferences -> External Tools has at least one Android SDK Platform installed.");
                return(false);
            }

            if (newestVersion < MinimumVersion)
            {
                var installedVersionMessage = string.Format(
                    "The highest installed Android API Level is {0}, however version {1} is the minimum "
                    + "required to build for Google Play.\n\nClick \"OK\" to install Android API Level {2}.",
                    newestVersion, MinimumVersion, LatestVersion);
                if (buildToolLogger.DisplayActionableErrorDialog(installedVersionMessage))
                {
                    // Note: this install can be slow, but it's not clear that it's any slower through Unity.
                    AndroidSdkPackageInstaller.InstallPackage(
                        string.Format("platforms;android-{0}", LatestVersion),
                        string.Format("Android SDK Platform {0}", LatestVersion),
                        _androidSdk.RootPath);
                }

                return(false);
            }

            var targetSdkVersion = PlayerSettings.Android.targetSdkVersion;

            if (targetSdkVersion == AndroidSdkVersions.AndroidApiLevelAuto || (int)targetSdkVersion >= MinimumVersion)
            {
                return(true);
            }

            var selectedVersionMessage = string.Format(
                "The currently selected Android Target API Level is {0}, however version {1} is the minimum "
                + "required to build for Google Play.\n\nClick \"OK\" to change the Target API Level to "
                + "\"Automatic (highest installed)\", which is currently {2}.",
                (int)targetSdkVersion, MinimumVersion, newestVersion);

            if (buildToolLogger.DisplayActionableErrorDialog(selectedVersionMessage))
            {
                PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto;
            }

            return(false);
        }
예제 #10
0
        // Don't support certain versions of Unity due to the "Failed to load 'libmain.so'" crash.
        // See https://github.com/google/play-unity-plugins/issues/80 and
        // https://issuetracker.unity3d.com/issues/android-app-installed-using-apk-from-app-bundle-option-in-android-studio-fails-to-run
        private static bool CheckUnityVersion(BuildToolLogger buildToolLogger)
        {
#if UNITY_2020_2 || UNITY_2020_3_0 || UNITY_2020_3_1 || UNITY_2020_3_2 || UNITY_2021_1_0 || UNITY_2021_1_1
            buildToolLogger.DisplayErrorDialog(
                "Apps built as AABs with this version of Unity may crash at runtime. Upgrade to 2020.3.3f1, 2021.1.2f1, or later to avoid this issue.");
            return(false);
#else
            return(true);
#endif
        }
예제 #11
0
        /// <summary>
        /// Builds an APK or AAB based on the specified options.
        /// Displays warning/error dialogs if there are issues during the build.
        /// </summary>
        public virtual AndroidBuildResult Build(BuildPlayerOptions buildPlayerOptions)
        {
            if (_buildToolLogger == null)
            {
                throw new BuildToolNotInitializedException(this);
            }

            if (buildPlayerOptions.target != BuildTarget.Android)
            {
                throw new ArgumentException("The build target must be Android.", "buildPlayerOptions");
            }

            if (buildPlayerOptions.targetGroup != BuildTargetGroup.Android)
            {
                throw new ArgumentException("The build target group must be Android.", "buildPlayerOptions");
            }

            // Note: the type of the variable below differs by version. On 2018+ it's BuildReport. On pre-2018 it's
            // string: if the string is null, the build was successful, otherwise it's a build error message.
            var buildReportOrErrorMessage = BuildPipeline.BuildPlayer(buildPlayerOptions);
            var androidBuildResult        = GetAndroidBuildResult(buildReportOrErrorMessage);

            if (androidBuildResult.Cancelled)
            {
                // Don't display an error message dialog if the user asked to cancel, just log to the Console.
                Debug.Log(BuildCancelledMessage);
                return(androidBuildResult);
            }

            if (androidBuildResult.Succeeded && !File.Exists(buildPlayerOptions.locationPathName))
            {
                // Sometimes the build "succeeds" but the AAB/APK file is missing.
                androidBuildResult.ErrorMessage =
                    string.Format(
                        "The Android Player file \"{0}\" is missing, possibly because of a late cancellation.",
                        buildPlayerOptions.locationPathName);
#if UNITY_2018_1_OR_NEWER
                androidBuildResult.ErrorMessage += " TotalErrors=" + buildReportOrErrorMessage.summary.totalErrors;
#endif
            }

            if (androidBuildResult.Succeeded)
            {
                Debug.Log("Android Player build succeeded");
            }
            else
            {
                _buildToolLogger.DisplayErrorDialog(androidBuildResult.ErrorMessage);
            }

            return(androidBuildResult);
        }
예제 #12
0
        // TODO(b/130759565): add check for PlayerSettings.productName
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            // Try to determine whether this is intended to be a release build.
            if (!_jarSigner.UseCustomKeystore || EditorUserBuildSettings.development)
            {
                // Seems like a debug build, so no need to do release build checks.
                return(true);
            }

            if (!HasIconForTargetGroup(BuildTargetGroup.Unknown) && !HasIconForTargetGroup(BuildTargetGroup.Android))
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate a Default Icon or an Android Icon for this project. " +
                    "Check Player Settings to set an icon");
                return(false);
            }

            string message;

            switch (AndroidArchitectureHelper.ArchitectureStatus)
            {
            case AndroidArchitectureHelper.Status.Ok:
                return(true);

            case AndroidArchitectureHelper.Status.ArmV7Disabled:
                message = "ARMv7 and " + Arm64RequiredDescription + Il2CppRequiredDescription;
                break;

            case AndroidArchitectureHelper.Status.Il2CppDisabled:
                message = Arm64RequiredDescription + Il2CppRequiredDescription;
                break;

            case AndroidArchitectureHelper.Status.Arm64Disabled:
                message = Arm64RequiredDescription;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            message += "\n\nClick \"OK\" to enable an IL2CPP build for ARMv7 and ARM64 architectures.";
            if (buildToolLogger.DisplayActionableErrorDialog(message))
            {
                AndroidArchitectureHelper.FixTargetArchitectures();
            }

            return(false);
        }
예제 #13
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_javaUtils.Initialize(buildToolLogger))
            {
                return(false);
            }

            _streamingAssetsPath = Application.streamingAssetsPath;
            _bundletoolJarPath   = BundletoolJarPath;
            if (_bundletoolJarPath == null)
            {
                buildToolLogger.DisplayErrorDialog("Failed to locate bundletool.");
                return(false);
            }

            return(true);
        }
예제 #14
0
        private bool SetSdkRoot(BuildToolLogger buildToolLogger, string sdkPath)
        {
            if (string.IsNullOrEmpty(sdkPath))
            {
                sdkPath = Environment.GetEnvironmentVariable(AndroidHomeEnvironmentVariableKey);
            }

            if (!Directory.Exists(sdkPath))
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate the Android SDK. Check Preferences -> External Tools to set the path.");
                return(false);
            }

            _androidSdkRoot = sdkPath;
            return(true);
        }
예제 #15
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
#if UNITY_2019_3_OR_NEWER
            var sdkPath = UnityEditor.Android.AndroidExternalToolsSettings.sdkRootPath;
#else
            var sdkPath = EditorPrefs.GetString(AndroidSdkRootEditorPrefsKey);
#endif
            if (string.IsNullOrEmpty(sdkPath))
            {
                sdkPath = Environment.GetEnvironmentVariable(AndroidHomeEnvironmentVariableKey);
            }

            if (!Directory.Exists(sdkPath))
            {
                buildToolLogger.DisplayErrorDialog(
                    "Failed to locate the Android SDK. Check Preferences -> External Tools to set the path.");
                return(false);
            }

            _androidSdkRoot = sdkPath;
            return(true);
        }
예제 #16
0
        public virtual bool Initialize(BuildToolLogger buildToolLogger)
        {
            if (!_androidBuildTools.Initialize(buildToolLogger) || !_javaUtils.Initialize(buildToolLogger))
            {
                return(false);
            }

            if (GetApkSignerJarPath() == null)
            {
                buildToolLogger.DisplayErrorDialog(
                    "Unable to locate apksigner. Check that a recent version of Android SDK " +
                    "Build-Tools is installed and check the Console log for more details on the error.");
                return(false);
            }

            // Cache PlayerSettings on the main thread so they can be accessed from a background thread.
            _keystoreName = PlayerSettings.Android.keystoreName;
            _keystorePass = PlayerSettings.Android.keystorePass;
            _keyaliasName = PlayerSettings.Android.keyaliasName;
            _keyaliasPass = PlayerSettings.Android.keyaliasPass;

            return(true);
        }