Vision Pro/Unity/Poly Spatial开发笔记整理【四】(打包工具)

打包工具

在多次打包尝试中,不断的切换打包名称和打包类型成了一件很麻烦的事情,而且还要区分类型进行文件夹管理,于是就诞生了写一个打包工具的想法。
打包工具截图

具体步骤

  • 获取Vision OS Settings配置
  • 根据当前配置设置打包的场景
  • 设置打包输出文件夹类型

关键步骤:获取打包平台配置

VisionOSSettings

成员类型成员名称描述作用
字段k_SettingsKey用于存储和检索VisionOSSettings实例的键。用于在Player设置中保存和加载配置数据。
字段k_HandTrackingUsageTooltip手部追踪用途描述的提示信息。用于在请求手部追踪授权时向用户展示的描述信息。
字段k_WorldSensingUsageTooltip世界感知用途描述的提示信息。用于在请求世界感知授权时向用户展示的描述信息。
枚举AppMode定义应用程序的模式:虚拟现实(VR)、混合现实(MR)或窗口化(Windowed)。用于设置应用程序的初始模式。
字段m_AppMode应用程序的初始模式。用于获取或设置应用程序的初始模式。
字段m_HandsTrackingUsageDescription手部追踪用途的描述。用于提供手部追踪用途的描述,将添加到生成的visionOS Player Xcode项目的Info.plist文件中。
字段m_WorldSensingUsageDescription世界感知用途的描述。用于提供世界感知用途的描述,将添加到生成的visionOS Player Xcode项目的Info.plist文件中。
属性appMode获取或设置应用程序的模式。用于获取或设置m_AppMode字段的值。
属性handsTrackingUsageDescription获取或设置手部追踪用途的描述。用于获取或设置m_HandsTrackingUsageDescription字段的值。
属性worldSensingUsageDescription获取或设置世界感知用途的描述。用于获取或设置m_WorldSensingUsageDescription字段的值。
方法GetOrCreateSettings获取当前选中的设置,或者如果没有设置则创建默认设置。用于获取或创建VisionOSSettings实例。
属性currentSettings获取或设置用于Player构建的VisionOSSettings用于获取或设置当前的VisionOSSettings实例。
方法TrySelect尝试选择当前的VisionOSSettings实例。用于将当前的VisionOSSettings实例设置为活动对象。
方法GetSerializedSettings获取VisionOSSettings的序列化对象。用于创建VisionOSSettings实例的SerializedObject

这个文件是通过Package ManagerAdd Package By Name导入com.unity.polyspatial才会出现,文件位置是:"Assets/XR/Settings/VisionOSSettings.asset",。

读取VisionOSSettings方法

以下是读取配置文件的代码:

/// <summary>
/// 加载关于VisionOS的配置参数
/// </summary>
private void LoadSettings()
{
	var configPath = "Assets/XR/Settings/VisionOSSettings.asset";
	_visionOSSettings = AssetDatabase.LoadAssetAtPath<VisionOSSettings>(configPath);
}

获取当前打包的版本

这段代码提供了一个下拉菜单,让开发者在Unity编辑器中选择VisionOS项目的构建类型:实机(Device)或模拟器(Simulator)。选择结果会更新项目的构建设置,确保生成的应用适配目标平台。

PlayerSettings.VisionOS.sdkVersion =
            (VisionOSSdkVersion)EditorGUILayout.EnumPopup(PlayerSettings.VisionOS.sdkVersion);

以及选择的版本的枚举类型:

/// <summary>
///   <para>支持的VisionOS SDK版本</para>
/// </summary>
public enum VisionOSSdkVersion
{
    /// <summary>
    ///   <para>设备SDK</para>
    /// </summary>
    Device,
    /// <summary>
    ///   <para>模拟器SDK</para>
    /// </summary>
    Simulator,
}

根据当前配置设置打包的场景

InitBuildScenes用于初始化场景的默认列表,DrawSceneOptions在编辑器中提供界面让用户自定义每个场景的构建配置并保存。

/// <summary>
/// 初始化构建项目的参数
/// </summary>
private void InitBuildScenes()
{
	_sceneConfigs = new Dictionary<string, VisionOSSettings.AppMode>();
	foreach (var editorBuildSettingsScene in EditorBuildSettings.scenes)
		_sceneConfigs.Add(editorBuildSettingsScene.path, VisionOSSettings.AppMode.MR);
}

