[Unity]화면 스크린샷 찍고 모바일 갤러리에 저장하기(Android, IOS)
게임을 만들다 보면 스크린 샷을 찍어서 갤러리에 저장 할 일이 종종 있다.
이번 포스팅은 스크린 샷 찍고 갤러리에 저장하는 기능을 다루었다.
1. 메니페스트 파일에 권한추가
스크린 샷을 찍고 파일을 사용자 핸드폰에 저장하기 위해서는 읽기 및 쓰기 권한이 필요하다.
아래의 권한을 선언한다.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. ScreenShot을 찍을 GameObject에 아래 DemoScript기능 추가.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.IO;
public class DemoScript : MonoBehaviour {
public bool hideGUI = false;
public Texture2D texture;
public Text console;
public CanvasGroup ui;
public Image screenshot;
private string paths=null;
void OnEnable ()
{
// call backs
ScreenshotManager.OnScreenshotTaken += ScreenshotTaken;
ScreenshotManager.OnScreenshotSaved += ScreenshotSaved;
ScreenshotManager.OnImageSaved += ImageSaved;
}
void OnDisable ()
{
ScreenshotManager.OnScreenshotTaken -= ScreenshotTaken;
ScreenshotManager.OnScreenshotSaved -= ScreenshotSaved;
ScreenshotManager.OnImageSaved -= ImageSaved;
}
//스크린샷찍고 저장.
public void OnSaveScreenshotPress()
{
ScreenshotManager.SaveScreenshot("MyScreenshot", "ScreenshotApp", "jpeg");
if(hideGUI) ui.alpha = 0;
}
//이미지 저장.
public void OnSaveImagePress()
{
ScreenshotManager.SaveImage(texture, "MyImage", "MyImages", "png");
}
void ScreenshotTaken(Texture2D image)
{
console.text += "\nScreenshot has been taken and is now saving...";
screenshot.sprite = Sprite.Create(image, new Rect(0, 0, image.width, image.height), new Vector2(.5f, .5f));
screenshot.color = Color.white;
ui.alpha = 1;
}
void ScreenshotSaved(string path)
{
console.text += "\nScreenshot finished saving to " + path;
paths = path;
}
void ImageSaved(string path)
{
console.text += "\n" + texture.name + " finished saving to " + path;
paths = path;
}
}
3. 스크린 샷을 찍고 기기에 저장하는 역할의 ScreenshotManager 코드 추가
#pragma warning disable 0168 // variable declared but not used.
#pragma warning disable 0219 // variable assigned but not used.
using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
public class ScreenshotManager : MonoBehaviour {
enum ImageType { IMAGE, SCREENSHOT };
enum SaveStatus { NOTSAVED, SAVED, DENIED, TIMEOUT };
public static event Action<Texture2D> OnScreenshotTaken;
public static event Action<string> OnScreenshotSaved;
public static event Action<string> OnImageSaved;
static ScreenshotManager instance = null;
static GameObject go;
#if UNITY_IOS
[DllImport("__Internal")]
private static extern int saveToGallery( string path );
#elif UNITY_ANDROID
static AndroidJavaClass obj;
#endif
//=============================================================================
// Init singleton
//=============================================================================
public static ScreenshotManager Instance
{
get {
if(instance == null)
{
go = new GameObject();
go.name = "ScreenshotManager";
instance = go.AddComponent<ScreenshotManager>();
#if UNITY_ANDROID
if(Application.platform == RuntimePlatform.Android)
obj = new AndroidJavaClass("com.secondfury.galleryscreenshot.MainActivity");
#endif
}
return instance;
}
}
void Awake()
{
if (instance != null && instance != this)
{
Destroy(this.gameObject);
}
}
//=============================================================================
// Grab and save screenshot
//=============================================================================
public static void SaveScreenshot(string fileName, string albumName = "MyScreenshots", string fileType = "jpg", Rect screenArea = default(Rect))
{
Debug.Log("Save screenshot to gallery " + fileName);
if(screenArea == default(Rect))
screenArea = new Rect(0, 0, Screen.width, Screen.height);
Instance.StartCoroutine(Instance.GrabScreenshot(fileName, albumName, fileType, screenArea));
}
IEnumerator GrabScreenshot(string fileName, string albumName, string fileType, Rect screenArea)
{
yield return new WaitForEndOfFrame();
Texture2D texture = new Texture2D ((int)screenArea.width, (int)screenArea.height, TextureFormat.RGB24, false);
texture.ReadPixels (screenArea, 0, 0);
texture.Apply ();
byte[] bytes;
string fileExt;
if(fileType == "png")
{
bytes = texture.EncodeToPNG();
fileExt = ".png";
}
else
{
bytes = texture.EncodeToJPG();
fileExt = ".jpg";
}
if(OnScreenshotTaken != null)
OnScreenshotTaken(texture);
else
Destroy (texture);
string date = System.DateTime.Now.ToString("hh-mm-ss_dd-MM-yy");
string screenshotFilename = fileName + "_" + date + fileExt;
string path = Application.persistentDataPath + "/" + screenshotFilename;
#if UNITY_ANDROID
if(Application.platform == RuntimePlatform.Android)
{
string androidPath = Path.Combine(albumName, screenshotFilename);
path = Path.Combine(Application.persistentDataPath, androidPath);
string pathonly = Path.GetDirectoryName(path);
Directory.CreateDirectory(pathonly);
}
#endif
Instance.StartCoroutine(Instance.Save(bytes, fileName, path, ImageType.SCREENSHOT));
}
//=============================================================================
// Save texture
//=============================================================================
public static void SaveImage(Texture2D texture, string fileName, string albumName = "MyImages", string fileType = "jpg")
{
Debug.Log("Save image to gallery " + fileName);
Instance.Awake();
byte[] bytes;
string fileExt;
if(fileType == "png")
{
bytes = texture.EncodeToPNG();
fileExt = ".png";
}
else
{
bytes = texture.EncodeToJPG();
fileExt = ".jpg";
}
string path = Application.persistentDataPath + "/" + fileName + fileExt;
#if UNITY_ANDROID
if(Application.platform == RuntimePlatform.Android)
{
string androidPath = Path.Combine(albumName, fileName + fileExt);
path = Path.Combine(Application.persistentDataPath, androidPath);
string pathonly = Path.GetDirectoryName(path);
Directory.CreateDirectory(pathonly);
}
#endif
Instance.StartCoroutine(Instance.Save(bytes, fileName, path, ImageType.IMAGE));
}
IEnumerator Save(byte[] bytes, string fileName, string path, ImageType imageType)
{
int count = 0;
SaveStatus saved = SaveStatus.NOTSAVED;
#if UNITY_IOS
if(Application.platform == RuntimePlatform.IPhonePlayer)
{
System.IO.File.WriteAllBytes(path, bytes);
while(saved == SaveStatus.NOTSAVED)
{
count++;
if(count > 30)
saved = SaveStatus.TIMEOUT;
else
saved = (SaveStatus)saveToGallery(path);
yield return Instance.StartCoroutine(Instance.Wait(.5f));
}
UnityEngine.iOS.Device.SetNoBackupFlag(path);
}
#elif UNITY_ANDROID
if(Application.platform == RuntimePlatform.Android)
{
System.IO.File.WriteAllBytes(path, bytes);
while(saved == SaveStatus.NOTSAVED)
{
count++;
if(count > 30)
saved = SaveStatus.TIMEOUT;
else
saved = (SaveStatus)obj.CallStatic<int>("addImageToGallery", path);
yield return Instance.StartCoroutine(Instance.Wait(.5f));
}
}
#else
yield return null;
Debug.Log("Gallery Manager: Save file only available in iOS/Android modes");
saved = SaveStatus.SAVED;
#endif
switch(saved)
{
case SaveStatus.DENIED:
path = "DENIED";
break;
case SaveStatus.TIMEOUT:
path = "TIMEOUT";
break;
}
switch(imageType)
{
case ImageType.IMAGE:
if(OnImageSaved != null)
OnImageSaved(path);
break;
case ImageType.SCREENSHOT:
if(OnScreenshotSaved != null)
OnScreenshotSaved(path);
break;
}
}
IEnumerator Wait(float delay)
{
float pauseTarget = Time.realtimeSinceStartup + delay;
while(Time.realtimeSinceStartup < pauseTarget)
{
yield return null;
}
}
}
이렇게 만든 뒤 함수를 호출해보면 찍은 이미지가 잘 저장되는 것을 볼 수 있다.
'Game Engine > Unity3D' 카테고리의 다른 글
[Unity]빌드한 앱 로그 PC에서 확인하기(Android apk) (0) | 2020.11.02 |
---|