说一说unity3d 一键打包吧,比如在Android平台下各种不同分辨率和不同内存大小的机器,可能还有不同的渠道包,不同渠道可能用的SDK都不一样,这一切的一切都表明你的代码无法做到自适应的,除非批量打包提供各个平台的预定义标签#define 。

Unity默认提供了一些预定义标签如:

UNITY_EDITOR  : 编辑器模式下。

UNITY_STANDALONE:PC Mac Linux模型下。

UNITY_IPHONE:IOS模式下。

UNITY_ANDROID:ANDROID模式下。

官方提供的标签属于比较大的范围标签,比如我希望在UNITY_ANDROID下面在写一些自定义的标签、类似 QQ UC CMCC这样的渠道标签该如何呢?如下图所示,ProjectSetting打包界面每个平台都会有Scripting Define Symbols这个选项,可以在这里添加每个平台下对应的自定义标签(多个标签用“;”号隔开),这里我设置的是Android平台,如果IOS也需要打这样的渠道标签那么也要在IOS页面Scripting Define Symbols选项处添加对应的标签。

标签做出来了就好办了,然后在代码中我们可以这样来写。如果在Scripting Define Symbols中没有出现的标签默认是不启用的,就像 #define Test 一样,会自动被注释掉。

然后我们看看如何实现脚本批量打包。


  1. using UnityEditor;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5. using System.IO;
  6.  
  7. public class MyEditorScript  
  8. {
  9.    //得到工程中所有场景名称
  10.         static string[] SCENES = FindEnabledEditorScenes();
  11.         //一系列批量build的操作
  12.         [MenuItem ("Custom/Build Android QQ")]
  13.         static void PerformAndroidQQBuild ()
  14.         {   
  15.      BulidTarget("QQ","Android");
  16.         }
  17.  
  18. [MenuItem ("Custom/Build Android UC")]
  19.         static void PerformAndroidUCBuild ()
  20.         {   
  21.      BulidTarget("UC","Android");
  22.         }
  23.  
  24. [MenuItem ("Custom/Build Android CMCC")]
  25.         static void PerformAndroidCMCCBuild ()
  26.         {   
  27.      BulidTarget("CMCC","Android");
  28.         }
  29.  
  30. [MenuItem ("Custom/Build Android ALL")]
  31.         static void PerformAndroidALLBuild ()
  32.         {   
  33.  BulidTarget("QQ","Android");
  34.      BulidTarget("UC","Android");
  35.  BulidTarget("CMCC","Android");
  36.         }
  37.    [MenuItem ("Custom/Build iPhone QQ")]
  38.   static void PerformiPhoneQQBuild ()
  39.         {   
  40. BulidTarget("QQ","IOS");
  41.         }
  42.  
  43.    [MenuItem ("Custom/Build iPhone QQ")]
  44.   static void PerformiPhoneUCBuild ()
  45.         {   
  46. BulidTarget("UC","IOS");
  47.         } 
  48.  
  49.   [MenuItem ("Custom/Build iPhone CMCC")]
  50.   static void PerformiPhoneCMCCBuild ()
  51.         {   
  52. BulidTarget("CMCC","IOS");
  53.         } 
  54.  
  55. [MenuItem ("Custom/Build iPhone ALL")]
  56.         static void PerformiPhoneALLBuild ()
  57.         {   
  58.  BulidTarget("QQ","IOS");
  59.      BulidTarget("UC","IOS");
  60.  BulidTarget("CMCC","IOS");
  61.         }
  62.  
  63.    //这里封装了一个简单的通用方法。
  64. static void BulidTarget(string name,string target)
  65. {
  66.   string app_name = name;
  67.       string target_dir = Application.dataPath + "/TargetAndroid";
  68.   string target_name = app_name + ".apk";
  69.       BuildTargetGroup targetGroup = BuildTargetGroup.Android;
  70.   BuildTarget buildTarget = BuildTarget.Android;
  71.   string applicationPath = Application.dataPath.Replace("/Assets","");
  72.  
  73. if(target == "Android")
  74. {
  75. target_dir = applicationPath + "/TargetAndroid";
  76. target_name = app_name + ".apk";
  77.     targetGroup = BuildTargetGroup.Android;
  78. }
  79. if(target == "IOS")
  80. {
  81. target_dir = applicationPath + "/TargetIOS";
  82. target_name = app_name;
  83. targetGroup = BuildTargetGroup.iPhone;
  84. buildTarget = BuildTarget.iPhone;
  85. }
  86.  
  87.        //每次build删除之前的残留
  88. if(Directory.Exists(target_dir)) 
  89.          {
  90.  if (File.Exists(target_name))
  91.                     {
  92.                        File.Delete(target_name);
  93.                      }
  94.              }else
  95. {
  96. Directory.CreateDirectory(target_dir); 
  97. }
  98.  
  99.    //==================这里是比较重要的东西=======================
  100. switch(name)
  101. {
  102. case "QQ":
  103.    PlayerSettings.bundleIdentifier = "com.game.qq";
  104. PlayerSettings.bundleVersion = "v0.0.1";
  105.          PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup,"QQ");  
  106. break;
  107. case "UC":
  108.    PlayerSettings.bundleIdentifier = "com.game.uc";
  109. PlayerSettings.bundleVersion = "v0.0.1";
  110.          PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup,"UC");         
  111. break;
  112. case "CMCC":
  113.    PlayerSettings.bundleIdentifier = "com.game.cmcc";
  114. PlayerSettings.bundleVersion = "v0.0.1";
  115.          PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup,"CMCC");         
  116. break;
  117. }
  118.  
  119. //==================这里是比较重要的东西=======================
  120.  
  121. //开始Build场景,等待吧~
  122.                  GenericBuild(SCENES, target_dir + "/" + target_name, buildTarget,BuildOptions.None);
  123.  
  124. }
  125.  
  126. private static string[] FindEnabledEditorScenes() {
  127. List<string> EditorScenes = new List<string>();
  128. foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
  129. if (!scene.enabled) continue;
  130. EditorScenes.Add(scene.path);
  131. }
  132. return EditorScenes.ToArray();
  133. }
  134.  
  135.         static void GenericBuild(string[] scenes, string target_dir, BuildTarget build_target, BuildOptions build_options)
  136.         {   
  137.                 EditorUserBuildSettings.SwitchActiveBuildTarget(build_target);
  138.                 string res = BuildPipeline.BuildPlayer(scenes,target_dir,build_target,build_options);
  139.  
  140.                 if (res.Length > 0) {
  141.                         throw new Exception("BuildPlayer failure: " + res);
  142.                 }
  143.         }
  144.  
  145. }
