// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#if !UNITY_2018_3_OR_NEWER
using System;
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
namespace Google.Android.AppBundle.Editor.Internal.BuildTools
{
///
/// Runs a task after a player build causes the application domain to reset and scripts to be reloaded.
/// Starting with Unity 2018.3 player builds no longer reset the application domain.
///
public static class PostBuildRunner
{
///
/// Class that provides an abstraction layer above in order to capture
/// the task's full type name, which is needed for task deserialization.
///
[Serializable]
private class TaskConfig
{
///
/// Location of the serialized file.
///
public string taskFilePath;
///
/// The full type name of the class that was serialized at .
///
public string taskTypeName;
}
private static readonly string PostBuildTaskConfigFilePath =
Path.Combine("Library", "PlayPostBuildTaskConfig.json");
private static float _progress;
///
/// Serializes the specified task to disk for running after scripts are reloaded.
///
public static void RunTask(PostBuildTask task)
{
if (File.Exists(PostBuildTaskConfigFilePath))
{
Debug.LogWarningFormat(
"Creating a new post-build task when one already exists: {0}", PostBuildTaskConfigFilePath);
}
var taskFilePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var taskConfig = new TaskConfig {taskFilePath = taskFilePath, taskTypeName = task.GetType().FullName};
SerializeToJson(taskFilePath, task);
SerializeToJson(PostBuildTaskConfigFilePath, taskConfig);
_progress = 0.0f;
// We don't unsubscribe from updates (except when canceling) because script reload will reset everything.
EditorApplication.update += HandleUpdate;
}
[DidReloadScripts]
private static void DidReloadScripts()
{
if (!File.Exists(PostBuildTaskConfigFilePath))
{
// In the common case the scripts reloaded because of a script change, etc. Nothing to do.
return;
}
PostBuildTask postBuildTask;
try
{
// Hide the progress bar that was shown in HandleUpdate().
EditorUtility.ClearProgressBar();
Debug.LogFormat("Loading post-build task config file: {0}", PostBuildTaskConfigFilePath);
var taskConfigJsonText = File.ReadAllText(PostBuildTaskConfigFilePath);
var taskConfig = JsonUtility.FromJson(taskConfigJsonText);
var taskJsonText = File.ReadAllText(taskConfig.taskFilePath);
var taskTypeName = taskConfig.taskTypeName;
Debug.LogFormat("Loading and running post-build task for type: {0}", taskTypeName);
var postBuildTaskObj = JsonUtility.FromJson(taskJsonText, Type.GetType(taskTypeName));
postBuildTask = (PostBuildTask) postBuildTaskObj;
}
finally
{
// Remove the config file so that this task doesn't run again after the next application domain reset.
File.Delete(PostBuildTaskConfigFilePath);
}
postBuildTask.RunPostBuildTask();
}
// Handler for EditorApplication.update callbacks.
private static void HandleUpdate()
{
// Magic number to partially fill up the progress bar during the time that it takes scripts to reload.
// Note that the best number varies by version, but better to finish with the progress bar less than
// full on some versions than full long before scripts reload on other versions.
_progress += 0.0005f;
if (!EditorUtility.DisplayCancelableProgressBar("Waiting for scripts to reload...", null, _progress))
{
return;
}
Debug.Log("Canceling post-build task before scripts reload...");
// Since the existence of the config file is the signal to run a post-build task, delete the file to cancel.
File.Delete(PostBuildTaskConfigFilePath);
EditorUtility.ClearProgressBar();
EditorApplication.update -= HandleUpdate;
}
private static void SerializeToJson(string path, object obj)
{
var jsonText = JsonUtility.ToJson(obj);
File.WriteAllText(path, jsonText);
}
}
}
#endif