You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity游戏APK打包前手动添加指定文件夹至数据目录方法

问题解答

直接通过Android Studio将文件夹打包进APK后自动部署到Android/Data/com.application.name/needed_folder/目录是做不到的——APK内的文件默认存放在应用内部的assets/res目录,不会自动复制到外部的公共数据目录。以下是两种可行的解决方案:

方案1:Unity端处理(推荐,无需跳转Android Studio)

  1. 把需要的文件夹放到Unity的StreamingAssets目录下,这个目录的内容会以原始文件形式打包进APK的assets目录。
  2. 编写C#脚本,在游戏第一次启动时将StreamingAssets内的目标文件夹复制到指定外部目录:
using System.IO;
using UnityEngine;

public class FileCopier : MonoBehaviour
{
    void Start()
    {
        // 目标目录:Android/Data/包名/needed_folder
        string targetDir = Path.Combine(Application.persistentDataPath, "needed_folder");
        string sourceDir = Path.Combine(Application.streamingAssetsPath, "needed_folder");

        if (!Directory.Exists(targetDir))
        {
            Directory.CreateDirectory(targetDir);
            if (Application.platform == RuntimePlatform.Android)
            {
                CopyAndroidAssets(sourceDir, targetDir);
            }
            else
            {
                CopyLocalDir(sourceDir, targetDir, true);
            }
        }
    }

    // 本地平台(PC/Editor)的目录复制逻辑
    void CopyLocalDir(string source, string dest, bool copySubDirs)
    {
        var sourceDir = new DirectoryInfo(source);
        if (!sourceDir.Exists) return;

        var destDir = new DirectoryInfo(dest);
        if (!destDir.Exists) destDir.Create();

        foreach (var file in sourceDir.GetFiles())
        {
            file.CopyTo(Path.Combine(dest, file.Name), false);
        }

        if (copySubDirs)
        {
            foreach (var subDir in sourceDir.GetDirectories())
            {
                CopyLocalDir(subDir.FullName, Path.Combine(dest, subDir.Name), true);
            }
        }
    }

    // Android平台下StreamingAssets的复制逻辑(需读取Jar内资源)
    void CopyAndroidAssets(string source, string dest)
    {
        try
        {
            var fileNames = AndroidJNIHelper.CallStatic<string[]>(
                new AndroidJavaClass("com.unity3d.player.UnityPlayer"),
                "getStreamingAssetFiles",
                source.Replace("jar:file://" + Application.dataPath + "!/assets/", "")
            );

            foreach (var fileName in fileNames)
            {
                var sourcePath = Path.Combine(source, fileName);
                var destPath = Path.Combine(dest, fileName);
                Directory.CreateDirectory(Path.GetDirectoryName(destPath));

                using (var request = UnityWebRequest.Get(sourcePath))
                {
                    request.SendWebRequest();
                    while (!request.isDone) { }
                    if (request.result == UnityWebRequest.Result.Success)
                    {
                        File.WriteAllBytes(destPath, request.downloadHandler.data);
                    }
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError($"文件复制失败:{e.Message}");
        }
    }
}

方案2:修改Unity导出的Android Studio工程

  1. 将目标文件夹放到Android Studio工程的src/main/assets目录下。
  2. 在原生MainActivity中添加启动时的文件复制逻辑(以Kotlin为例):
import android.os.Bundle
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import com.unity3d.player.UnityPlayerActivity

class MainActivity : UnityPlayerActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        copyAssetsFolder("needed_folder", "${externalFilesDir(null)?.absolutePath}/needed_folder")
    }

    private fun copyAssetsFolder(source: String, dest: String) {
        val destDir = File(dest)
        if (!destDir.exists()) destDir.mkdirs()

        assets.list(source)?.forEach { fileName ->
            val sourcePath = "$source/$fileName"
            val destPath = "$dest/$fileName"

            if (assets.list(sourcePath)?.isNotEmpty() == true) {
                copyAssetsFolder(sourcePath, destPath)
            } else {
                copySingleAsset(sourcePath, destPath)
            }
        }
    }

    private fun copySingleAsset(source: String, dest: String) {
        var input: InputStream? = null
        var output: FileOutputStream? = null
        try {
            input = assets.open(source)
            output = FileOutputStream(dest)
            val buffer = ByteArray(1024)
            var length: Int
            while (input.read(buffer).also { length = it } > 0) {
                output.write(buffer, 0, length)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            input?.close()
            output?.close()
        }
    }
}

为什么直接放Unity Assets目录不行?

Unity的Assets目录下的文件(除StreamingAssets外)会被Unity编译处理(比如转成AssetBundle或内置资源),不会以原始文件形式打包进APK,直接读取会触发资源解析异常;同时Unity没有自动将Assets内文件复制到外部数据目录的机制。

内容的提问来源于stack exchange,提问作者Angry Fool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:52:56