/// <summary>
/// 绘制所有场景的配置项
/// </summary>
private void DrawSceneOptions()
{
	GUILayout.Space(5f);
	GUILayout.Label("场景类型配置选择:");

	GUILayout.BeginVertical("HelpBox");

	for (int i = 0; i < EditorBuildSettings.scenes.Length; i++)
	{
		var editorBuildSetting = EditorBuildSettings.scenes[i];
		GUILayout.BeginHorizontal();
		GUILayout.Label(editorBuildSetting.path, GUILayout.Width(250f));
			_sceneConfigs[editorBuildSetting.path] =
                (VisionOSSettings.AppMode)EditorGUILayout.EnumPopup(_sceneConfigs[editorBuildSetting.path]);
		GUILayout.EndHorizontal();
	}

	GUILayout.EndVertical();
	if (GUILayout.Button("保存配置")) SaveLocalData();
}

开始打包Xcode工程输出到指定目录

这段代码用于构建VisionOS项目,通过选择匹配的场景并指定输出路径。OnClickBuildVisionOSProject触发构建流程,GetEnabledScenes获取要包含的场景。



/// <summary>
/// 点击构建VisionOS项目
/// </summary>
private void OnClickBuildVisionOSProject()
{
	_outputXcodeProject =
	$"{_outputPath}/{_visionOSAppMode}/{PlayerSettings.VisionOS.sdkVersion}/{DateTime.Now:yyMMddHHmm}";

	if (!Directory.Exists(_outputXcodeProject))
		Directory.CreateDirectory(_outputXcodeProject);

	var scenes = GetEnabledScenes();
	if (scenes.Length == 0) _exceptionMessage = "没有满足条件的场景";

	var buildXcodeProjectPath = Path.Combine(_outputXcodeProject, "");

	if (!string.IsNullOrEmpty(_exceptionMessage)) return;

	var result = BuildPipeline.BuildPlayer(new BuildPlayerOptions
	{
		scenes = scenes,
		locationPathName = buildXcodeProjectPath,
		target = BuildTarget.VisionOS,
		options = BuildOptions.None
	});
}


/// <summary>
/// 获取当前已激活场景
/// </summary>
/// <returns>符合当前打包模式的场景列表</returns>
private string[] GetEnabledScenes()
{
	var scenes = new List<string>();
	for (var i = 0; i < EditorBuildSettings.scenes.Length; i++)
	{
		var scenePath = EditorBuildSettings.scenes[i].path;
		if (_sceneConfigs[scenePath] == _visionOSAppMode)
			scenes.Add(scenePath);
	}

	return scenes.ToArray();
}

完整代码

using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Unity.VisualScripting;
using UnityEditor;
using UnityEditor.XR.VisionOS;
using UnityEngine;
using UnityEngine.XR;

public class VisionProBuildingWindow : EditorWindow
{
    private VisionOSSettings _visionOSSettings;

    private VisionOSSettings.AppMode _visionOSAppMode;

    private string _outputPath, _outputXcodeProject;

    private Dictionary<string, VisionOSSettings.AppMode> _sceneConfigs;

    private string[] _editorBuildSettingsScenes;

    private string _exceptionMessage;

    [MenuItem("Window/Tools/VisionProBuildingWindow")]
    private static void ShowWindow()
    {
        var window = GetWindow(typeof(VisionProBuildingWindow));
        window.titleContent = new GUIContent("设置VisionOS导出选项");
    }

    private void Awake()
    {
        InitWindowData();
        LoadSettings();
    }

    private void InitWindowData()
    {
        InitLocalData();
        InitOutputParams();
    }

    private void InitOutputParams()
    {
        _outputPath = $"{Application.dataPath.Replace("/Assets", "")}/Out";
    }


    /// <summary>
    /// 初始化本地存储的配置数据
    /// </summary>
    private void InitLocalData()
    {
        var data = EditorPrefs.GetString($"{nameof(VisionProBuildingWindow)}.EnableScene");
        if (string.IsNullOrEmpty(data)) InitBuildScenes();
        else _sceneConfigs = JsonConvert.DeserializeObject<Dictionary<string, VisionOSSettings.AppMode>>(data);
    }


    /// <summary>
    /// 初始化构建项目的参数
    /// </summary>
    private void InitBuildScenes()
    {
        _sceneConfigs = new Dictionary<string, VisionOSSettings.AppMode>();
        foreach (var editorBuildSettingsScene in EditorBuildSettings.scenes)
            _sceneConfigs.Add(editorBuildSettingsScene.path, VisionOSSettings.AppMode.MR);
    }

    /// <summary>
    /// 保存本地存储的配置数据
    /// </summary>
    private void SaveLocalData()
    {
        EditorPrefs.SetString(
            $"{nameof(VisionProBuildingWindow)}.EnableScene",
            JsonConvert.SerializeObject(_sceneConfigs));
    }

    private void OnFocus()
    {
        InitWindowData();
    }

