Java、Objective-C 傳送圖片到遊戲引擎
3 min
前言
我的工作內容之一,是把 iOS、Android 的原生功能串接進遊戲引擎,像是 IAP、Permission、AlertDialog 這類平台能力,盡量整理成遊戲端可以直接呼叫的形式,讓遊戲專案本身可以更專心在遊戲與商業邏輯上。
這次剛好遇到一個需求,要讓玩家從手機相簿挑選圖片,並把它送進 Unity 或 Unreal 內做後續處理,所以就順手整理一下這個做法。

封面圖片來源:Unity, Unreal, Native : Choose Better Game Engine for Mobile Game Development
功能需求
這次的需求起因,是遊戲專案需要讓玩家自訂頭像。
原本專案內使用的 Unity 套件已經沒有持續更新,對新版 Android 的隱私權政策支援也不夠完整,所以最後這個 case 就轉回原生端處理,再把結果傳回引擎。
作法簡介
整體做法其實很單純,就是先把圖片轉成 byte array,再編碼成 base64 字串送進引擎,由引擎端再做 decode 與 texture 建立。
處理順序如下:
- Convert to byte array
- Encode to base64
- Send message to engine
- Engine base64 decode
- Convert to engine texture
引擎注意事項
Unity 可以接受帶有換行的 Base64 字串,但 Unreal 對這件事比較嚴格。 為了避免跨引擎差異,原生端建議直接使用「不帶換行」的 Base64 內容。
Objective-C
// 選擇照片的 callback
- (void)onSelectPhotoSuccess:(UIImage *)chosenImage
{
CGFloat quality = 0.8;
NSData *data = UIImageJPEGRepresentation(chosenImage, quality);
[self sendPhotoDataToEngine:data];
}
// 傳送處理後的 data 給遊戲引擎
- (void)sendPhotoDataToEngine:(NSData *)photoData
{
if (photoData != nil)
{
// 使用 0 代表不插入換行,跨 Unity / Unreal 會比較穩定
NSString *base64Str = [photoData base64EncodedStringWithOptions:0];
// Use your way to Engine
}
}Java
// 選擇照片的 callback
private void onSelectPhotoSuccess(Bitmap bitmap) {
int quality = 80;
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, quality, out);
sendPhotoDataToEngine(out.toByteArray());
}
// 傳送處理後的 data 給遊戲引擎
private void sendPhotoDataToEngine(byte[] data) {
String resultString = "";
// Unity 對 Base64.DEFAULT 的容忍度較高
resultString = Base64.encodeToString(data, Base64.DEFAULT);
// 若要兼容 Unreal,建議不要帶換行
resultString = Base64.encodeToString(data, Base64.NO_WRAP);
// Use your way to Engine
}Unity
/// <summary>
/// 處理傳來的 base64
/// </summary>
/// <param name="base64Str">圖片資訊</param>
private void ConvertBase64ToBytes(string base64Str)
{
byte[] bytes = System.Convert.FromBase64String(base64Str);
ConvertBytesToTexture(bytes);
}
/// <summary>
/// 轉換為 Texture
/// </summary>
/// <param name="photoByteArray">圖片 byte array</param>
private void ConvertBytesToTexture(byte[] photoByteArray)
{
if (photoByteArray != null)
{
// 如果有需要,也可以把長寬從 Java、iOS 一起傳過來
var photoTexture = new Texture2D(width, height);
photoTexture.LoadImage(photoByteArray);
}
}Unreal
// 略過相關的 C / JNI 類型轉換
void Sample::ConvertBase64ToTexture2D(FString base64Str)
{
TArray<uint8> sourceData;
FBase64::Decode(base64Str, sourceData);
UTexture2D* outTexture = FImageUtils::ImportBufferAsTexture2D(sourceData);
}Comments
Loading comments...