Unity导出Android工程 bat一键打包APK (导出Eclipce工程 )

    Unity虽然能直接打包Apk,很多时候我们需要在原生java环境中完成一些功能或者接入第3方库等等。这个时候我们就需要Unity导出java工程并合并,然后利用Eclipce打包APK。另外,Unity直接打包APK包体压缩率很低,同比Eclipce导出大了1倍多(本人测试unity 90M,Eclipce 35M),Unity生成APK利用反编译工具反编译,然后在编译一次就与Eclipce相同,可能Unity从运行效率考虑,默认没有压缩。

      言归正传,Android打包其实是对一系打包命令的执行。Unity导出Java工程,手动合并JAVA工程必然工作量提高,还容易出现错误,还需要利用Eclipce等JAVA工具打包,非常繁琐。所以通过Unity打包工具调用BAT一键打包APK非常必要。

环境:Unity5.6.3 JDK8 android-sdk-r24.4.1 (WIN7/Win10下测试可用)

一 导出Java工程

//打包场景
static string[] buildScences = new[] { "Assets/Shiyi/Scenes/Enter.unity",
                                    "Assets/Shiyi/Scenes/GameMain.unity" };
//导出工程临时目录 
static string tempProPath = "Android";
BuildPipeline.BuildPlayer(buildScences, tempProPath, BuildTarget.Android,     BuildOptions.AcceptExternalModificationsToPlayer);

BuildOptions.AcceptExternalModificationsToPlayer 设置后导出的就是Eclipce工程 tempProPath 生成的临时目录

二.合并工程

    /// <summary>
    /// 需要合并的目录
    /// </summary>
    static string[] copyPathList = new[] { "assets" ,
                                        "libs" ,
                                };
    string tempPath = tempProPath + "/" + PlayerSettings.productName ;
    EditorFunc.DeleteFolder(info.eclipsePath + "/" + copyPathList[0]);//清除掉Assets目录
    for (int i=0;i< copyPathList.Length;i++)  //替换打包目录Eclipse文件夹
        EditorFunc.CopyDirectory(tempPath + "/" + copyPathList[i], info.eclipsePath + "/" + copyPathList[i]);
//=======================================================================================
    /// <summary>
    /// 删除文件夹
    /// </summary>
    /// <param name="dir"></param>
    public static void DeleteFolder(string dir)
    {
        if (!Directory.Exists(dir))
            return;
        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, true);
            }
        }
    }
    /// <summary>
    /// 复制文件夹
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <param name="destinationPath"></param>
    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,true);
            else
            {
                Directory.CreateDirectory(destName);
                CopyDirectory(fsi.FullName, destName);
            }
        }
    }

info.eclipsePath 我们需要扩展,合并的工程,也是最终打包的工程

三.bat 调用SDK JDK打包

这一步比较麻烦,网上有人写,但是很多坑没提示不够详细。首先运行CMD,输入javac,appd,java,dx命令时候能正常运行,没有提示“不是命令和关键字”说明你配置对了,如果不能请检查环境变量。 (这是我的 配置成自己电脑目录):
 

Path E:\Android\android-sdk-r24.4.1\platform-tools;E:\Android\android-sdk-r24.4.1\tools;E:\Android\android-sdk-r24.4.1\build-tools\25.0.2;E:\Android\android-sdk-r24.4.1;%JAVA_HOME%\bin;E:\AndroidSDK\android-sdk-r24.4.1\tools;

JAVA_HOME E:\Java\jdk8

CLASSPATH .;%JAVA_HOME%\lib;E:\Work\TestPJ\Android\TestMajiang\libs\unity-classes.jar;E:\Work\TestPJ\Android\TestMajiang\libs\wechat-sdk-android-with-mta-1.1.7.jar;E:\Work\TestPJ\Android\TestMajiang\libs\android-support-v4.jar;E:\Work\TestPJ\Android\TestMajiang\libs\GCloudVoice.jar;

注意:CLASSPATH 中请配置好 第三方jar包,不然编译不通过,也可以Bat里面调用设置,不过不推荐,最好这里设置好。如果CMD可以运行,但调用BAT报错,这个时候重启电脑就好了
编写Bat文件工程目录

扫描二维码关注公众号,回复: 126309 查看本文章

1、生成R.java

aapt package -f -m -J gen -S res -I E:/AndroidSDK/android-sdk-r24.4.1/platforms/android-25/android.jar -M AndroidManifest.xml  

生成成功,在gen目录下有R.JAVA
文件参数说明:
-f -m -J gen :以覆盖的形式在gen目录下生成带包路径的R.java 
-S res:指定资源文件
-I E:\Android\SDK\android-sdk_r09-windows\platforms\android-7\android.jar:使用指定版本的android jar包
-M AndroidManifest.xml:指定程序的配置文件

2、编译*.java