这里面忘说了一点,如果我们希望在性能高的手机上用一套好的资源,在性能低的手机上用一套差一点的资源该怎么办?那么首先我们先搞清楚Unity会把什么资源打包,什么资源不打包?

1.Resources文件夹 

Resources文件夹是一个只读的文件夹,通过Resources.Load()来读取对象。因为这个文件夹下的所有资源都可以运行时来加载,所以Resources文件夹下的所有东西都会被无条件的打到发布包中。建议这个文件夹下只放Prefab或者一些Object对象,因为Prefab会自动过滤掉对象上不需要的资源。举个例子我把模型文件还有贴图文件都放在了Resources文件夹下,但是我有两张贴图是没有在模型上用的,那么此时这两张没用的贴图也会被打包到发布包中。假如这里我用Prefab,那么Prefab会自动过滤到这两张不被用的贴图,这样发布包就会小一些了。 

2.StreamingAssets

StreamingAssets文件夹也是一个只读的文件夹,但是它和Resources有点区别,Resources文件夹下的资源会进行一次压缩,而且也会加密,不使用点特殊办法是拿不到原始资源的。但是StreamingAssets文件夹就不一样了,它下面的所有资源不会被加密,然后是原封不动的打包到发布包中,这样很容易就拿到里面的文件。所以StreamingAssets适合放一些二进制文件,而Resources更适合放一些GameObject和Object文件。StreamingAssets 只能用过www类来读取!!

3. 最后凡是在Hierarchy视图对象引用过的资源文件也会被无条件打包到发布包中。如果有一部分文件可能没有在Resources文件夹下也没有在StreamingAssets文件夹下,也没有被Hierarchy视图游戏对象引用,那么这类资源是不会被打包到发布包中的。

OK!搞清楚这一点就好办了!在处理不同包对应不同资源包的时候,尽量让可配置的资源放在Resources 或StreamingAssets文件夹下,运行的时候程序动态的来读取它们,最后显示在游戏中就可以了。在批量打包前,在Project视图下创建不同包的资源文件夹, 然后脚本 AssetDatabase 动态的将资源拷贝至Resources或StreamingAssets 文件夹中,

  1.         [MenuItem ("Custom/Build Android QQ")]
  2.         static void PerformAndroidQQBuild ()
  3.         {   
  4.                          //先把资源拷贝到Resources或者StreamingAssets
  5. AssetDatabase.CopyAsset("path","newPath");
  6.                          //然后开始编译版本 
  7.     BulidTarget("QQ","Android");
  8.         }