/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System.Diagnostics.CodeAnalysis; using System.Xml; using UnityEditor; using UnityEditor.Build; using System.IO; #if UNITY_2018_1_OR_NEWER using UnityEditor.Build.Reporting; using UnityEngine; using UnityEditor.Android; using System.Text; using System.Text.RegularExpressions; #endif #if UNITY_2018_1_OR_NEWER /// The preprocess build base. internal class PreprocessBuildBase : IPreprocessBuildWithReport #else internal class PreprocessBuildBase : IPreprocessBuild #endif { /// /// Returns the relative callback order for callbacks. Callbacks with lower values are /// called before ones with higher values. /// The callback order. public int callbackOrder { get { return 0; } } #if UNITY_2018_1_OR_NEWER /// /// Implement this function to receive a callback before the build is started. /// A report containing information about the build, such as its target /// platform and output path. public void OnPreprocessBuild(BuildReport report) { OnPreprocessBuild(report.summary.platform, report.summary.outputPath); } #endif /// Executes the 'preprocess build' action. /// Target for the. /// Full pathname of the file. public virtual void OnPreprocessBuild(BuildTarget target, string path) { if (target == BuildTarget.Android) { OnPreprocessBuildForAndroid(); } } private const string DefaultXML = @" "; /// True if is show on desktop, false if not. private const bool isShowOnDesktop = true; /// Executes the 'preprocess build for android' action. [MenuItem("NRSDK/PreprocessBuildForAndroid")] public static void OnPreprocessBuildForAndroid() { string basePath = Application.dataPath + "/Plugins/Android"; if (!Directory.Exists(Application.dataPath + "/Plugins")) { Directory.CreateDirectory(Application.dataPath + "/Plugins"); } if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); } string xmlPath = Application.dataPath + "/Plugins/Android/AndroidManifest.xml"; if (!File.Exists(xmlPath)) { string xml = DefaultXML.Replace("\'", "\""); if (isShowOnDesktop) { xml = xml.Replace("", ""); } File.WriteAllText(xmlPath, xml); } AutoGenerateAndroidManifest(xmlPath); ApplySettingsToConfig(); AutoGenerateAndroidGradleTemplate(); AssetDatabase.Refresh(); } private static void ApplySettingsToConfig() { NRProjectConfig projectConfig = NRProjectConfigHelper.GetProjectConfig(); var sessionConfigGuids = AssetDatabase.FindAssets("t:NRSessionConfig"); foreach (var item in sessionConfigGuids) { var config = AssetDatabase.LoadAssetAtPath( AssetDatabase.GUIDToAssetPath(item)); config.SetUseMultiThread(PlayerSettings.GetMobileMTRendering(BuildTargetGroup.Android)); config.SetProjectConfig(projectConfig); EditorUtility.SetDirty(config); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } [MenuItem("NRSDK/AddAudioPermission")] public static void AddAudioPermission() { string xmlPath = Application.dataPath + "/Plugins/Android/AndroidManifest.xml"; var androidManifest = new AndroidManifest(xmlPath); androidManifest.SetAudioRecordPermission(); androidManifest.Save(); } [MenuItem("NRSDK/InitVideoPlayerDemoEnv")] public static void InitVideoPlayerDemoEnv() { string javaDir = ""; string[] assets = AssetDatabase.FindAssets("AndroidMediaPlayer"); foreach (var asset in assets) { string path = AssetDatabase.GUIDToAssetPath(asset); if (path.Contains("NRSDKExperimental") && path.EndsWith(".java")) { javaDir = Path.GetDirectoryName(path); break; } } if (!string.IsNullOrEmpty(javaDir)) { string[] files = Directory.GetFiles(javaDir, "*.java"); foreach (var file in files) { PluginImporter importer = (PluginImporter)AssetImporter.GetAtPath(file); if (importer != null) { importer.SetCompatibleWithPlatform(BuildTarget.Android, true); importer.SaveAndReimport(); } } } //set project dependency string gradleFile = "mainTemplate.gradle"; if (UseCustomGradleFile(gradleFile)) { string gradleInProject = Application.dataPath + "/Plugins/Android/" + gradleFile; AndroidGradleTemplate gradleTmp = new AndroidGradleTemplate(gradleInProject); gradleTmp.AddDenpendency("implementation 'com.google.android.exoplayer:exoplayer:2.13.2'"); gradleTmp.PreprocessGradleFile(); } EditorUtility.DisplayDialog("Tips", "Added ExoPlayer library dependency. The scene Overlay-VideoPlayer now supports DRM video playback.", "OK"); } /// Automatic generate android manifest. /// Full pathname of the file. public static void AutoGenerateAndroidManifest(string path) { var androidManifest = new AndroidManifest(path); //bool needrequestLegacyExternalStorage = (GetAndroidTargetApiLevel() >= 29); //androidManifest.SetExternalStorage(needrequestLegacyExternalStorage); // androidManifest.SetPackageReadPermission(); //androidManifest.SetCameraPermission(); androidManifest.SetBlueToothPermission(); androidManifest.SetSDKMetaData(); androidManifest.SetAPKDisplayedOnLauncher(isShowOnDesktop); androidManifest.Save(); } public static int GetAndroidTargetApiLevel() { if (PlayerSettings.Android.targetSdkVersion == AndroidSdkVersions.AndroidApiLevelAuto) { string androidsdkRoot = EditorPrefs.GetString("AndroidSdkRoot"); string[] androidVersions = Directory.GetDirectories(Path.Combine(androidsdkRoot, "platforms")); string regex = "android-([0-9]*)"; int maxVersion = (int)AndroidSdkVersions.AndroidApiLevelAuto; foreach (var item in androidVersions) { MatchCollection coll = Regex.Matches(item, regex); if (coll != null && coll[0] != null && coll[0].Groups[1] != null) { string result = coll[0].Groups[1].Value; int versionCode = int.Parse(result); if (versionCode > maxVersion) { maxVersion = versionCode; } } } return maxVersion; } else { return (int)PlayerSettings.Android.targetSdkVersion; } } /// In order to support 'queries' in manifest, gradle plugin must be higher than 3.4.3. /// For unity version lower than 2020, this can be modified by using 'Custom Gradle Template', then modify the gradle plugin version in template file public static void AutoGenerateAndroidGradleTemplate() { string version = Application.unityVersion; Debug.Log("UnityVersion: " + version); string vMain = version.Substring(0, 4); int nVersion = 0; int.TryParse(vMain, out nVersion); if (nVersion < 2018) Debug.LogErrorFormat("NRSDK require unity version higher than 2018"); else if (nVersion == 2018) AutoGenerateAndroidGradleTemplate("mainTemplate.gradle"); else AutoGenerateAndroidGradleTemplate("baseProjectTemplate.gradle"); //unity2020 should add support android.useAndroidX manually if (nVersion >= 2020) { AutoGenerateGradleProperties("gradleTemplate.properties"); } } /// /// Use custom gradle file, copy from unity install directory to project directory. /// /// gradle file name. private static bool UseCustomGradleFile(string templateFileName) { string gradleInProject = Application.dataPath + "/Plugins/Android/" + templateFileName; if (!File.Exists(gradleInProject)) { string unityEditorPath = EditorApplication.applicationPath; string gradleReletPath = "/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/" + templateFileName; #if UNITY_EDITOR_WIN gradleReletPath = "/data" + gradleReletPath; #endif string gradleFullPath = unityEditorPath.Substring(0, unityEditorPath.LastIndexOf("/")) + gradleReletPath; Debug.LogFormat("Copy gradle template : {0} --> {1}", gradleFullPath, gradleInProject); if (File.Exists(gradleFullPath)) File.Copy(gradleFullPath, gradleInProject); else { Debug.LogErrorFormat("GradleTemplate of unity not found : {0}", gradleFullPath); return false; } } return true; } /// /// Generate custom gradle file, set minal /// /// Gradle file name. private static void AutoGenerateAndroidGradleTemplate(string templateFileName) { if(!UseCustomGradleFile(templateFileName)) { return; } string gradleInProject = Application.dataPath + "/Plugins/Android/" + templateFileName; AndroidGradleTemplate gradleTmp = new AndroidGradleTemplate(gradleInProject); gradleTmp.SetMinPluginVersion(3, 4, 3); gradleTmp.PreprocessGradleFile(); } private static void AutoGenerateGradleProperties(string templateFileName) { if (!UseCustomGradleFile(templateFileName)) { return; } string gradleInProject = Application.dataPath + "/Plugins/Android/" + templateFileName; AndroidGradleTemplate gradleTmp = new AndroidGradleTemplate(gradleInProject); gradleTmp.AddSupport("android.useAndroidX"); gradleTmp.PreprocessGradleFile(); } } }