md bin 
javac -encoding UTF-8 -target 1.6 -source 1.6 -bootclasspath E:/AndroidSDK/android-sdk-r24.4.1/platforms/android-25/android.jar -d bin gen/com/yiqiu/mj/jiangsu/*.java src\com\yiqiu\mj\jiangsu\wxapi\*.java src\com\yiqiu\mj\jiangsu\*.java 

生成成功,会在bin目录下生成一系列的class文件
md bin 创建bin目录
-encoding UTF-8 使用UTF8编码,不然代码中有中文的地方都会报错编码GBK错误
-target 1.6 生成特定 VM 版本的类文件 ( JavaCompiler版本,推荐设置1.6,)
-source <版本>  提供与指定版本的源兼容性
-bootclasspath <路径>        覆盖引导类文件的位置 android-25对应android 7.1.1 根据项目具体需要选择,部分功能没有,用老版可能编译不过
-d <目录> 指定存放生成的类文件的位置本的类文件(包含第三方的JAVA源文件)
3、生成classes.dex

 dx --dex --output=bin\classes.dex bin libs

--output=bin\classes.dex 生成classes.dex 文件目录
bin libs 需要编译的class文件以及jar包,工程引入的JAR包的目录都要包含进来(列:unity的底层函数库 unity-classes.jar)。不然打出的APK无法执行
我的libs 目录


4、assets、res打包

aapt package -f -A assets -S res -I E:/AndroidSDK/android-sdk-r24.4.1/platforms/android-25/android.jar -M AndroidManifest.xml -F bin/TestMajiang

-F bin/TestMajiang 生成成功后,bin目录下有资源文件
5、生成未签名的apk

java -cp E:\AndroidSDK\android-sdk-r24.4.1\tools\lib\sdklib.jar com.android.sdklib.build.ApkBuilderMain bin/majiang_unsigned.apk -v -u -z bin\TestMajiang -f bin/classes.dex -rf src -nf libs

将之前生成的资源文件、classes.dex和src下的文件一起生成APK
-cp E:\AndroidSDK\android-sdk-r24.4.1\tools\lib\sdklib.jar com.android.sdklib.build.ApkBuilderMain 调用打包APK命令,apkbuilder在新版sdk 中已经被移除;
-nf libs 打包so文件
注意:如果第三方jar包里含有图片资源,一定要加上-rj参数,不然jar包里资源文件解不出来,程序会因为无法引用资源而报错!
6、apk签名

arsigner  -digestalg SHA1 -sigalg MD5withRSA  -keystore keystore\test.keystore -storepass 12345 -keypass 12345 -signedjar bin/majiang.apk bin/majiang_unsigned.apk aliasName

-digestalg SHA1    摘要算法的名称
-sigalg MD5withRSA       签名算法的名称
-keystore keystore\test.keystore  keystore位置
-storepass 12345 用于密钥库完整性的口令
-keypass 12345 专用密钥的口令(如果不同)
-signedjar <签名后的包><签名前的包><Alias>
时间戳警告 加上-tsa https://timestamp.geotrust.com/tsa 需要VPN 不然连接不上生成失败。不加也可以正常运行。

7._build.bat调用1-6

call 1_genR.bat
call 2_compile.bat
call 3_dex.bat  
call 4_package.bat
call 5_unsigned.bat
call 6_signed.bat

四.Unity调用_build

   //PakageSettingInfo.Mgr.Instance.androidSDkPath + " " + apkName // SDK路径 apk名字
   string apkName = PakageSettingInfo.Mgr.Instance.exportApkPath + "/" + info.pakageName + ".apk";
   EditorFunc.ExecuteProgram(info.eclipsePath + "/_build.bat",info.eclipsePath, 
       PakageSettingInfo.Mgr.Instance.androidSDkPath + " " + apkName);

//---------------------------------------------------------------------------------------------

    /// <summary>
    /// 运行Cmd
    /// </summary>
    /// <param name="exeFilename"></param>
    /// <param name="workDir"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    public static bool ExecuteProgram(string exeFilename, string workDir, string args)
    {
        System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
        info.FileName = exeFilename;
        info.WorkingDirectory = workDir;
        info.CreateNoWindow = false;
        info.Arguments = args;
        info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;

        System.Diagnostics.Process task = null;
        bool rt = true;
        try
        {
            Debug.Log("ExecuteProgram:" + args);

            task = System.Diagnostics.Process.Start(info);
            if (task != null)
            {
                task.WaitForExit(100000);
            }
            else
            {
                return false;
            }
        }
        catch (Exception e)
        {
            Debug.LogError("ExecuteProgram:" + e.ToString());
            return false;
        }
        finally
        {
            if (task != null && task.HasExited)
            {
                rt = (task.ExitCode == 0);
            }
        }

        return rt;
    }

我们把sdk目录,以及生成apk名字作为参数传到bat文件中
修改bat,最终如下

call 1_genR.bat  %1
call 2_compile.bat  %1
call 3_dex.bat  
call 4_package.bat  %1
call 5_unsigned.bat  %1
call 6_signed.bat %1 %2
aapt package -f -m -J gen -S res -I %1/platforms/android-25/android.jar -M AndroidManifest.xml 
md bin  
javac -encoding UTF-8 -target 1.6 -source 1.6 -bootclasspath %1/platforms/android-25/android.jar -d bin gen/com/yiqiu/mj/jiangsu/*.java src\com\yiqiu\mj\jiangsu\wxapi\*.java src\com\yiqiu\mj\jiangsu\*.java 
dx --dex --output=bin\classes.dex bin libs 
aapt package -f -A assets -S res -I %1/platforms/android-25/android.jar -M AndroidManifest.xml -F bin/TestMajiang
java -cp %1\tools\lib\sdklib.jar com.android.sdklib.build.ApkBuilderMain bin/majiang_unsigned.apk -v -u -z bin\TestMajiang -f bin/classes.dex -rf src -nf libs
jarsigner  -digestalg SHA1 -sigalg MD5withRSA  -keystore keystore\jklhhh.keystore -storepass jkl0202hhh -keypass jkl0202hhh -signedjar %2 bin/majiang_unsigned.apk android

完工。

猜你喜欢

转载自my.oschina.net/u/3700246/blog/1552119