    /// <summary>
    /// 加载关于VisionOS的配置参数
    /// </summary>
    private void LoadSettings()
    {
        var configPath = "Assets/XR/Settings/VisionOSSettings.asset";
        _visionOSSettings = AssetDatabase.LoadAssetAtPath<VisionOSSettings>(configPath);
    }

    /// <summary>
    /// 切换当前VisionOS打包显示类型
    /// </summary>
    /// <param name="appMode">1=VR,2=MR,3=Windowed</param>
    private void SwitchVisionOSMode(VisionOSSettings.AppMode appMode)
    {
        if (_visionOSSettings == null) return;
        if (_visionOSSettings.appMode == appMode) return;
        _visionOSSettings.appMode = appMode;
        EditorUtility.SetDirty(_visionOSSettings);
        AssetDatabase.SaveAssetIfDirty(_visionOSSettings);
    }

    private void OnGUI()
    {
        DrawProjectOptions();
        DrawSceneOptions();
        DrawBuildOptions();
    }

    /// <summary>
    /// 绘制项目的
    /// </summary>
    private void DrawProjectOptions()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("当前选择的打包类型", GUILayout.Width(150f));
        PlayerSettings.VisionOS.sdkVersion =
            (VisionOSSdkVersion)EditorGUILayout.EnumPopup(PlayerSettings.VisionOS.sdkVersion);
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("当前输出的打包路径", GUILayout.Width(150f));
        GUILayout.Label(_outputXcodeProject);
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("当前选中的打包模式", GUILayout.Width(150f));
        _visionOSAppMode = (VisionOSSettings.AppMode)EditorGUILayout.EnumPopup(_visionOSAppMode);
        SwitchVisionOSMode(_visionOSAppMode);
        GUILayout.EndHorizontal();
    }

    /// <summary>
    /// 绘制所有场景的配置项
    /// </summary>
    private void DrawSceneOptions()
    {
        GUILayout.Space(5f);
        GUILayout.Label("场景类型配置选择:");

        GUILayout.BeginVertical("HelpBox");

        for (int i = 0; i < EditorBuildSettings.scenes.Length; i++)
        {
            var editorBuildSetting = EditorBuildSettings.scenes[i];
            GUILayout.BeginHorizontal();
            GUILayout.Label(editorBuildSetting.path, GUILayout.Width(250f));
            _sceneConfigs[editorBuildSetting.path] =
                (VisionOSSettings.AppMode)EditorGUILayout.EnumPopup(_sceneConfigs[editorBuildSetting.path]);
            GUILayout.EndHorizontal();
        }

        GUILayout.EndVertical();

        if (GUILayout.Button("保存配置")) SaveLocalData();
    }

    /// <summary>
    /// 绘制Build参数选项和按钮
    /// </summary>
    private void DrawBuildOptions()
    {
        GUILayout.Space(5f);
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        if (GUILayout.Button("开始创建工程", GUILayout.Width(200f), GUILayout.Height(60f)))
            OnClickBuildVisionOSProject();

        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();

        if (string.IsNullOrEmpty(_exceptionMessage))
            return;
        GUILayout.BeginHorizontal("HelpBox");
        GUILayout.Label($"{_exceptionMessage}");
        GUILayout.EndHorizontal();
    }

    /// <summary>
    /// 点击构建VisionOS项目
    /// </summary>
    private void OnClickBuildVisionOSProject()
    {
        _outputXcodeProject =
            $"{_outputPath}/{_visionOSAppMode}/{PlayerSettings.VisionOS.sdkVersion}/{DateTime.Now:yyMMddHHmm}";

        if (!Directory.Exists(_outputXcodeProject))
            Directory.CreateDirectory(_outputXcodeProject);

        var scenes = GetEnabledScenes();
        if (scenes.Length == 0) _exceptionMessage = "没有满足条件的场景";

        var buildXcodeProjectPath = Path.Combine(_outputXcodeProject, "");

        if (!string.IsNullOrEmpty(_exceptionMessage)) return;

        var result = BuildPipeline.BuildPlayer(new BuildPlayerOptions
        {
            scenes = scenes,
            locationPathName = buildXcodeProjectPath,
            target = BuildTarget.VisionOS,
            options = BuildOptions.None
        });
    }


    /// <summary>
    /// 获取当前已激活场景
    /// </summary>
    /// <returns>符合当前打包模式的场景列表</returns>
    private string[] GetEnabledScenes()
    {
        var scenes = new List<string>();
        for (var i = 0; i < EditorBuildSettings.scenes.Length; i++)
        {
            var scenePath = EditorBuildSettings.scenes[i].path;
            if (_sceneConfigs[scenePath] == _visionOSAppMode)
                scenes.Add(scenePath);
        }

        return scenes.ToArray();
    }
}
  • 22
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值