【狂云歌之unity_vr】unity项目持续集成dailybuild以及多平台打包管理

前言

 持续集成的意义就不多说了。unity通常打包一般就直接build&run,但是在实际项目中,往往直接在服务器build包,所以命令行打包必不可少,这里一方面分享unity打包做持续集成,一方面分享使用unity管理多平台打包,例如一个vrapp需要支持gear版本,支持小米版本,支持cardboard版本等等~懂的人就知道这里具有一定的管理维护成本。

 我们做vr相关的app,需要支持gear、cardboard、小米、vivo、大朋、暴风、Idealens、pico、nibiru、酷开等一大堆平台,曾经还有lg和htcvive、oculus平台,未来还会有更多的平台,所以关于unity项目的多平台管理是很重要的,在这方面我们也在探索,积累了一点经验。这里介绍的主要是基于unity中c#写的打包和多平台管理,如果将其中一部分功能使用python和其他配置文件来实现也是可以的,只是用c#直接做会方便许多。

jenkins

https://jenkins.io/index.html

 jenkins不用多说,懂的人都了解是干什么的,来源于hudson,可以比较容易的搭起一个持续集成服务器,支持svn和git等版本管理。支持bash,所以可以用bash、python等大部分脚本来写打包脚本和前后的处理。

unity命令行打包

 unity如何进行命令行打包呢,其实unity是支持以命令行方式启动的,但是需要关闭editor支持执行命令,如下:

${unity可执行文件路径} -projectPath ${项目路径}
-executeMethod CloudBuild.PerformBuildAndroidCloudAlphaRelease
-batchmode -quit -logFile ${放log的路径}
-ForceExitEditor

 整体比较容易理解,其中CloudBuild.PerformBuildAndroidCloudAlphaRelease是一个类的静态方法,然后在这个方法中写打包相关逻辑即可。

EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.Android);
string[] scenes = { "Assets/Scenes/Init.unity", "Assets/Scenes/Main.unity" };
BuildPipeline.BuildPlayer(scenes, buildpath, BuildTarget.Android, BuildOptions.None);

 核心逻辑就这么多,就会开始打一个android包并且生成到buildpath下面

多平台打包管理

准备工作

 对unity插件不熟悉的可以看下 开发unity插件——一次搞定unity编辑器常用功能

 我这里准备了一个全局的配置文件,当然这个可以使用外部配置文件来管理配置,是一个道理的。这里定义了两个平台版本一个是alpha一个是beta,使用宏来区分不同平台的版本号。

using UnityEngine;
using System.Collections;public class GlobalConfig {
#if CLOUD_ALPHApublic const int ClientVersionCode = 1;public const string ClientVersion = "1.0";
#elif CLOUD_BETApublic const int ClientVersionCode = 2;public const string ClientVersion = "1.1";
#endif
}

 文件目录组织大概如下,其中CloudBuild是编辑器工具,包含菜单项和打包功能,两个平台分别依赖不同的so文件和manifest文件。

 制作了一个menu,主要包含的功能是可以在alpha和beta平台之间切换,可以打alpha平台的apk包,当然想打beta平台的包只需要简单修改。

manifest管理

 写个简单的脚本进行manifest替换就好,对于alpha平台和beta平台各有自己的manifest文件,在切换平台的时候将对应的manifest复制替换。

/// <summary>
///  使用相应的androidmanifest
/// </summary>
static void UseAndroidManifest(string filename)
{string src_filename = string.Format("AndroidManifest-{0}.xml", filename);string dst_filename = "AndroidManifest.xml";string path = Application.dataPath + "/Plugins/Android/";File.Copy(path + src_filename, path + dst_filename, true);AssetDatabase.Refresh();//因为修改了manifest文件,所以刷新unity的assets
}

