Unity自動(dòng)打包Android其實(shí)要比IOS容易得多,因?yàn)锳ndroid不用先生成java工程,然后在構(gòu)建.apk包,我先說(shuō)說(shuō)Android打包的步驟。
1.把sdk拷貝至Plugins/Android下。
如下圖所示,如果你做過(guò)Android源生開(kāi)發(fā),我相信下面的東西你不會(huì)陌生??墒侨绻銢](méi)做過(guò)Android原生開(kāi)發(fā),我還是詳細(xì)說(shuō)明以下。
AndroidManifest:這是Android程序必不可少的文件,這里記錄著應(yīng)用程序的啟動(dòng)Activity。Activity就是Android的一個(gè)界面,一般應(yīng)用程序會(huì)有很多Acitivty,來(lái)回切換界面。但是游戲就不太一樣了,因?yàn)橛螒蛑恍枰粋€(gè)Activity 一個(gè)View就可以了。(扯遠(yuǎn)了)
AndroidManifest:里面還記錄著應(yīng)用程序的權(quán)限,Service啊什么的,,有興趣的同學(xué)可以谷歌搜一搜。
每次打包的時(shí)候Unity會(huì)用它默認(rèn)的AndroidManifest,它默認(rèn)的AndroidManifest在 unity.app/Contents/PlaybackEngines/AndroidPlayer下面。當(dāng)你在進(jìn)行打包apk的時(shí)候 unity會(huì)拷貝該路徑下的所有參數(shù)。
在ProjectSetting里面勾選一些權(quán)限的時(shí)候,Unity會(huì)自動(dòng)幫你修改AndroidManifest里面的權(quán)限,但是如果某個(gè)權(quán)限不能在Unity工程里面修改,那么就需要自己手動(dòng)替換。如下圖所示,我們把AndroidManifest放在Plugins/Android下面, 這樣Unity在進(jìn)行打包的時(shí)候就不會(huì)用它默認(rèn)的,而是用我自己新寫(xiě)的打包。。這樣就方便靈活很多了。。
bin:下面就記錄著sdk用到的第三方j(luò)ar
res:下面就是安卓的一些圖片,資源啊什么。
你可以隨便解開(kāi)一個(gè)android的APK看看它的目錄結(jié)構(gòu)就明白了。。

這樣在打包的時(shí)候unity就會(huì)自動(dòng)把Plugins/Android下面的所有資源打包在你的APK里面了。但是如果你做渠道包的時(shí)候,每個(gè)包用的是不同的sdk,所以你需要在打包不同渠道的時(shí)候把相關(guān)的文件拷貝在Plugins/Android下面。
如下圖所示,我在根目錄下創(chuàng)建一個(gè)文件夾名子叫91,當(dāng)我自動(dòng)化打包的時(shí)候自動(dòng)把91文件夾下面的資源先拷貝在Plugins/Android下面,然后在自動(dòng)打包。。打完包以后再把Plugins/Andoird文件夾清空即可。。

