Unity游戏APK打包前手动添加指定文件夹至数据目录方法
问题解答
直接通过Android Studio将文件夹打包进APK后自动部署到Android/Data/com.application.name/needed_folder/目录是做不到的——APK内的文件默认存放在应用内部的assets/res目录,不会自动复制到外部的公共数据目录。以下是两种可行的解决方案:
方案1:Unity端处理(推荐,无需跳转Android Studio)
- 把需要的文件夹放到Unity的
StreamingAssets目录下,这个目录的内容会以原始文件形式打包进APK的assets目录。 - 编写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工程
- 将目标文件夹放到Android Studio工程的
src/main/assets目录下。 - 在原生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
相关产品推荐
相关产品推荐

