UE4打包釋出後,在Windows和Android平臺上訪問非Asset檔案

hesetone發表於2024-06-26

1、問題來源

  最近的專案裡面有個需求,要在打包之後的exe或者apk執行起來後訪問工程Content或者安卓目錄下的非Asset檔案,比如text檔案,json檔案等,從中讀取一些可隨時修改的配置項資訊。但是這些沒法直接被UE平臺序列化儲存,因此需要做一點點額外的操作來實現我們的目標,假設工程目錄Content裡面有個Json目錄,Json裡面有個A.json檔案,程式在執行時需要讀取A.json。

  下面針對WindowsAndroid平臺依次展開討論怎麼做。

2、Windows平臺

  第一步,在Project Settings->Project->Packaging下面,取消勾選Use Pak File,因為打包成.pak檔案的話,Content目錄下的所有資源(Asset檔案或Non-Asset檔案),都會被打包進一個.pak檔案,後期無法隨時修改。

  第二步,在Project Setting頂部搜尋asset,在Additional Non-Asset Directories to Package右邊點選加號,在新增的一行右側點選"..."標記,新增一條路徑指向Conent目錄下的Json資料夾。

  打包一下,資料夾裡面顯示我們的Json/A.json已經作為獨立檔案成功打包到WindowsNoEditor目錄下。

  寫幾行測試一下看看行不行,假設我要藍圖裡面讀A.jsonC++封裝函式如下,其實主要是要透過FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir()) + JsonName拼接得到A.json的正確絕對路徑

 1 bool UJsonOperator::FindValueWithGivenProperty(FString JsonName, FString FieldName, FString& Val)
 2 {
 3     FString AbsoluteJsonPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir()) + JsonName;
 4     if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*AbsoluteJsonPath)) {
 5         UE_LOG(MiniFileReaderLog, Warning, TEXT("%s"), *AbsoluteJsonPath); // do not call UKismetSystemLibrary::PrintString in static function
 6 
 7         FString JsonData;
 8         FFileHelper::LoadFileToString(JsonData, *AbsoluteJsonPath);
 9 
10         /* convert fstring to json object. */
11         TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(JsonData);
12         TSharedPtr<FJsonObject> RootJsonObj = MakeShareable(new FJsonObject);
13 
14         if (FJsonSerializer::Deserialize(JsonReader, RootJsonObj)) {
15             UE_LOG(MiniFileReaderLog, Warning, TEXT("Json Data: %s"), *JsonData);
16 
17             TSharedPtr<FJsonValue> Member = RootJsonObj->TryGetField(FieldName);
18             if (Member) {
19                 Val = Member->AsString();
20                 UE_LOG(MiniFileReaderLog, Log, TEXT("Property [%s], Value: %s"), *FieldName, *(Member->AsString()));
21             }
22             else {
23                 UE_LOG(MiniFileReaderLog, Warning, TEXT("Property [%s] specified not exists."), *FieldName);
24                 return false;
25             }
26         }
27         else {
28             UE_LOG(MiniFileReaderLog, Warning, TEXT("FJsonSerializer::Deserialize Failed!"));
29             return false;
30         }
31     }
32     else {
33         UE_LOG(MiniFileReaderLog, Error, TEXT("File : %s not exists."), *JsonName);
34         return false;
35     }
36     return true;
37 }

3、Android平臺

  Android平臺略有不同,UE工程釋出到安卓裝置並啟動之後,會在安卓裝置的/storage/emulated/0/UE4Game目錄下新建一個和UE Project Name的同名目錄。該目錄存放程式的執行資料,此處工程名假設為FunctionProject

  第一步,在執行資料目錄新建Json/A.json,如下所示,裡面存放程式需要讀取的屬性資料資訊。

  第二步,寫一段示例程式碼讀取到該目錄下的A.json檔案,如下所示:

bool UJsonOperator::LoadRawContentsToString(FString FileName, FString& FileContents)
{
#if PLATFORM_ANDROID
    extern FString GFilePathBase;
    FString tmp = GFilePathBase + FString("/UE4Game/") + UKismetSystemLibrary::GetGameName() + FString("/") + FileName;
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT("%s"), *tmp));
    return FFileHelper::LoadFileToString(FileContents, *tmp);
#else
    const FString ThePath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir());
    UE_LOG(MiniFileReaderLog, Log, TEXT("Json Path: %s"), *(ThePath + FileName));
    return FFileHelper::LoadFileToString(FileContents, *(ThePath + FileName));
#endif
}

  此處,UKismetSystemLibrary::GetGameName()就是獲取UE4Game目錄下的APP釋出名稱,可以理解為Android APP執行資料的根目錄,函式傳入引數的第1個引數FileNameJson/A.json,那麼最終拼接得到的A.json絕對路徑為:

/storage/emulated/0/UE4Game/FunctionProject/Json/A.json

  拿到這個絕對路徑,就可以讀取檔案內容了,到此結束!

相關文章