依赖包管理

 为什么要做依赖包管理呢?因为在使用不同平台sdk的时候,可能会引入很多sdk,每个sdk里包含自己的so、jar、aar包等,如果什么都不管理,直接打包的话,那么这些依赖的文件都会打进所有的apk包,简单来说就会增加包的体积,更严重的情况下,这些不同平台sdk里的依赖库可能还会有冲突,如果打进同一个apk包,后果不堪设想~

 做依赖包管理主要依赖unity自己的assetimport管理如下图,那么只要在需要的时候勾选不需要的时候取消勾选就好了,我们要做的就是用代码来自动实现这个功能。

 先准备好各个平台的依赖包路径

static string[] Plugins_Alpha = new string[] {"Assets/Plugins/Android/libs/armeabi-v7a/alpha.so",
};static string[] Plugins_Beta = new string[] {"Assets/Plugins/Android/libs/armeabi-v7a/beta.so",
};

 然后在切换不同平台的时候对这些依赖包的import做处理,这块Asset属于plugin,所以使用pluginimporter来管理勾选的问题。

static void ChangePluginToAlpha()
{SetEnablePluginImport(Plugins_Alpha, true);SetEnablePluginImport(Plugins_Beta, false);
}static void ChangePluginToBeta()
{SetEnablePluginImport(Plugins_Alpha, false);SetEnablePluginImport(Plugins_Beta, true);
}static void SetEnablePluginImport(string[] plugins, bool enable = true)
{foreach(var path in plugins){PluginImporter vrlib = AssetImporter.GetAtPath(path) as PluginImporter;vrlib.SetCompatibleWithPlatform(BuildTarget.Android, enable);}
}

 非常简单一看就可以懂,然后试一下就明白了。

平台切换

 平台切换功能主要是在editor里调试各个平台功能的时候使用的菜单项,功能也很简单,就做了下面几件事情

  • 切平台和宏定义
  • 切playersetting参数
  • 切buildscene配置
  • 切manifest和依赖包
  • 保存及打开对应平台的场景(如果场景不是复用的)

 代码示例如下,因为我们做vr相关的app,所以在gear平台时vrsupport为true,其他平台时为false,如果不同平台的scene不一样,那么在最后问用户是否保存当前场景,然后打开对应平台的场景。

/// <summary>
/// 切换alpha平台
/// </summary>
[UnityEditor.MenuItem("CloudBuild/SwitchToAlpha", priority = 50)]
static void SwitchToAlpha()
{PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, DEFINES_ALPHA);PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, DEFINES_ALPHA);PlayerSettings.virtualRealitySupported = true;EditorBuildSettings.scenes = new EditorBuildSettingsScene[] {new EditorBuildSettingsScene("Assets/Scenes/Init.unity", true),new EditorBuildSettingsScene("Assets/Scenes/Main.unity", true)};//场景UseAndroidManifest("Alpha");ChangePluginToAlpha();EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();EditorSceneManager.OpenScene("Assets/Scenes/Main.unity");
}

打包

 那么最后打包脚本如下,粗看信息量可能比较大,实际只做了几件事情

  • 准备好要打包的scene
  • 将当前editor的状态保存一下,以便打完包恢复,这是为了开发使用方便而已,否则在开发机上打个包就发现editor的很多属性变了有时很尴尬
  • 处理android的签名问题
  • 打包
  • 最后如果是windows,一般是开发机,直接打开build好的apk所在文件夹,方便使用
