Skip to content

I created a script to support Meta Quest 3 and Android Phone! #345

Description

@VR-Jobs

this script is a OnGUI script to support Android phone and VR Meta Quest 3, very useful!

Image

using System.Collections;
using UnityEngine;

public class AndroidImagePicker : MonoBehaviour
{
    [Header("Settings")]
    public int maxImageSize = 1024;
    public string albumName = "MyApp";

    // GUI 相关变量
    private string statusMessage = "点击按钮选择图片";
    private Texture2D currentTexture;
    private Vector2 scrollPosition = Vector2.zero;

    // GUI 样式
    private GUIStyle buttonStyle;
    private GUIStyle labelStyle;
    private GUIStyle boxStyle;
    private bool stylesInitialized = false;

    void Start()
    {
        // 初始化状态信息
        statusMessage = "点击按钮选择图片";
    }

    void OnGUI()
    {
        // 初始化GUI样式
        if (!stylesInitialized)
        {
            InitializeGUIStyles();
            stylesInitialized = true;
        }

        // 开始滚动视图
        scrollPosition = GUILayout.BeginScrollView(scrollPosition);

        // 主容器
        GUILayout.BeginVertical(boxStyle);

        // 标题
        GUILayout.Label("Android 图片选择器", labelStyle);
        GUILayout.Space(10);

        // 状态显示
        GUILayout.BeginHorizontal();
        GUILayout.Label("状态: ", GUILayout.Width(50));
        GUILayout.Label(statusMessage);
        GUILayout.EndHorizontal();
        GUILayout.Space(10);

        // 选择多张图片按钮
        if (GUILayout.Button("选择图片", buttonStyle, GUILayout.Height(50)))
        {
            PickMultipleImages();
        }
        GUILayout.Space(10);

        // 保存按钮(如果有当前图片的话)
        if (currentTexture != null)
        {
            if (GUILayout.Button("保存图片到相册", buttonStyle, GUILayout.Height(35)))
            {
                SaveImageToGallery();
            }
            GUILayout.Space(10);
        }

        // 图片显示区域
        if (currentTexture != null)
        {
            GUILayout.Label("选择的图片:", labelStyle);
            GUILayout.Space(5);

            // 计算显示尺寸,保持宽高比
            float maxDisplayWidth = Screen.width - 40;
            float maxDisplayHeight = Screen.height * 0.4f;

            float aspectRatio = (float)currentTexture.width / currentTexture.height;
            float displayWidth, displayHeight;

            if (aspectRatio > 1) // 横图
            {
                displayWidth = Mathf.Min(maxDisplayWidth, currentTexture.width);
                displayHeight = displayWidth / aspectRatio;
            }
            else // 竖图或正方形
            {
                displayHeight = Mathf.Min(maxDisplayHeight, currentTexture.height);
                displayWidth = displayHeight * aspectRatio;
            }

            // 居中显示图片
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            GUILayout.Label(currentTexture, GUILayout.Width(displayWidth), GUILayout.Height(displayHeight));
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            GUILayout.Space(10);

            // 图片信息
            GUILayout.Label($"图片尺寸: {currentTexture.width} x {currentTexture.height}", labelStyle);
        }

        GUILayout.Space(20);

        // 设置区域
        GUILayout.Label("设置:", labelStyle);

        GUILayout.BeginHorizontal();
        GUILayout.Label("最大图片尺寸:", GUILayout.Width(100));
        string maxSizeStr = GUILayout.TextField(maxImageSize.ToString(), GUILayout.Width(100));
        if (int.TryParse(maxSizeStr, out int newMaxSize))
        {
            maxImageSize = newMaxSize;
        }
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("相册名称:", GUILayout.Width(100));
        albumName = GUILayout.TextField(albumName, GUILayout.Width(150));
        GUILayout.EndHorizontal();

        GUILayout.EndVertical();

        // 结束滚动视图
        GUILayout.EndScrollView();
    }

    /// <summary>
    /// 初始化GUI样式
    /// </summary>
    private void InitializeGUIStyles()
    {
        // 按钮样式
        buttonStyle = new GUIStyle(GUI.skin.button);
        buttonStyle.fontSize = 16;
        buttonStyle.fontStyle = FontStyle.Bold;

        // 标签样式
        labelStyle = new GUIStyle(GUI.skin.label);
        labelStyle.fontSize = 14;
        labelStyle.fontStyle = FontStyle.Bold;

        // 框体样式
        boxStyle = new GUIStyle(GUI.skin.box);
        boxStyle.padding = new RectOffset(10, 10, 10, 10);
    }