Ok上腳本。。代碼和上一篇文章的第一步差不多,我就不多余注釋?zhuān)?,?zhí)行下面shell腳本將自動(dòng)打開(kāi)unity,然后執(zhí)行ProjectBuild.BuidForAndroid方法。。?project-$1 就是傳入的參數(shù)。。
#!/bin/sh
#參數(shù)判斷??
if [ $# != 1 ];then??
????echo "需要一個(gè)參數(shù)。 參數(shù)是游戲包的名子"??
????exit????
fi??
#UNITY程序的路徑#
UNITY_PATH=/Applications/Unity/Unity.app/Contents/MacOS/Unity
#游戲程序路徑#
PROJECT_PATH=/Users/MOMO/commond
#在Unity中構(gòu)建apk#
$UNITY_PATH -projectPath $PROJECT_PATH -executeMethod ProjectBuild.BuildForAndroid project-$1 -quit
echo "Apk生成完畢"
在關(guān)閉unity的情況下運(yùn)行。在命令行里面執(zhí)行這一條腳本, 參數(shù)一個(gè)參數(shù) 91。

using System.Collections;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System;
class ProjectBuild : Editor{
//在這里找出你當(dāng)前工程所有的場(chǎng)景文件,假設(shè)你只想把部分的scene文件打包 那么這里可以寫(xiě)你的條件判斷 總之返回一個(gè)字符串?dāng)?shù)組。
static string[] GetBuildScenes()
{
List<string> names = new List<string>();
foreach(EditorBuildSettingsScene e in EditorBuildSettings.scenes)
{
if(e==null)
continue;
if(e.enabled)
names.Add(e.path);
}
return names.ToArray();
}
static void BuildForAndroid()
{
Function.DeleteFolder(Application.dataPath+"/Plugins/Android");
if(Function.projectName == "91")
{
Function.CopyDirectory(Application.dataPath+"/91",Application.dataPath+"/Plugins/Android");
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, "USE_SHARE");
}
string path = Application.dataPath +"/" + Function.projectName+".apk";
BuildPipeline.BuildPlayer(GetBuildScenes(), path, BuildTarget.Android, BuildOptions.None);
}
}
程序會(huì)執(zhí)行BuildForAndroid的方法,這里我把shell傳入的參數(shù)取出來(lái)。根據(jù)傳入的不同參數(shù)來(lái)初始化打包的一些設(shè)置。。
最終BuildPlayr就開(kāi)始構(gòu)建apk,第二個(gè)參數(shù)就是打包出apk保存的路徑。 在打包之前你可以處理一些 游戲包名, 游戲icon 等等一些平臺(tái)之間的特殊性 ,也可以設(shè)置一些 預(yù)定義標(biāo)簽,。
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.XCodeEditor;
using System.Xml;
#endif
using System.IO;
public static class XCodePostProcess
{
????#if UNITY_EDITOR
????[PostProcessBuild (100)]
????public static void OnPostProcessBuild (BuildTarget target, string pathToBuiltProject)
????{
if (target == BuildTarget.Android)
{
Function.DeleteFolder(Application.dataPath+"/Plugins/Android");
if(Function.projectName== "91")
???? {
???????????? //當(dāng)我們?cè)诖?1包的時(shí)候 這里面做一些 操作。
}
}
????}
????#endif
}
?在回到XUPortr里面,當(dāng)Android打包完畢后,這里我們清空Plugins/Android文件夾。?;蛘吣阋部梢宰鲆恍┎僮?。。
Function.cs 用到的一個(gè)工具類(lèi)
using UnityEngine;
using System.Collections;
using System.IO;
public class Function??{
//得到項(xiàng)目的名稱(chēng)
public static string projectName
{
get
{
//在這里分析shell傳入的參數(shù), 還記得上面我們說(shuō)的哪個(gè) project-$1 這個(gè)參數(shù)嗎?
//這里遍歷所有參數(shù),找到 project開(kāi)頭的參數(shù), 然后把-符號(hào) 后面的字符串返回,
//這個(gè)字符串就是 91 了。。
foreach(string arg in System.Environment.GetCommandLineArgs()) {
if(arg.StartsWith("project"))
{
return arg.Split("-"[0])[1];
}
}
return "test";
}
}
public static void DeleteFolder(string dir)
{
foreach (string d in Directory.GetFileSystemEntries(dir))
{
if (File.Exists(d))
{
FileInfo fi = new FileInfo(d);
if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1)
fi.Attributes = FileAttributes.Normal;
File.Delete(d);
}
else
{
DirectoryInfo d1 = new DirectoryInfo(d);
if (d1.GetFiles().Length != 0)
{
DeleteFolder(d1.FullName);////遞歸刪除子文件夾
}
Directory.Delete(d);
}
}
}
public static void CopyDirectory(string sourcePath, string destinationPath)
{
DirectoryInfo info = new DirectoryInfo(sourcePath);
Directory.CreateDirectory(destinationPath);
foreach (FileSystemInfo fsi in info.GetFileSystemInfos())
{
string destName = Path.Combine(destinationPath, fsi.Name);
if (fsi is System.IO.FileInfo)??????
File.Copy(fsi.FullName, destName);
else????????????????????
{
Directory.CreateDirectory(destName);
CopyDirectory(fsi.FullName, destName);
}
}
}
}
如下圖所示,腳本運(yùn)行完畢,你打包的APK就靜靜的放在了這里,怎么樣?簡(jiǎn)單吧?嘿嘿。。

注意事項(xiàng):
1、因?yàn)槟愕墓こ炭赡鼙容^大,如果IOS和Android同時(shí)打包的話(huà)切個(gè)平臺(tái)都要半個(gè)多小時(shí),我建議的svn在本地check out 兩個(gè)工程,一個(gè)切在ios 一個(gè)切在A(yíng)ndroid ?打包的時(shí)候分開(kāi)打。
2.執(zhí)行shell腳本的時(shí)候請(qǐng)關(guān)閉保存unity工程。
3.Android 因?yàn)椴皇茏C書(shū)的限制,我上傳的工程建議你下載下來(lái)看看,肯定可以直接打出來(lái)包。。
4.我建議打包的機(jī)器使用mac。 因?yàn)閣indows不能打包IOS 而MAC可以同時(shí) 打包 IOS 和 Android