/// <summary>
/// </summary>
[UnityEditor.MenuItem("CloudBuild/CloudAlpha-Release")]
static void PerformBuildAndroidCloudAlphaRelease()
{EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.Android);string[] scenes = { "Assets/Scenes/Init.unity", "Assets/Scenes/Main.unity" };string path = GetBuildPathAndroid();if (scenes == null || scenes.Length == 0 || path == null){Debug.LogError("error scene is null");return;}string tempid = PlayerSettings.bundleIdentifier;string name = PlayerSettings.productName;bool virtualRealitySupported = PlayerSettings.virtualRealitySupported;PlayerSettings.virtualRealitySupported = true;PlayerSettings.bundleIdentifier = "net.itsong.vralpha";PlayerSettings.productName = PRODUCT_NAME;PlayerSettings.Android.keystoreName = "";PlayerSettings.Android.keyaliasName = "";PlayerSettings.Android.keyaliasPass = "";PlayerSettings.Android.keystorePass = "";PlayerSettings.Android.bundleVersionCode = GlobalConfig.ClientVersionCode;PlayerSettings.bundleVersion = GlobalConfig.ClientVersion;string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android);UseAndroidManifest("Alpha");ChangePluginToAlpha();PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, DEFINES_ALPHA + DEFINES_RELEASE);string buildpath = path + string.Format("cloudvr_alpha_release_{0}.apk", DateTime.Now.ToString("MMddHHmm", DateTimeFormatInfo.InvariantInfo));BuildPipeline.BuildPlayer(scenes, buildpath, BuildTarget.Android, BuildOptions.None);PlayerSettings.virtualRealitySupported = virtualRealitySupported;PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, defines);PlayerSettings.bundleIdentifier = tempid;PlayerSettings.productName = name;PlayerSettings.Android.keystoreName = "";PlayerSettings.Android.keyaliasName = "";PlayerSettings.Android.keyaliasPass = "";PlayerSettings.Android.keystorePass = "";string dir = path.Replace('/', '\\');
#if UNITY_EDITOR_WINSystem.Diagnostics.Process.Start("explorer.exe", "\"" + dir + "\"");
#endif
}

 完整的CloudBuild文件如下:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System;
using System.Globalization;
using UnityEditor.SceneManagement;
/// <summary>
/// </summary>
partial class CloudBuild
{const string PRODUCT_NAME = "狂云歌VR";const string DEFINES_ALPHA  = "CROSS_PLATFORM_INPUT;MOBILE_INPUT;CLOUD_ALPHA;";const string DEFINES_BETA = "CROSS_PLATFORM_INPUT;MOBILE_INPUT;CLOUD_BETA;";const string DEFINES_RELEASE = "CLOUD_RELEASE";static string[] Plugins_Alpha = new string[] {"Assets/Plugins/Android/libs/armeabi-v7a/alpha.so",};static string[] Plugins_Beta = new string[] {"Assets/Plugins/Android/libs/armeabi-v7a/beta.so",};// Build the Android APK and place into main project folderstatic string GetBuildPathAndroid(){string dirPath = Application.dataPath + "/../build/android/";if (!System.IO.Directory.Exists(dirPath)){System.IO.Directory.CreateDirectory(dirPath);}return dirPath;}/// <summary>/// </summary>[UnityEditor.MenuItem("CloudBuild/CloudAlpha-Release")]static void PerformBuildAndroidCloudAlphaRelease(){EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.Android);string[] scenes = { "Assets/Scenes/Init.unity", "Assets/Scenes/Main.unity" };string path = GetBuildPathAndroid();if (scenes == null || scenes.Length == 0 || path == null){Debug.LogError("error scene is null");return;}string tempid = PlayerSettings.bundleIdentifier;string name = PlayerSettings.productName;bool virtualRealitySupported = PlayerSettings.virtualRealitySupported;PlayerSettings.virtualRealitySupported = true;PlayerSettings.bundleIdentifier = "net.itsong.vralpha";PlayerSettings.productName = PRODUCT_NAME;PlayerSettings.Android.keystoreName = "";PlayerSettings.Android.keyaliasName = "";PlayerSettings.Android.keyaliasPass = "";PlayerSettings.Android.keystorePass = "";PlayerSettings.Android.bundleVersionCode = GlobalConfig.ClientVersionCode;PlayerSettings.bundleVersion = GlobalConfig.ClientVersion;string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android);UseAndroidManifest("Alpha");ChangePluginToAlpha();PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, DEFINES_ALPHA + DEFINES_RELEASE);string buildpath = path + string.Format("cloudvr_alpha_release_{0}.apk", DateTime.Now.ToString("MMddHHmm", DateTimeFormatInfo.InvariantInfo));BuildPipeline.BuildPlayer(scenes, buildpath, BuildTarget.Android, BuildOptions.None);PlayerSettings.virtualRealitySupported = virtualRealitySupported;PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, defines);PlayerSettings.bundleIdentifier = tempid;PlayerSettings.productName = name;PlayerSettings.Android.keystoreName = "";PlayerSettings.Android.keyaliasName = "";PlayerSettings.Android.keyaliasPass = "";PlayerSettings.Android.keystorePass = "";string dir = path.Replace('/', '\\');
#if UNITY_EDITOR_WINSystem.Diagnostics.Process.Start("explorer.exe", "\"" + dir + "\"");
#endif}/// <summary>/// 切换alpha平台/// </summary>[UnityEditor.MenuItem("CloudBuild/SwitchToAlpha", priority = 50)]static void SwitchToAlpha(){PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, DEFINES_ALPHA);PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, DEFINES_ALPHA);PlayerSettings.virtualRealitySupported = true;EditorBuildSettings.scenes = new EditorBuildSettingsScene[] {new EditorBuildSettingsScene("Assets/Scenes/Init.unity", true),new EditorBuildSettingsScene("Assets/Scenes/Main.unity", true)};//场景UseAndroidManifest("Alpha");ChangePluginToAlpha();EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();EditorSceneManager.OpenScene("Assets/Scenes/Main.unity");}/// <summary>/// 切换beta平台/// </summary>[UnityEditor.MenuItem("CloudBuild/SwitchToBeta", priority = 50)]static void SwitchToBeta(){PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, DEFINES_BETA);PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, DEFINES_BETA);PlayerSettings.virtualRealitySupported = true;EditorBuildSettings.scenes = new EditorBuildSettingsScene[] {new EditorBuildSettingsScene("Assets/Scenes/Init.unity", true),new EditorBuildSettingsScene("Assets/Scenes/Main.unity", true)};//场景UseAndroidManifest("Beta");ChangePluginToBeta();EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();EditorSceneManager.OpenScene("Assets/Scenes/Main.unity");}/// <summary>///  使用相应的androidmanifest/// </summary>static void UseAndroidManifest(string filename){string src_filename = string.Format("AndroidManifest-{0}.xml", filename);string dst_filename = "AndroidManifest.xml";string path = Application.dataPath + "/Plugins/Android/";File.Copy(path + src_filename, path + dst_filename, true);PlayerSettings.Android.bundleVersionCode = GlobalConfig.ClientVersionCode;PlayerSettings.bundleVersion = GlobalConfig.ClientVersion;AssetDatabase.Refresh();}static void ChangePluginToAlpha(){SetEnablePluginImport(Plugins_Alpha, true);SetEnablePluginImport(Plugins_Beta, false);}static void ChangePluginToBeta(){SetEnablePluginImport(Plugins_Alpha, false);SetEnablePluginImport(Plugins_Beta, true);}static void SetEnablePluginImport(string[] plugins, bool enable = true){foreach(var path in plugins){PluginImporter vrlib = AssetImporter.GetAtPath(path) as PluginImporter;vrlib.SetCompatibleWithPlatform(BuildTarget.Android, enable);}}
}

后续

 这里没写build ios ipa包的过程,ios的build过程会稍微长一些,要先build好xcode project然后再通过xcode的命令行去打包,所以前半部分与android是可以复用的,只要稍加修改就可以支持ios的build。另外我们现在做vr相关的app,大部分都是android版本,所以apk的管理比较实用。

