Unity 多渠道打包 APK

Unity 多渠道打包 APK

一个工程打包给 N 个渠道,每个渠道有自己的 应用名、应用Icon、包名、keystore、各种需要接入的SDK,甚至每个渠道有单独的资源等等

为了方便、省事、省时,决定通过脚本执行打包,下面是自己的一个思路实践,比较简单,只包含了一个 SDK,没有根据渠道来区分SDK(需后续添加),也没有为每个渠道设置单独的资源(需后续添加)。

思路:将渠道不同需求规整到一个统一的配置表,打包时读取配置表,在代码中动态设置相应的值,最终执行打包。

抽象出来的配置表如下
这里写图片描述

目前只配置了这么几个
将 Excel 导出到 xml
这里写图片描述

定义一个 配置表对应的 C# 类 BuildConfig.cs

public class BuildConfig {
    /// <summary>
    ///编号
    /// <summary>
    public int id { get; private set; }
    /// <summary>
    ///公司名
    /// <summary>
    public string companyName { get; private set; }
    /// <summary>
    ///应用名
    /// <summary>
    public string productName { get; private set; }
    /// <summary>
    ///包名
    /// <summary>
    public string bundleIdentifier { get; private set; }
    /// <summary>
    ///应用图标
    /// <summary>
    public string defaultIcon { get; private set; }
    /// <summary>
    ///版本号
    /// <summary>
    public string bundleVersion { get; private set; }
    /// <summary>
    ///版本号
    /// <summary>
    public int bundleVersionCode { get; private set; }
    /// <summary>
    ///keystore文件路径
    /// <summary>
    public string keystorePath { get; private set; }
    /// <summary>
    ///keystore密码
    /// <summary>
    public string keystorePass { get; private set; }
    /// <summary>
    ///别名
    /// <summary>
    public string keyaliasName { get; private set; }
    /// <summary>
    ///别名密码
    /// <summary>
    public string keyaliasPass { get; private set; }
    /// <summary>
    ///脚本宏定义
    /// <summary>
    public string scriptingDefine { get; private set; }
    /// <summary>
    ///APK名
    /// <summary>
    public string apkName { get; private set; }

}

将 channel.xml 导入到Unity 工程,
自己写一个解析 xml 的方法,

每一行的值对应赋值给 一个 BuildConfig 对象 new BuildConfig,将每个渠道配置传入打包方法,依次打包所有渠道 APK 包

代码如下,注释比较详细不细说了

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;

public class BuildAPK : Editor {

    [MenuItem("Tool/BuildApk")]
    static void Build()
    {
        TextAsset textAsset = LoadXML.Instance.LoadTextAsset("Assets/Channel/channel.xml");

        // 读取 channel.xml 将每一行的数据赋值给 一个 BuildConfig 对象,添加到字典中
        // 最终将 BuildConfig 对象字典返回
        Dictionary<object, BuildConfig> buildConfigDic = LoadXML.Instance.GetTableData<BuildConfig>("channel", textAsset.text);

        // 遍历字典
        foreach(KeyValuePair<object, BuildConfig> kv in buildConfigDic)
        {
            // 获取每个渠道的配置
            BuildConfig _buildConfig = kv.Value;

            // 执行打包
            Build(_buildConfig);
        }
    }

    private static void Build(BuildConfig buildConfig)
    {
        // 公司名
        PlayerSettings.companyName = buildConfig.companyName;
        // 产品名
        PlayerSettings.productName = buildConfig.productName;
        // 包名
        PlayerSettings.bundleIdentifier = buildConfig.bundleIdentifier;

        // 
        PlayerSettings.bundleVersion = buildConfig.bundleVersion;
        PlayerSettings.Android.bundleVersionCode = buildConfig.bundleVersionCode;

        // keystore 路径, G:\keystore\one.keystore
        PlayerSettings.Android.keystoreName = buildConfig.keystorePath;
        // one.keystore 密码
        PlayerSettings.Android.keystorePass = buildConfig.keystorePass;

        // one.keystore 别名
        PlayerSettings.Android.keyaliasName = buildConfig.keyaliasName;
        // 别名密码
        PlayerSettings.Android.keyaliasPass = buildConfig.keyaliasPass;

        // Load 应用图标,暂时放 Resource 下了
        Texture2D icon = Resources.Load(buildConfig.defaultIcon) as Texture2D;
        // 设置应用图标
        PlayerSettings.SetIconsForTargetGroup(BuildTargetGroup.Android, new Texture2D[] { icon, icon, icon, icon, icon, icon });

        BuildTargetGroup buildTargetGroup = BuildTargetGroup.Android;
        // 设置宏定义
        PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, buildConfig.scriptingDefine); // 宏定义

        List<string> levels = new List<string>();
        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
        {
            if (!scene.enabled) continue;
            // 获取有效的 Scene
            levels.Add(scene.path);
        }

        BuildTarget buildTarget = BuildTarget.Android;
        // 切换到 Android 平台
        EditorUserBuildSettings.SwitchActiveBuildTarget(buildTarget);

        // 打包出 APK 名
        string apkName = string.Format("{0}.apk", buildConfig.apkName);
        // 执行打包
        string res = BuildPipeline.BuildPlayer(levels.ToArray(), apkName, buildTarget, BuildOptions.None);

        if (res.Length > 0)
        {
            throw new Exception("BuildPlayer failure: " + res);
        }

        AssetDatabase.Refresh();
    }

}

所有渠道 APK 使用同样的 SDK (实际项目中会有不同)
这里写图片描述

Resources\Icon 下放了几个图标
这里写图片描述

在菜单栏创建了一个 BuildApk 按钮,执行打包
这里写图片描述

打包完成在项目根目录生成了所有渠道的 APK
这里写图片描述

APK 的图标和 apk名都和配置表中对应上了,

将所有APK 同时安装到模拟器上运行测试
1.安装所有APK
这里写图片描述
6 个 APK 都可以成功安装到模拟器上

2.分别测试
这里写图片描述

这里写图片描述

这里写图片描述

不一一贴出来了。经过测试都可以成功执行

测试打包过程中遇到的一些坑

1.
图标或者应用名不是设置的,检查 AndroidManifest.xml 中 application 标签中是否添加了
应用名 android:lable
应用图标 android:icon

android:label="@string/app_name"    
android:icon="@drawable/app_icon"

这里写图片描述

PlayerSettings.SetIconsForTargetGroup 方法设置的图标,打包 APK 时,会将设置的图片自动放到 APK 中 res\drawable-mdpi-v4\app_icon.png 、 res\drawable-xhdpi-v4\app_icon.png 等文件夹中,图片名字被设置成了 app_icon.png(固定设置)

应用名 app_name 到 res\values\strings.xml 中查找
app_name 的值对应为 PlayerSettings.productName 设置的值

这里写图片描述

2.
测试中发现 点击 Speak 按钮没有调用到 SDK,speak 调用的是接入的 讯飞-语音合成SDK。点击其他几个按钮,可以正常调用(其他几个为自己写的 加、减,字符串操作,不是第三方的SDK)
查找原因发现调用方法 PlayerSettings.SetIconsForTargetGroup 会将 PlayseSetting 中Icon 项中设置为 Override for Android,这里是正确的
这里写图片描述

由于 接入 讯飞 SDK 的时候没有处理好 res 下的资源,导致Unity 打包 APK时资源编译出了问题,通过清空 SDK Android 项目中 res 文件夹下没用的资源和 配置,重新导出 aar 放入Unity 中打包 APK 测试成功了

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值