【狂云歌之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的管理比较实用。

VR开发或者unity相关交流可以邮件madcloudsong@qq .com
转载请注明原文链接
http://blog.csdn.net/madcloud...

【狂云歌之unity_vr】unity项目持续集成cibuilddailybuild相关推荐

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

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

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

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

  3. Jenkins——Jenkins介绍+基于云平台的Jenkins安装和持续集成环境配置(插件+用户权限+凭据+Maven打包)

    Jenkins--Jenkins介绍+基于云平台的Jenkins安装和持续集成环境配置(插件+用户权限+凭据+Maven打包) 持续集成及Jenkins介绍 软件开发生命周期 什么是持续集成? 持续集 ...

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. heroku_了解如何使用Heroku部署全栈Web应用程序
  2. 如何利用 C# 实现 K-D Tree 结构?
  3. 【SpringBoot】关闭HttpClient无用日志
  4. 高速公路 (Highway,CERC 2006,LA 3720)
  5. MySQL安装失败问题
  6. python实验原理_Python实验报告八
  7. HTML+CSS+JS实现 ❤️创意时间轮盘时钟特效❤️
  8. linux嵌入式gdb调试指南,建立嵌入式gdb调试环境
  9. 对联广告(jQuery)
  10. 【NOIP2002】【codevs1010】过河卒
  11. 关于SVM参数cg选取的总结帖[matlab-libsvm]
  12. FileUtils工具类的使用
  13. 苹果iPhone 6Plus 拆机过程,拆机图完全拆机流程及注意事项
  14. python 热度图_python可视化(七)绘制詹姆斯、杜兰特、伦纳德生涯数据热度图...
  15. 一位ML工程师构建深度神经网络的实用技巧
  16. Android设置标题栏透明
  17. Android学习之登陆界面设计(一)前后期准备以及相关配置
  18. linux 软件安装笔记
  19. 浏览器窗口切换(从一个页面切换到另一个页面并且不刷新)
  20. 当LCC画龙时,新老车企分别在想什么?

热门文章

  1. Outlook或Foxmail发送邮件退信问题
  2. 一款神仙接私活低代码平台,牛到不行!
  3. 上班族干什么副业赚钱?不知道做什么,就来看看这5个!
  4. Scala解码base64编码的URL提示Last unit does not have enough valid bits
  5. 别不信,读书虽然不是唯一的出路,但读书一定是最好的出路
  6. 编写高质量代码改善C++程序的150个建议
  7. 短时主频点特征对声音表达能力探究1
  8. 财政收入的各种统计口径
  9. 顺序结构(基本结构)
  10. 1.2 计算机的分类和应用