public static bool UninstallAPK() { OVRBundleTool.PrintLog("Uninstalling Application . . ."); OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { string output, error; string appPackagename = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android) + GetTransitionApkOptionalIdentifier(); string[] appStartCommand = { "-d shell", "pm uninstall", appPackagename }; if (adbTool.RunCommand(appStartCommand, null, out output, out error) == 0) { OVRBundleTool.PrintSuccess(); OVRBundleTool.PrintLog("App package " + appPackagename + " is uninstalled."); return(true); } OVRBundleTool.PrintError("Failed to uninstall APK."); } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } return(false); }
public static void BuildDeployTransitionAPK() { OVRBundleTool.PrintLog("Building and deploying transition APK . . .\n", true); PrebuildProjectSettingUpdate(); var buildPlayerOptions = CalculateBundleBuildPlayerOptions(); if (!buildPlayerOptions.HasValue) { return; } DateTime apkBuildStart = DateTime.Now; BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions.Value); if (report.summary.result == BuildResult.Succeeded) { OVRBundleTool.PrintSuccess(); } else if (report.summary.result == BuildResult.Failed) { OVRBundleTool.PrintError(); } PostbuildProjectSettingUpdate(); }
public static bool LaunchApplication() { OVRBundleTool.PrintLog("Launching Application . . . "); OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { string output, error; string appPackagename = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android) + GetTransitionApkOptionalIdentifier(); string playerActivityName = "\"" + appPackagename + "/com.unity3d.player.UnityPlayerActivity\""; string[] appStartCommand = { "-d shell", "am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -S -f 0x10200000 -n", playerActivityName }; if (adbTool.RunCommand(appStartCommand, null, out output, out error) == 0) { OVRBundleTool.PrintSuccess(); OVRBundleTool.PrintLog("App package " + appPackagename + " is launched."); return(true); } string completeError = "Failed to launch application. Try launching it manually through the device.\n" + (string.IsNullOrEmpty(error) ? output : error); OVRBundleTool.PrintError(completeError); } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } return(false); }
private static void PrebuildProjectSettingUpdate() { // Modify application identifier for transition APK projectDefaultAppIdentifier = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android); PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, projectDefaultAppIdentifier + GetTransitionApkOptionalIdentifier()); // Set VersionCode as a unique identifier for transition APK projectDefaultVersion = PlayerSettings.bundleVersion; PlayerSettings.bundleVersion = TRANSITION_APK_VERSION_NAME; // Modify IL2CPP option as it strips script symbols that are necessary for the scenes at runtime projectScriptImplementation = PlayerSettings.GetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup); if (projectScriptImplementation != ScriptingImplementation.Mono2x) { // Show message in console to make it more clear to developers OVRBundleTool.PrintLog("Build will use Mono as scripting backend."); PlayerSettings.SetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup, ScriptingImplementation.Mono2x); } // Avoid stripping managed code that are necessary for the scenes at runtime projectManagedStrippingLevel = PlayerSettings.GetManagedStrippingLevel(BuildTargetGroup.Android); if (projectManagedStrippingLevel != ManagedStrippingLevel.Disabled) { OVRBundleTool.PrintLog("Build will set Managed Stripping Level to Disabled."); PlayerSettings.SetManagedStrippingLevel(BuildTargetGroup.Android, ManagedStrippingLevel.Disabled); } projectStripEngineCode = PlayerSettings.stripEngineCode; if (projectStripEngineCode) { PlayerSettings.stripEngineCode = false; } }
public static void DeleteRemoteAssetBundles() { OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { bool failure = false; string fileExistsError = "No such file or directory"; OVRBundleTool.PrintLog("Deleting device bundles . . . "); string output, error; string[] deleteBundleCommand = { "-d shell", "rm -r", externalSceneCache }; if (adbTool.RunCommand(deleteBundleCommand, null, out output, out error) != 0) { if (!(output.Contains(fileExistsError) || error.Contains(fileExistsError))) { failure = true; } } if (failure) { OVRBundleTool.PrintError(string.IsNullOrEmpty(error) ? output : error); OVRBundleTool.PrintError("Failed to delete scene bundle cache directory."); } else { OVRBundleTool.PrintSuccess(); } } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } }
public static bool UninstallAPK() { OVRBundleTool.PrintLog("Uninstalling Application . . ."); OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { string output, error; string packageName = Application.identifier + ".transition"; string[] appStartCommand = { "-d shell", "pm uninstall", packageName }; if (adbTool.RunCommand(appStartCommand, null, out output, out error) == 0) { OVRBundleTool.PrintSuccess(); return(true); } OVRBundleTool.PrintError("Failed to uninstall APK."); } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } return(false); }
public static void BuildDeployTransitionAPK(bool useOptionalTransitionApkPackage) { OVRBundleTool.PrintLog("Building and deploying transition APK . . .\n", true); if (!Directory.Exists(BUNDLE_MANAGER_OUTPUT_PATH)) { Directory.CreateDirectory(BUNDLE_MANAGER_OUTPUT_PATH); } PrebuildProjectSettingUpdate(); if (String.IsNullOrEmpty(transitionScenePath)) { // Get current editor script's directory as base path string[] res = System.IO.Directory.GetFiles(Application.dataPath, "OVRBundleManager.cs", SearchOption.AllDirectories); if (res.Length > 1) { OVRBundleTool.PrintError("More than one OVRBundleManager editor script has been found, please double check your Oculus SDK import."); return; } else { // Append Transition Scene's relative path to base path var OVREditorScript = Path.GetDirectoryName(res[0]); transitionScenePath = Path.Combine(OVREditorScript, TRANSITION_SCENE_RELATIVE_PATH); } } string[] buildScenes = new string[1] { transitionScenePath }; string apkOutputPath = Path.Combine(BUNDLE_MANAGER_OUTPUT_PATH, "OVRTransition.apk"); DateTime apkBuildStart = DateTime.Now; var buildPlayerOptions = new BuildPlayerOptions { scenes = buildScenes, locationPathName = apkOutputPath, target = BuildTarget.Android, options = BuildOptions.Development | BuildOptions.AutoRunPlayer }; BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions); if (report.summary.result == BuildResult.Succeeded) { OVRBundleTool.PrintSuccess(); } else if (report.summary.result == BuildResult.Failed) { OVRBundleTool.PrintError(); } OVRPlugin.SendEvent("oculus_bundle_tool", "apk_build_time", (DateTime.Now - apkBuildStart).TotalSeconds.ToString()); PostbuildProjectSettingUpdate(); }
public static void DeleteLocalAssetBundles() { try { if (Directory.Exists(BUNDLE_MANAGER_OUTPUT_PATH)) { OVRBundleTool.PrintLog("Deleting local bundles . . . "); Directory.Delete(BUNDLE_MANAGER_OUTPUT_PATH, true); } } catch (Exception e) { OVRBundleTool.PrintError(e.Message); } OVRBundleTool.PrintSuccess(); }
public static void PrebuildProjectSettingUpdate() { // Save existing settings as some modifications can change other settings projectDefaultAppIdentifier = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android); projectDefaultVersion = PlayerSettings.bundleVersion; projectAndroidArchitecture = PlayerSettings.Android.targetArchitectures; projectScriptImplementation = PlayerSettings.GetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup); projectManagedStrippingLevel = PlayerSettings.GetManagedStrippingLevel(BuildTargetGroup.Android); projectStripEngineCode = PlayerSettings.stripEngineCode; // Modify application identifier for transition APK PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, projectDefaultAppIdentifier + GetTransitionApkOptionalIdentifier()); // Set VersionCode as a unique identifier for transition APK PlayerSettings.bundleVersion = TRANSITION_APK_VERSION_NAME; // Modify Android target architecture as ARM64 does not support Mono. if (projectAndroidArchitecture != AndroidArchitecture.ARMv7) { // Show message in console to make it more clear to developers OVRBundleTool.PrintLog("Build will use ARMv7 as Android architecture."); PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7; } // Modify IL2CPP option as it strips script symbols that are necessary for the scenes at runtime if (projectScriptImplementation != ScriptingImplementation.Mono2x) { // Show message in console to make it more clear to developers OVRBundleTool.PrintLog("Build will use Mono as scripting backend."); PlayerSettings.SetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup, ScriptingImplementation.Mono2x); } // Avoid stripping managed code that are necessary for the scenes at runtime if (projectManagedStrippingLevel != ManagedStrippingLevel.Disabled) { OVRBundleTool.PrintLog("Build will set Managed Stripping Level to Disabled."); PlayerSettings.SetManagedStrippingLevel(BuildTargetGroup.Android, ManagedStrippingLevel.Disabled); } if (projectStripEngineCode) { OVRBundleTool.PrintLog("Build will set Strip Engine Code to Disabled."); PlayerSettings.stripEngineCode = false; } }
public static void DeleteRemoteAssetBundles() { OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { externalSceneCache = EXTERNAL_STORAGE_PATH + "/" + PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android) + GetTransitionApkOptionalIdentifier() + "/cache/scenes"; bool failure = false; string fileExistsError = "No such file or directory"; OVRBundleTool.PrintLog("Deleting device bundles . . . "); string output, error; string[] deleteBundleCommand = { "-d shell", "rm -r", externalSceneCache }; if (adbTool.RunCommand(deleteBundleCommand, null, out output, out error) != 0) { if (!(output.Contains(fileExistsError) || error.Contains(fileExistsError))) { failure = true; } } if (failure) { OVRBundleTool.PrintError(string.IsNullOrEmpty(error) ? output : error); OVRBundleTool.PrintError("Failed to delete scene bundle cache directory."); } else { OVRBundleTool.PrintSuccess(); } } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } }
private static bool TransferSceneBundles(OVRADBTool adbTool, string absoluteTempPath, string externalSceneCache) { List <string> bundlesToTransfer = new List <string>(); List <string> bundlesToDelete = new List <string>(); string manifestFilePath = externalSceneCache + "/" + BUNDLE_MANAGER_MASTER_BUNDLE; string[] pullManifestCommand = { "-d pull", "\"" + manifestFilePath + "\"", "\"" + absoluteTempPath + "\"" }; string output, error; if (adbTool.RunCommand(pullManifestCommand, null, out output, out error) == 0) { // An existing manifest file was found on device. Load hashes and upload bundles that have changed hashes. Debug.Log("[OVRBundleManager] - Scene bundle manifest file found. Decoding changes . . ."); // Load hashes from remote manifest AssetBundle remoteBundle = AssetBundle.LoadFromFile(Path.Combine(absoluteTempPath, BUNDLE_MANAGER_MASTER_BUNDLE)); if (remoteBundle == null) { OVRBundleTool.PrintError("Failed to load remote asset bundle manifest file."); return(false); } AssetBundleManifest remoteManifest = remoteBundle.LoadAsset <AssetBundleManifest>("AssetBundleManifest"); Dictionary <string, Hash128> remoteBundleToHash = new Dictionary <string, Hash128>(); if (remoteManifest != null) { string[] assetBundles = remoteManifest.GetAllAssetBundles(); foreach (string bundleName in assetBundles) { remoteBundleToHash[bundleName] = remoteManifest.GetAssetBundleHash(bundleName); } } remoteBundle.Unload(true); // Load hashes from local manifest AssetBundle localBundle = AssetBundle.LoadFromFile(BUNDLE_MANAGER_OUTPUT_PATH + "\\" + BUNDLE_MANAGER_MASTER_BUNDLE + "\\" + BUNDLE_MANAGER_MASTER_BUNDLE); if (localBundle == null) { OVRBundleTool.PrintError("<color=red>Failed to load local asset bundle manifest file.\n</color>"); return(false); } AssetBundleManifest localManifest = localBundle.LoadAsset <AssetBundleManifest>("AssetBundleManifest"); if (localManifest != null) { Hash128 zeroHash = new Hash128(0, 0, 0, 0); // Build a list of dirty bundles that will have to be transfered string relativeSceneBundlesPath = Path.Combine(BUNDLE_MANAGER_OUTPUT_PATH, BUNDLE_MANAGER_MASTER_BUNDLE); bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, BUNDLE_MANAGER_MASTER_BUNDLE)); string[] assetBundles = localManifest.GetAllAssetBundles(); foreach (string bundleName in assetBundles) { if (!remoteBundleToHash.ContainsKey(bundleName)) { bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, bundleName)); } else { if (remoteBundleToHash[bundleName] != localManifest.GetAssetBundleHash(bundleName)) { bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, bundleName)); } remoteBundleToHash[bundleName] = zeroHash; } } OVRBundleTool.PrintLog(bundlesToTransfer.Count + " dirty bundle(s) will be transfered.\n"); } } else { if (output.Contains("does not exist") || output.Contains("No such file or directory")) { // Fresh install of asset bundles, transfer all asset bundles OVRBundleTool.PrintLog("Manifest file not found. Transfering all bundles . . . "); string[] mkdirCommand = { "-d shell", "mkdir -p", "\"" + externalSceneCache + "\"" }; if (adbTool.RunCommand(mkdirCommand, null, out output, out error) == 0) { string absoluteSceneBundlePath = Path.Combine(Path.Combine(Application.dataPath, ".."), Path.Combine(BUNDLE_MANAGER_OUTPUT_PATH, BUNDLE_MANAGER_MASTER_BUNDLE)); string[] assetBundlePaths = Directory.GetFiles(absoluteSceneBundlePath); if (assetBundlePaths.Length != 0) { foreach (string path in assetBundlePaths) { if (!path.Contains(".manifest")) { bundlesToTransfer.Add(path); } } } else { OVRBundleTool.PrintError("Failed to locate scene bundles to transfer."); return(false); } } } } // If any adb error occured during manifest calculation, print it and return false if (!string.IsNullOrEmpty(error) || output.Contains("error")) { OVRBundleTool.PrintError(string.IsNullOrEmpty(error) ? output : error); return(false); } // Transfer bundles to device DateTime transferStart = DateTime.Now; foreach (string bundle in bundlesToTransfer) { string absoluteBundlePath = Path.Combine(Path.Combine(Application.dataPath, ".."), bundle); string[] pushBundleCommand = { "-d push", "\"" + absoluteBundlePath + "\"", "\"" + externalSceneCache + "\"" }; adbTool.RunCommandAsync(pushBundleCommand, null); } Debug.Log("[OVRBundleManager] - Transfer took " + (DateTime.Now - transferStart).TotalSeconds + " seconds."); // Delete stale bundles on device if (bundlesToDelete.Count > 0) { foreach (string bundle in bundlesToDelete) { string bundlePath = externalSceneCache + "/" + bundle; string[] deleteBundleCommand = { "-d shell", "rm", "\"" + bundlePath + "\"" }; adbTool.RunCommandAsync(deleteBundleCommand, null); } OVRBundleTool.PrintLog("Deleted " + bundlesToDelete.Count + " bundle(s) that were stale"); } return(true); }
private static bool DeploySceneBundles(List <OVRBundleTool.EditorSceneInfo> sceneList) { // Create Temp directory on local machine if it does not exist string tempDirectory = Path.Combine(BUNDLE_MANAGER_OUTPUT_PATH, "Temp"); if (!Directory.Exists(tempDirectory)) { Directory.CreateDirectory(tempDirectory); } string absoluteTempPath = Path.Combine(Path.Combine(Application.dataPath, ".."), tempDirectory); OVRBundleTool.PrintLog("Deploying scene bundles to device . . . "); OVRADBTool adbTool = new OVRADBTool(OVRConfig.Instance.GetAndroidSDKPath()); if (adbTool.isReady) { DateTime transferStart = DateTime.Now; for (int i = 0; i < sceneList.Count; ++i) { if (!sceneList[i].shouldDeploy) { continue; } OVRBundleTool.UpdateSceneBuildStatus(OVRBundleTool.SceneBundleStatus.TRANSFERRING, i); } // Transfer all scene bundles that are relavent if (!TransferSceneBundles(adbTool, absoluteTempPath, externalSceneCache)) { return(false); } for (int i = 0; i < sceneList.Count; ++i) { if (!sceneList[i].shouldDeploy) { continue; } OVRBundleTool.UpdateSceneBuildStatus(OVRBundleTool.SceneBundleStatus.DEPLOYED, i); } // Create file to tell transition scene APK which scene to load and push it to the device string sceneLoadDataPath = Path.Combine(tempDirectory, OVRSceneLoader.sceneLoadDataName); if (File.Exists(sceneLoadDataPath)) { File.Delete(sceneLoadDataPath); } StreamWriter writer = new StreamWriter(sceneLoadDataPath, true); // Write version and scene names long unixTime = (int)(DateTimeOffset.UtcNow.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; writer.WriteLine(unixTime.ToString()); for (int i = 0; i < sceneList.Count; i++) { if (!sceneList[i].shouldDeploy) { continue; } writer.WriteLine(Path.GetFileNameWithoutExtension(sceneList[i].scenePath)); } writer.Close(); string absoluteSceneLoadDataPath = Path.Combine(absoluteTempPath, OVRSceneLoader.sceneLoadDataName); string[] pushCommand = { "-d push", "\"" + absoluteSceneLoadDataPath + "\"", "\"" + externalSceneCache + "\"" }; string output, error; if (adbTool.RunCommand(pushCommand, null, out output, out error) == 0) { Debug.Log("[OVRBundleManager] Scene Load Data Pushed to Device."); return(true); } OVRBundleTool.PrintError(string.IsNullOrEmpty(error) ? output : error); } else { OVRBundleTool.PrintError(ADB_TOOL_INITIALIZE_ERROR); } return(false); }
// Build assets that are used by scenes from the given list. // This function will automatically de-duplicated same asset file being referenced in multiple scenes. // Scene bundles will be created with name pattern: <SceneName>_<AssetTypeExtention><ChunckNumber> private static void BuildSceneBundles(List <OVRBundleTool.EditorSceneInfo> sceneList) { DateTime totalStart = DateTime.Now; // Keeps track of dependent assets across scenes // to ensure each asset is only packaged once in one of the scene bundles. // uniqueAssetInSceneBundle is a map from "asset unique identifier" to the first scene that references the asset. // It supports different assets with same file name as "asset unique identifier" contain full qualified asset file path Dictionary <string, string> uniqueAssetInSceneBundle = new Dictionary <string, string>(); // List of bundle targets for Unity's build pipeline to package List <AssetBundleBuild> assetBundleBuilds = new List <AssetBundleBuild>(); // Map that contains "asset type" to list of assets that are of the asset type Dictionary <string, List <string> > extToAssetList = new Dictionary <string, List <string> >(); // Check if assets in Resources need to be packaged if (CheckForResources()) { var resourceDirectories = Directory.GetDirectories("Assets", "Resources", SearchOption.AllDirectories).ToArray(); // Fetch a list of all files in resource directory string[] resourceAssetPaths = AssetDatabase.FindAssets("", resourceDirectories).Select(x => AssetDatabase.GUIDToAssetPath(x)).ToArray(); ProcessAssets(resourceAssetPaths, "resources", ref uniqueAssetInSceneBundle, ref extToAssetList); AssetBundleBuild resourceBundle = new AssetBundleBuild(); resourceBundle.assetNames = uniqueAssetInSceneBundle.Keys.ToArray(); resourceBundle.assetBundleName = OVRSceneLoader.resourceBundleName; assetBundleBuilds.Add(resourceBundle); } // Create scene bundle output directory string sceneBundleDirectory = Path.Combine(BUNDLE_MANAGER_OUTPUT_PATH, BUNDLE_MANAGER_MASTER_BUNDLE); if (!Directory.Exists(sceneBundleDirectory)) { Directory.CreateDirectory(sceneBundleDirectory); } OVRBundleTool.PrintLog("Building scene bundles . . . "); DateTime labelingStart = DateTime.Now; for (int i = 0; i < sceneList.Count; ++i) { var scene = sceneList[i]; if (!scene.shouldDeploy) { continue; } // Get all the assets that the scene depends on and sort them by type DateTime getDepStart = DateTime.Now; string[] assetDependencies = AssetDatabase.GetDependencies(scene.scenePath); Debug.Log("[OVRBundleManager] - " + scene.sceneName + " - Calculated scene asset dependencies in: " + (DateTime.Now - getDepStart).TotalSeconds); ProcessAssets(assetDependencies, scene.sceneName, ref uniqueAssetInSceneBundle, ref extToAssetList); // Add the scene into it's own bundle string[] sceneAsset = new string[1] { scene.scenePath }; AssetBundleBuild sceneBuild = new AssetBundleBuild(); sceneBuild.assetBundleName = "scene_" + scene.sceneName; sceneBuild.assetNames = sceneAsset; assetBundleBuilds.Add(sceneBuild); } // Chunk the asset bundles by number of assets foreach (string ext in extToAssetList.Keys) { int assetCount = extToAssetList[ext].Count; int numChunks = (assetCount + BUNDLE_CHUNK_SIZE - 1) / BUNDLE_CHUNK_SIZE; //Debug.Log(ext + " has " + assetCount + " asset(s) that will be split into " + numChunks + " chunk(s)"); for (int i = 0; i < numChunks; i++) { List <string> assetChunkList; if (i == numChunks - 1) { int size = BUNDLE_CHUNK_SIZE - (numChunks * BUNDLE_CHUNK_SIZE - assetCount); assetChunkList = extToAssetList[ext].GetRange(i * BUNDLE_CHUNK_SIZE, size); } else { assetChunkList = extToAssetList[ext].GetRange(i * BUNDLE_CHUNK_SIZE, BUNDLE_CHUNK_SIZE); } AssetBundleBuild build = new AssetBundleBuild(); build.assetBundleName = "asset_" + ext + i; build.assetNames = assetChunkList.ToArray(); //Debug.Log("Chunk " + i + " has " + assetChunkList.Count + " asset(s)"); assetBundleBuilds.Add(build); } } Debug.Log("[OVRBundleManager] - Created chucked scene bundles in: " + (DateTime.Now - labelingStart).TotalSeconds); // Build asset bundles BuildPipeline.BuildAssetBundles(sceneBundleDirectory, assetBundleBuilds.ToArray(), BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android); double bundleBuildTime = (DateTime.Now - totalStart).TotalSeconds; Debug.Log("[OVRBundleManager] - Total Time: " + bundleBuildTime); }