Loupe

[Unity] Créer une build personnalisée pour WP8/W8

Si vous développez un jeu qui cible Windows Phone 8 ou Windows Store Apps, vous allez probablement utiliser certaines fonctionnalités comme le partage, les tuiles dynamiques, …

Cela peut être fait en utilisant certains mécanismes que j’ai expliqué dans un article précédent et il serait plutôt cool de pouvoir inclure automatiquement dans notre build les fichiers que l’on a modifié (MainPage, splashscreen, tuiles, …)

Créer un menu personnalisé

La première étape consiste à créer une entrée dans le menu pour accéder à notre build plus facilement.

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
 
public class AutoBuilderMenu : MonoBehaviour
{
  [MenuItem("AutoBuilder/WP8")]
  private static void PerformBuild()
  {
    // TODO : Build and replace files
  }
}

Pour plus d’informations sur les MenuItem : http://blogs.infinitesquare.com/b/unity-creer-des-menus-personnalises

Build simple

Ce script va simplement compiler le projet Unity et le convertir en projet WP8 ou W8.

Le nouveau projet sera créé dans le dossier : [PROJECT_BASE_UNITY]/../Builds/{ProjectName}/{BundleVersion}/{TargetPlatform}/{BundleIdentifier} afin de garder un historique de chaque version dans un dossier spécifique.

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
 
public class AutoBuilderMenu : MonoBehaviour
{
  [MenuItem("AutoBuilder/WP8")]
  private static void PerformBuild()
  {
    // Save current editor build target
    var currentTarget = EditorUserBuildSettings.activeBuildTarget;
    EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.WP8Player);
 
    var buildPath = GetBuildPath(target);
    var path = Path.GetDirectoryName(buildPath);
 
    var folderExists = Directory.Exists(path);
    if (!folderExists)
      Directory.CreateDirectory(path);
 
    // Create solution folder and project files
    BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
 
    // Set saved build target
    EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
  }
 
  private static string GetProjectName()
  {
    string[] s = Application.dataPath.Split('/');
    return s[s.Length - 2];
  }
 
  private static string[] GetScenePaths()
  {
    return EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
  }
 
  private static string GetBuildPath(BuildTarget target)
  {
    var extension = String.Empty;
 
    return String.Format("../Builds/{0}/{1}/{2}/{3}",
      GetProjectName(),
      PlayerSettings.bundleVersion,
      target.ToString(),
      PlayerSettings.bundleIdentifier);
  }
}

Build personnalisée

L’astuce est de compiler deux fois le jeu. La première fois pour créer le projet de base avec les fichiers par défaut, puis on remplace les fichiers que l’on souhaite modifier (MainPage, tuiles, …). Pour finir, on relance la compilation une seconde fois pour prendre en compte les fichiers que l’on a remplacés.

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
 
public class AutoBuilderMenu : MonoBehaviour
{
  [MenuItem("AutoBuilder/WP8")]
  private static void PerformBuild()
  {
    // Save current editor build target
    var currentTarget = EditorUserBuildSettings.activeBuildTarget;
    EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.WP8Player);
 
    var buildPath = GetBuildPath(target);
    var path = Path.GetDirectoryName(buildPath);
 
    var folderExists = Directory.Exists(path);
    if (!folderExists)
      Directory.CreateDirectory(path);
 
    // First build to create solution folder and project files
    BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
 
    // Replace custom files
    UpdateWP8Settings(buildPath);
 
    // Rebuild with replacing files
    BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
 
    // Set saved editor build target
    EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
  }
 
  private static void UpdateWP8Settings(string buildPath)
  {
    // SplashScreenImage
    var replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/SplashScreenImage.jpg");
    var current = string.Format("{0}/{1}/SplashScreenImage.jpg", buildPath, PlayerSettings.bundleIdentifier);
    if (File.Exists(replace))
      File.Copy(replace, current, true);
 
    // MainPage.xaml.cs
    replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/MainPage.xaml.cs");
    current = string.Format("{0}/{1}/MainPage.xaml.cs", buildPath, PlayerSettings.bundleIdentifier);
    if (File.Exists(replace))
      File.Copy(replace, current, true);    
 
    // ApplicationIcon
    replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/ApplicationIcon.png");
    current = string.Format("{0}/{1}/Assets/ApplicationIcon.png", buildPath, PlayerSettings.bundleIdentifier);
    if (File.Exists(replace))
      File.Copy(replace, current, true);
 
    // WMAppManifest
    replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/WMAppManifest.xml");
    current = string.Format("{0}/{1}/Properties/WMAppManifest.xml", buildPath, PlayerSettings.bundleIdentifier);
    if (File.Exists(replace))
      File.Copy(replace, current, true);
  }
 
  private static string GetProjectName()
  {
    string[] s = Application.dataPath.Split('/');
    return s[s.Length - 2];
  }
 
  private static string[] GetScenePaths()
  {
    return EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
  }
 
  private static string GetBuildPath(BuildTarget target)
  {
    return String.Format("../Builds/{0}/{1}/{2}/{3}",
      GetProjectName(),
      PlayerSettings.bundleVersion,
      target.ToString(),
      PlayerSettings.bundleIdentifier);
  }
}

Une façon plus élégante

Dans le script précédent, nous copions chaque fichiers “à la main”, ce qui n’est pas vraiment très pratique. Une autre possibilité est de copier le dossier contentant l’ensemble des fichiers modifiés pour WP8/W8 (BuildSettings/WP8 par exemple) automatiquement.

private static void PerformBuild(BuildTarget target, bool isBeta = false)
{
  var currentTarget = EditorUserBuildSettings.activeBuildTarget;
  EditorUserBuildSettings.SwitchActiveBuildTarget(target);
 
  var buildPath = GetBuildPath(target);
  var path = Path.GetDirectoryName(buildPath);
 
  var folderExists = Directory.Exists(path);
  if (!folderExists)
l  {
    Directory.CreateDirectory(path);
  }
 
  BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
 
  if (target == BuildTarget.WP8Player)
  {
    UpdateWP8Settings(buildPath, string.Concat(Application.dataPath, "/../BuildSettings/WP8/"), string.Concat(buildPath, "/"));
    if (isBeta)
    {
      UpdateWP8Settings(buildPath, string.Concat(Application.dataPath, "/../BuildSettings/WP8_Beta/"), string.Concat(buildPath, "/"));
 
    }
    BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
  }
 
  EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
}
 
private static void UpdateWP8Settings(string buildPath, string sourceRootPath, string destinationRootPath = "")
{
  var files = Directory.GetFiles(sourceRootPath);
  foreach (var file in files)
  {
    var replace = file;
    var fileName = replace.Split('/').LastOrDefault().Split('\\').LastOrDefault();
    var current = string.Concat(destinationRootPath, "/" + fileName);
    File.Copy(replace, current, true);
  }
 
  var directories = Directory.GetDirectories(sourceRootPath);
  foreach (var directory in directories)
  {
    var folderName = directory.Split('/').LastOrDefault().Split('\\').LastOrDefault();
    UpdateWP8Settings(buildPath, directory, destinationRootPath + "/" + folderName);
  }
}

Voici la hiérarchie des dossiers que j’ai mis en place :

unity_custom_build

Merci Jonathan pour l’astuce.

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus