package com.unity.filepicker; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.provider.OpenableColumns; import android.util.Log; import com.unity3d.player.UnityPlayer; import java.io.ByteArrayOutputStream; import java.io.InputStream; public class FilePicker { private static final String TAG = "[FILE-PICKER]"; private static final int REQUEST_CODE_PICK_FILE = 1001; private static FilePickerCallback callback; public interface FilePickerCallback { void onFileSelected(String filePath, String fileName, byte[] fileData); void onFileSelectCanceled(); void onError(String error); } /** * 打开文件选择器 */ public static void pickFile(String[] mimeTypes, FilePickerCallback cb) { Log.d(TAG, "[JAVA] pickFile() 被调用"); callback = cb; try { Activity activity = UnityPlayer.currentActivity; if (activity == null) { Log.e(TAG, "[JAVA] UnityPlayer.currentActivity 为 null"); if (callback != null) { callback.onError("无法获取当前Activity"); } return; } Log.d(TAG, "[JAVA] 获取到当前Activity: " + activity.getClass().getName()); // 设置回调到 Activity setupActivityCallback(activity); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); // 设置可选的MIME类型 if (mimeTypes != null && mimeTypes.length > 0) { intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); Log.d(TAG, "[JAVA] 设置MIME类型: " + java.util.Arrays.toString(mimeTypes)); } intent.addCategory(Intent.CATEGORY_OPENABLE); // 创建选择器 Intent chooser = Intent.createChooser(intent, "选择固件文件"); Log.d(TAG, "[JAVA] 创建文件选择器Intent成功"); // 启动文件选择器 Log.d(TAG, "[JAVA] 启动文件选择器,requestCode=" + REQUEST_CODE_PICK_FILE); activity.startActivityForResult(chooser, REQUEST_CODE_PICK_FILE); Log.d(TAG, "[JAVA] startActivityForResult 调用成功"); } catch (Exception e) { Log.e(TAG, "[JAVA] 打开文件选择器失败: " + e.getMessage()); e.printStackTrace(); if (callback != null) { callback.onError("打开文件选择器失败: " + e.getMessage()); } } } /** * 设置Activity回调 */ private static void setupActivityCallback(Activity activity) { Log.d(TAG, "[JAVA] 设置Activity回调..."); // 使用反射设置回调 try { // 检查是否是 UnityActivityCallback 类型 if (activity instanceof UnityActivityCallback) { Log.d(TAG, "[JAVA] Activity 是 UnityActivityCallback 类型"); ((UnityActivityCallback) activity).setCallback(new UnityActivityCallback.FilePickerResultCallback() { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "[JAVA] UnityActivityCallback.onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode); handleActivityResult(requestCode, resultCode, data); } }); } else { Log.w(TAG, "[JAVA] Activity 不是 UnityActivityCallback 类型,尝试使用反射"); // 尝试使用反射设置静态回调 UnityActivityCallback.setCallback(new UnityActivityCallback.FilePickerResultCallback() { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "[JAVA] 通过反射回调: requestCode=" + requestCode + ", resultCode=" + resultCode); handleActivityResult(requestCode, resultCode, data); } }); } Log.d(TAG, "[JAVA] Activity回调设置成功"); } catch (Exception e) { Log.e(TAG, "[JAVA] 设置Activity回调失败: " + e.getMessage()); e.printStackTrace(); } } /** * 处理Activity结果 - 这个方法会被UnityActivityCallback调用 */ public static void handleActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "[JAVA] handleActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode); if (requestCode != REQUEST_CODE_PICK_FILE) { Log.d(TAG, "[JAVA] requestCode不匹配,忽略"); return; } if (resultCode != Activity.RESULT_OK || data == null) { Log.d(TAG, "[JAVA] 用户取消选择或data为null, resultCode=" + resultCode); if (callback != null) { callback.onFileSelectCanceled(); } return; } // 在后台线程读取文件,避免阻塞主线程 final Activity activity = UnityPlayer.currentActivity; final Uri uri = data.getData(); if (uri == null) { Log.e(TAG, "[JAVA] 无法获取文件URI"); if (callback != null) { callback.onError("无法获取文件URI"); } return; } Log.d(TAG, "[JAVA] 文件URI: " + uri.toString()); Log.d(TAG, "[JAVA] 在后台线程读取文件..."); new Thread(new Runnable() { @Override public void run() { try { // 获取文件名 Log.d(TAG, "[JAVA] 获取文件名..."); final String fileName = getFileName(activity, uri); Log.d(TAG, "[JAVA] 文件名: " + fileName); // 读取文件数据 Log.d(TAG, "[JAVA] 读取文件数据..."); final byte[] fileData = readFileData(activity, uri); Log.d(TAG, "[JAVA] 文件数据读取成功,大小: " + fileData.length); // 获取文件路径 final String filePath = uri.toString(); Log.d(TAG, "[JAVA] 选择文件成功: " + fileName + ", 大小: " + fileData.length); // 在主线程回调 activity.runOnUiThread(new Runnable() { @Override public void run() { if (callback != null) { Log.d(TAG, "[JAVA] 调用回调 onFileSelected"); callback.onFileSelected(filePath, fileName, fileData); } else { Log.e(TAG, "[JAVA] callback 为 null"); } } }); } catch (final Exception e) { Log.e(TAG, "[JAVA] 读取文件失败: " + e.getMessage()); e.printStackTrace(); activity.runOnUiThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onError("读取文件失败: " + e.getMessage()); } } }); } } }).start(); } /** * 获取文件名 */ private static String getFileName(Activity activity, Uri uri) { String result = null; if (uri.getScheme().equals("content")) { Log.d(TAG, "[JAVA] URI scheme is content, querying ContentResolver..."); try (Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); if (index >= 0) { result = cursor.getString(index); Log.d(TAG, "[JAVA] 从ContentResolver获取文件名: " + result); } } } catch (Exception e) { Log.e(TAG, "[JAVA] 查询ContentResolver失败: " + e.getMessage()); } } if (result == null) { result = uri.getLastPathSegment(); Log.d(TAG, "[JAVA] 从URI path获取文件名: " + result); } return result != null ? result : "unknown"; } /** * 读取文件数据 */ private static byte[] readFileData(Activity activity, Uri uri) throws Exception { Log.d(TAG, "[JAVA] 开始读取文件数据..."); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try (InputStream inputStream = activity.getContentResolver().openInputStream(uri)) { if (inputStream == null) { throw new Exception("无法打开文件输入流"); } byte[] buffer = new byte[4096]; int bytesRead; int totalBytes = 0; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); totalBytes += bytesRead; } Log.d(TAG, "[JAVA] 文件读取完成,总字节数: " + totalBytes); } catch (Exception e) { Log.e(TAG, "[JAVA] 读取文件时发生错误: " + e.getMessage()); throw e; } return outputStream.toByteArray(); } }