Unity腳本生成ipa或apk的方法

2016更新:本文寫于2014。其中值得注意的是,建議默認(rèn)使用python編寫腳本,對(duì)跨平臺(tái)有好處。而并非下文即將提及的、還不那么好地,使用bat、shell來編寫。

基礎(chǔ)概念

如果不關(guān)心概念只關(guān)心使用方法,可略過這里,直接去到“準(zhǔn)備環(huán)境”、“腳本構(gòu)建使用方法”。

能夠使用Unity進(jìn)行腳本生成ipa或apk(以下統(tǒng)稱app)的核心前提是:

  • Unity運(yùn)行時(shí)既包括了editor、也包括了compiler;
  • Unity運(yùn)行時(shí)既能以界面形式運(yùn)行、也能以命令行方式運(yùn)行??蓞⒁?a target="_blank" rel="nofollow">Unity命令行官方文檔;
  • Unity以命令行方式運(yùn)行時(shí),能夠通過形如-executeMethod MyScript.MyMethod參數(shù),調(diào)用Editor腳本工程里面的某一個(gè)靜態(tài)方法,該靜態(tài)方法可以引用UnityEngine庫(kù)、UnityEditor庫(kù)里的任意函數(shù),包括關(guān)鍵的BuildPipeline.BuildPlayer函數(shù)。可參考BuildPlayer的官方文檔;
  • 也就是說,理論上任何在Unity編輯器里能實(shí)現(xiàn)的操作,都能通過命令行實(shí)現(xiàn)。(親可以試一下使用命令行做一個(gè)Unity游戲出來:p)

所以,使用Unity進(jìn)行腳本生成app的核心步驟是:

  1. 準(zhǔn)備SDK環(huán)境。如果是生成apk,則機(jī)器(Mac或PC)先準(zhǔn)備好Android SDK;如果是生成ipa,則Mac先安裝好XCode
  2. 調(diào)用腳本,生成中間工程文件。腳本實(shí)際是運(yùn)行Unity命令行,調(diào)用用戶函數(shù)比如CommandBuild.Build函數(shù),輸入各類參數(shù)(比如-ios/-android的平臺(tái)參數(shù)、比如-debug/-release的版本參數(shù))
  3. 調(diào)用腳本,使用SDK將中間工程文件生成app。如果是生成apk,因?yàn)锳ndroid的開放性,Unity能夠?qū)⑦@一步合到第2步中,所以生成apk也就不需要我們?nèi)ジ愕?步了;但如果是生成ipa,因?yàn)樘O果限制必須使用XCode生成ipa,所以我們需要再用腳本調(diào)用XCode,將工程文件生成ipa。

準(zhǔn)備環(huán)境

準(zhǔn)備生成apk的環(huán)境

  1. 機(jī)器可以是PC或Mac。但這里只討論P(yáng)C。

  2. 下載java,并且添加java的安裝路徑到本機(jī)環(huán)境變量,方法可參考這里。

  3. Android官網(wǎng)下載最新的Eclipse ADT

    注:可能出現(xiàn)點(diǎn)擊下載按鈕沒反應(yīng)的情況,可以更換瀏覽器再試試。
    注:ADT包括了EclipseIDE和SDK本身。事實(shí)上我們的確只需要SDK就好了,但試過下載SDK是不行的,因?yàn)槿鄙倭死锩娴膒latforms。所以用下載工具下載ADT是個(gè)省時(shí)的選擇。

  4. 解壓下載好的壓縮包,放到合適的地方。

  5. 打開Unity,Edit>Preferences>External Tools>Android SDK Location,然后選擇你剛才解壓文件夾中的sdk文件夾。

  6. 完畢?,F(xiàn)在可以使用Unity構(gòu)建了。

    注:如果構(gòu)建中途,出現(xiàn)失敗形如Error building Player: Win32Exception: ...zipalign.exe...CommandLine='4"的錯(cuò)誤,可以把zipalignexe從sdk\build-tools\(你的版本)文件夾拷到sdk\tool文件夾。

準(zhǔn)備生成ipa的環(huán)境

  1. 機(jī)器必須是Mac
  2. 到App Store下載并安裝最新的XCode
  3. 準(zhǔn)備好開發(fā)者帳號(hào)、開發(fā)者p12文件。(過程略)

腳本使用方法

生成apk

  1. 修改Environment.bat
    • 修改“unity”變量,指定里面的unity路徑。
    • 修改“debugParam”變量,指定是-debug或者-release
  2. 執(zhí)行UnityToApk.bat,等待執(zhí)行完畢
  3. apk生成在KillerProject\Bin\Android文件夾下

生成ipa

  1. 修改UnityToXCode.sh里的“debugParam”變量,指定是-debug或者-release。
  2. 執(zhí)行UnityToIPA.sh生成ipa文件。也可以執(zhí)行SvnUnityToIPA.sh即先更新SVN再生成ipa。

附腳本

apk相關(guān)腳本

Environment.bat

:: set your own Unity path
set unity="D:\Program Files (x86)\Unity\Editor\Unity.exe"
:: -debug or -release
set debugParam=-debug

set projectPath=%~dp0

UnityToApk.bat

rmdir /q Bin\Android
mkdir Bin\Android

call Environment.bat

echo "Start Build Unity to Apk"

%unity% -batchmode -projectPath %projectPath% -executeMethod CommandBuild.PreBuild %debugParam% -quit -logFile ./PreBuild.log
%unity% -batchmode -projectPath %projectPath% -executeMethod CommandBuild.Build %debugParam% -android -quit -logFile ./BuildApk.log