    /// <summary>
    /// 选择多张图片(Android 18+,iOS 14+支持)
    /// </summary>
    public void PickMultipleImages()
    {
        // 检查是否已经在选择媒体文件
        if (NativeGallery.IsMediaPickerBusy())
        {
            UpdateStatus("正在选择图片,请稍候...");
            return;
        }

        // 检查设备是否支持多选
        if (!NativeGallery.CanSelectMultipleFilesFromGallery())
        {
            UpdateStatus("当前设备不支持选择多张图片");
            return;
        }

        // 检查权限
        CheckPermissionAndPickImages();
    }

    /// <summary>
    /// 检查权限并选择图片
    /// </summary>
    private void CheckPermissionAndPickImages()
    {
        bool hasPermission = NativeGallery.CheckPermission(NativeGallery.PermissionType.Read, NativeGallery.MediaType.Image);

        if (hasPermission)
        {
            // 有权限,直接选择图片
            PickImages();
        }
        else
        {
            // 需要请求权限
            UpdateStatus("请求权限中...");
            NativeGallery.RequestPermissionAsync(OnPermissionResult, NativeGallery.PermissionType.Read, NativeGallery.MediaType.Image);
        }
    }

    /// <summary>
    /// 权限请求结果回调
    /// </summary>
    /// <param name="permission">权限结果</param>
    private void OnPermissionResult(NativeGallery.Permission permission)
    {
        if (permission == NativeGallery.Permission.Granted)
        {
            UpdateStatus("权限获取成功!");
            PickImages();
        }
        else
        {
            UpdateStatus("权限被拒绝,无法访问相册");

            if (permission == NativeGallery.Permission.Denied)
            {
                // 权限被永久拒绝,提示用户去设置中开启
                UpdateStatus("权限被永久拒绝,请在设置中手动开启相册权限");
            }
        }
    }

    /// <summary>
    /// 执行选择图片操作
    /// </summary>
    private void PickImages()
    {
        UpdateStatus("正在打开相册选择多张图片...");

        NativeGallery.GetImagesFromGallery((paths) =>
        {
            if (paths != null && paths.Length > 0)
            {
                UpdateStatus($"选择了 {paths.Length} 张图片");

                // 输出选择的多张图片
                for (int i = 0; i < paths.Length; i++)
                {
                    Debug.Log($"图片 {i + 1}: {paths[i]}");
                }

                // 显示第一张图片
                if (paths.Length > 0)
                {
                    LoadAndDisplayImage(paths[0]);
                }
            }
            else
            {
                UpdateStatus("已取消选择图片");
            }
        }, "选择图片", "image/*");
    }

    /// <summary>
    /// 加载并显示选择的图片
    /// </summary>
    /// <param name="imagePath">图片路径</param>
    private void LoadAndDisplayImage(string imagePath)
    {
        // 释放之前的纹理以避免内存泄漏
        if (currentTexture != null)
        {
            Destroy(currentTexture);
            currentTexture = null;
        }

        // 从路径加载图片
        currentTexture = NativeGallery.LoadImageAtPath(imagePath, maxImageSize, false, true, false);

        if (currentTexture != null)
        {
            UpdateStatus($"图片加载成功!尺寸: {currentTexture.width}x{currentTexture.height}");

            // 可选:获取图片属性
            GetImageProperties(imagePath);
        }
        else
        {
            UpdateStatus("图片加载失败");
            Debug.LogError("无法从路径加载纹理: " + imagePath);
        }
    }

    /// <summary>
    /// 保存当前图片到相册(可选功能)
    /// </summary>
    public void SaveImageToGallery()
    {
        if (currentTexture == null)
        {
            UpdateStatus("没有图片可保存");
            return;
        }

        UpdateStatus("正在保存图片到相册...");

        NativeGallery.SaveImageToGallery(currentTexture, albumName, "SavedImage.png", (success, path) =>
        {
            if (success)
            {
                UpdateStatus("图片保存成功!路径: " + path);
                Debug.Log("图片保存成功: " + path);
            }
            else
            {
                UpdateStatus("图片保存失败");
                Debug.LogError("图片保存失败");
            }
        });
    }

    /// <summary>
    /// 更新状态文本
    /// </summary>
    /// <param name="message">状态信息</param>
    private void UpdateStatus(string message)
    {
        statusMessage = message;
        Debug.Log("状态: " + message);
    }

    /// <summary>
    /// 获取图片属性信息(可选功能)
    /// </summary>
    /// <param name="imagePath">图片路径</param>
    private void GetImageProperties(string imagePath)
    {
        NativeGallery.ImageProperties properties = NativeGallery.GetImageProperties(imagePath);

        if (properties.width > 0 && properties.height > 0)
        {
            Debug.Log($"图片属性 - 宽度: {properties.width}, 高度: {properties.height}, MIME类型: {properties.mimeType}, 方向: {properties.orientation}");
        }
        else
        {
            Debug.Log("无法获取图片属性");
        }
    }

    /// <summary>
    /// 清理资源
    /// </summary>
    void OnDestroy()
    {
        if (currentTexture != null)
        {
            Destroy(currentTexture);
        }
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions