251 lines
10 KiB
Java
251 lines
10 KiB
Java
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|