【狂云歌之unity_vr】unity项目持续集成dailybuild以及多平台打包管理相关推荐

  1. 【狂云歌之unity_vr】unity项目持续集成cibuilddailybuild

    [狂云歌之unity_vr]unity项目持续集成dailybuild以及多平台打包管理 前言  持续集成的意义就不多说了.unity通常打包一般就直接build&run,但是在实际项目中,往 ...

  2. 【狂云歌之unity_vr】VR开发中的优化

    [狂云歌之unity_vr]VR开发中的优化 前言 大概做了大半年的VR开发,HTCVive上与room scale和手柄控制器.激光相关的开发做过,gearvr使用oculus sdk开发做过,使用 ...

  3. Centos+Gitlab+Jenkins 针对.NET项目持续集成环境搭建和自动化部署

    目录 一.前言 二.系统环境 三.Gitlab安装 3.1 安装依赖软件 3.2 开启postfix 3.3 安装Gitlab 3.4 设置服务器IP和端口 3.5 重置并启动GitLab 3.6 浏 ...

  4. k8s和harbor的集成_爱威尔-基于kubernetes集群的项目持续集成(gitlab+harbor+Jenkins)安装...

    这个算是基于kubernetes集群的项目持续集成的前导篇,先把这用环境搭建好我们后面就可以专注做基于k8s的docker化项目持续集成了. gitlab安装 https://about.gitlab ...

  5. 完整项目持续集成方案

    完整项目持续集成方案 [docker|jenkins|git] 工具 本次持续集成使用到工具有:jenkins.maven.jdk.docker.docker私服[register].git. 发布流 ...

  6. 使项目持续集成支持Carthage管理

    2019独角兽企业重金招聘Python工程师标准>>> Travis CI是什么? Travis CI是在线托管的CI服务,用Travis来进行持续集成,不需要自己搭服务器,在网页上 ...

  7. jenkins部署流程图_一文教你使用 Jenkins 设计多环境、多项目持续集成环境!

    自动化部署主要是为了解决项目多.环境多.持续集成慢.部署操作麻烦.手动操作易出错.自动化运维等问题. Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建.部署.自动化 ...

  8. Practice - iOS 项目持续集成实践(一)

    For more, please visit my GitHub repo: github.com/kingcos/Per- Preface 一个软件工程项目从编写.到测试.再最终交付到用户通常有很多 ...

  9. Jenkins+Docker+Spring+Java项目持续集成(单机版)

    1.大致流程 流程说明: 1)开发人员每天把代码提交到 Gitlab 代码仓库 2)Jenkins 从 Gitlab 中拉取项目源码,编译并打成jar包,然后构建成 Docker 镜像,将镜像上传到 ...

最新文章

  1. 【干货】JDK动态代理的实现原理以及如何手写一个JDK动态代理
  2. 通过递归算法完成树的级联勾选的一般思路
  3. 配置apache2目录
  4. Silverlight开发历程—模糊特效与投影特效
  5. 实验——Windows常用网络测试命令
  6. fastadmin token 验证错误_用签名保护你的隐私(4)--token生成
  7. JVM学习-垃圾回收调优
  8. python实现屏幕录制_GitHub - Sijiu/record-camera-and-screen: 录制摄像头和录制屏幕,两者之间可以轻易切换...
  9. Spark Streaming源码解读之Driver中ReceiverTracker架构设计以具体实现彻底研究
  10. 毕业设计《项目管理》总结06之ajax的初步使用经验
  11. 用java编写台球小游戏项目
  12. ServerSocket与Socket入门详解
  13. 塔夫斯大学计算机教授,史上第一次生物创造,全球首个活体机器人诞生!
  14. T1076 正常血压(信息学一本通C++)
  15. 我在唯品会工作了四年_苦等两年,唯品会消金牌照终于批了,金融业务却“掉队”了...
  16. 数据结构之单向循环链表
  17. 层(Overlays)
  18. 如何使用激活工具Microsoft Toolkit
  19. 读书笔记:不可能的技艺,巅峰人生需要凶猛的起点
  20. 兄弟连NoSQL视频教程 redis笔记

热门文章

  1. 仿淘宝电商官网静态页面(HTML+CSS+JS)+ 常见布局解析,学会如果做是关键!
  2. ThinkPHP 框架建立 PostgreSQL / 腾讯云 TDSQL PgSQL (TBase) 连接
  3. Ubuntu Windows双系统切换技巧
  4. Java 8的新特性—终极版
  5. python回归算法_基于Python的函数回归算法验证
  6. tim工具包-sql管理平台-admin
  7. ElasticSearch 极简入门 CRUD
  8. 关于GBA模拟器悲惨的速度问题
  9. 典范杜希奇与机器人_典范英语7_16 杜希奇与机器人
  10. 入门练习:利用标准API 获取电影海报图片的 url