echo "End Build,please see log PreBuild.log and BuildApk.log"

ipa相關(guān)腳本

UnityToXCode.sh

#!/bin/bash

echo "Remove XCodeProject"

rm -rf XCodeProject

path=`pwd`
#-debug or -release
debugParam="-debug"

echo "Start Build Unity to XCodeProject"

/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -projectPath $path -executeMethod CommandBuild.PreBuild $debugParam -quit -logFile ./PreBuild.log
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -projectPath $path -executeMethod CommandBuild.Build $debugParam -ios -quit -logFile ./BuildXCodeProject.log

echo "End Build,please see log PreBuild.log and BuildXCodeProject.log"

XCodeToIPA.sh

#/bin/sh

usage()
{
    echo "usage: $0 AppName XCodeProject"
    echo "example: $0 Killer XCodeProject"
}

if [ $# -ne 2 ] ;then
    usage
    exit 1
fi

path=`pwd`
app_name=$1
xcodeproj_dir=$path/$2

#echo $app_name
#echo $xcodeproj_dir
#echo $path

if [ -d $xcodeproj_dir ] ;then
    echo "$xcode_dir exist"
else
    echo "dir $xcodeproj_dir doesn't exist"
    exit 1
fi

cd $xcodeproj_dir
xcodebuild -sdk iphoneos7.1

echo "end xcodebuild"

cd ./build
mkdir -p ipa/Payload
cp -r ./${app_name}.app ./ipa/Payload
cd ipa

echo "zip $app_name"
zip -r $app_name *

app_file=$path/${app_name}_$(date +%m%d_%H%M).ipa
mv ${app_name}.zip $app_file

echo "Build Successed ipa."
echo "$app_file"

通用Editor腳本代碼

CommandBuild.cs

using UnityEngine;
using UnityEditor;

public class CommandBuild
{
    private static string[] ms_scenes =
    {
        "Assets/Scenes/KillerStarter.unity"
    };

    private static bool ms_isDebugBuild = false;
    private static BuildTarget ms_buildTarget = BuildTarget.Android;

    private static string XCODE_PROJECT_NAME = "XCodeProject";
    private static string BUILD_OUTPUT_ANDROID = "Bin/Android/";

    private static void UpdateBuildFlag()
    {
        string[] args = System.Environment.GetCommandLineArgs();
        foreach(string oneArg in args)
        {
            if (oneArg != null && oneArg.Length > 0)
            {
                if (oneArg.ToLower().Contains("-debug"))
                {
                    Debug.Log("\"-debug\" is detected, switch to debug build.");
                    ms_isDebugBuild = true;
                    return;
                }
                else if (oneArg.ToLower().Contains("-release"))
                {
                    Debug.Log("\"-release\" is detected, switch to release build.");
                    ms_isDebugBuild = false;
                    return;
                }
            }
        }

        if (ms_isDebugBuild)
        {
            Debug.Log("neither \"-debug\" nor \"-release\" is detected, current is to debug build.");
        }
        else
        {
            Debug.Log("neither \"-debug\" nor \"-release\" is detected, current is to release build.");
        }
    }
    private static void UpdateBuildTarget()
    {
        string[] args = System.Environment.GetCommandLineArgs();
        foreach (string oneArg in args)
        {
            if (oneArg != null && oneArg.Length > 0)
            {
                if (oneArg.ToLower().Contains("-android"))
                {
                    Debug.Log("\"-android\" is detected, switch build target to android.");
                    ms_buildTarget = BuildTarget.Android;
                    return;
                }
                else if (oneArg.ToLower().Contains("-iphone"))
                {
                    Debug.Log("\"-iphone\" is detected, switch build target to iphone.");
                    ms_buildTarget = BuildTarget.iPhone;
                    return;
                }
                else if (oneArg.ToLower().Contains("-ios"))
                {
                    Debug.Log("\"-ios\" is detected, switch build target to iphone.");
                    ms_buildTarget = BuildTarget.iPhone;
                    return;
                }
            }
        }

        Debug.Log("neither \"-android\", \"-ios\" nor \"-iphone\" is detected, current build target is: " + ms_buildTarget);
    }
    public static void PreBuild()
    {
        Debug.Log("PreBuild");
        UpdateBuildFlag();
        SetKgfDebugActive(ms_isDebugBuild);
    }
    public static void Build()
    {
        Debug.Log("Build");
        UpdateBuildTarget();

        BuildOptions buildOption = BuildOptions.None;
        if (ms_isDebugBuild)
        {
            buildOption |= BuildOptions.Development;
            buildOption |= BuildOptions.AllowDebugging;
            buildOption |= BuildOptions.ConnectWithProfiler;
        }
        else
        {
            buildOption |= BuildOptions.None;
        }

        string locationPathName;
        if(BuildTarget.iPhone == ms_buildTarget)
        {
            locationPathName = XCODE_PROJECT_NAME;
        }
        else
        {
            locationPathName = BUILD_OUTPUT_ANDROID;
            System.DateTime time = System.DateTime.Now;
            locationPathName += "killer_" + time.Month.ToString("D2") + time.Day.ToString("D2") +
                "_" + time.Hour.ToString("D2") + time.Minute.ToString("D2") + ".apk";
        }
        BuildPipeline.BuildPlayer(ms_scenes, locationPathName, ms_buildTarget, buildOption);
    }
    public static void PostBuild()
    {
        Debug.Log("PostBuild");
    }

    private static void SetKgfDebugActive(bool activated)
    {
        ///非重點(diǎn),略
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容