Unity项目中如何实现游戏生成文件至Web/Android/iOS设备的下载功能
Unity跨平台文件下载实现方案
以下是针对WebGL、Android、iOS三个平台的具体实现方案,无需依赖AssetStore插件,直接通过原生API和少量原生代码即可完成:
WebGL平台
WebGL受浏览器沙箱限制,无法直接写入本地文件,需借助浏览器的下载API触发用户下载。核心思路是将文件数据转为可被浏览器识别的格式,通过JS触发下载链接。
C#代码
using UnityEngine; using System.IO; public class FileDownloader : MonoBehaviour { public void TriggerWebGLDownload(string fileName, byte[] fileData) { // 将字节数组转为Base64(小文件适用) string base64Data = System.Convert.ToBase64String(fileData); // 调用嵌入的JS函数 Application.ExternalEval($"initFileDownload('{fileName}', '{base64Data}')"); } }
WebGL模板JS代码
在WebGL打包后的index.html中添加以下JS函数(或直接修改Unity的WebGL模板文件):
function initFileDownload(fileName, base64Data) { const link = document.createElement('a'); link.href = `data:application/octet-stream;base64,${base64Data}`; link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); }
注意:大文件建议改用Blob对象优化性能,将C#中的字节数组直接传递给JS,替换上述JS函数为:
function initFileDownload(fileName, arrayBuffer) { const blob = new Blob([arrayBuffer]); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = fileName; link.click(); URL.revokeObjectURL(url); }对应的C#代码需调整为通过
SendMessage传递字节数组,避免Base64编码开销。
Android平台
Android可直接写入外部存储,需先申请读写权限,再将文件写入公共目录,最后通知系统刷新媒体库。
权限配置
在Plugins/Android/AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
C#代码
using UnityEngine; using System.IO; using UnityEngine.Android; public class FileDownloader : MonoBehaviour { public void TriggerAndroidDownload(string fileName, byte[] fileData) { // 检查权限 if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite)) { Permission.RequestUserPermission(Permission.ExternalStorageWrite); return; } // 写入外部存储根目录 string savePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, fileName); File.WriteAllBytes(savePath, fileData); // 通知系统刷新媒体库 using (var mediaScanner = new AndroidJavaClass("android.media.MediaScannerConnection")) using (var context = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity")) { mediaScanner.CallStatic("scanFile", context, new string[] { savePath }, null, null); } } }
注意:Android 10及以上推荐使用Scoped Storage,避免直接操作外部存储根目录,可改用
MediaStoreAPI写入公共媒体目录。
iOS平台
iOS需将文件写入应用的Documents目录,再通过UIDocumentInteractionController唤起系统分享面板,让用户选择保存到本地或其他应用。
C#代码
using UnityEngine; using System.IO; using System.Runtime.InteropServices; public class FileDownloader : MonoBehaviour { [DllImport("__Internal")] private static extern void ShowFileSharingPanel(string filePath); public void TriggeriOSDownload(string fileName, byte[] fileData) { // 写入应用Documents目录 string docsPath = Application.persistentDataPath; string savePath = Path.Combine(docsPath, fileName); File.WriteAllBytes(savePath, fileData); // 唤起系统分享面板 if (Application.platform == RuntimePlatform.IPhonePlayer) { ShowFileSharingPanel(savePath); } } }
iOS原生代码
在Plugins/iOS目录下创建FileSharer.m文件,添加以下代码:
#import <UIKit/UIKit.h> @interface FileSharer : NSObject <UIDocumentInteractionControllerDelegate> @end @implementation FileSharer UIDocumentInteractionController* _docController; + (void)showSharingPanelForFile:(NSString*)filePath { NSURL* fileURL = [NSURL fileURLWithPath:filePath]; _docController = [UIDocumentInteractionController interactionControllerWithURL:fileURL]; _docController.delegate = self; // 获取当前顶层ViewController UIViewController* currentVC = [UIApplication sharedApplication].keyWindow.rootViewController; while (currentVC.presentedViewController) { currentVC = currentVC.presentedViewController; } [_docController presentOptionsMenuFromRect:CGRectZero inView:currentVC.view animated:YES]; } - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller { return [UIApplication sharedApplication].keyWindow.rootViewController; } @end extern "C" { void ShowFileSharingPanel(const char* filePath) { NSString* nsFilePath = [NSString stringWithUTF8String:filePath]; [FileSharer showSharingPanelForFile:nsFilePath]; } }
内容的提问来源于stack exchange,提问作者Happy_cat
相关产品推荐
相关产品推荐

