From 7914b7b4c519c319cf31dd3f0805793358701da3 Mon Sep 17 00:00:00 2001 From: Gyubin Han Date: Thu, 1 Jan 2026 04:19:26 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20MANAGE=5FEXTERNAL=5FSTORAGE=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=93=B0=EA=B8=B0=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제: Android 11+ Scoped Storage로 인해 EPERM (Operation not permitted) 에러 발생 - Storage Access Framework로 디렉토리 선택했지만 File API로 쓰기 시도 - 권한 부족으로 파일 업로드(STOR) 실패 해결: - AndroidManifest.xml에 MANAGE_EXTERNAL_STORAGE 권한 추가 - MainActivity에서 Android 11+ (API 30+) 권한 요청 로직 추가 * Environment.isExternalStorageManager()로 권한 확인 * Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION으로 설정 화면 이동 * 서버 시작 전 권한 체크 추가 - 이 권한으로 외부 저장소 전체에 File API 접근 가능 사용자는 앱 실행 시 "All files access" 권한 활성화 필요 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- app/src/main/AndroidManifest.xml | 1 + .../gyu/android/server/ftp/MainActivity.java | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a31e421..98142e6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ + = Build.VERSION_CODES.TIRAMISU) { - // Android 13+ - if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - new String[]{ - Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.READ_MEDIA_VIDEO, - Manifest.permission.READ_MEDIA_AUDIO - }, - PERMISSION_REQUEST_CODE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // Android 11+ - Need MANAGE_EXTERNAL_STORAGE + if (!Environment.isExternalStorageManager()) { + try { + Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivity(intent); + Toast.makeText(this, "Please grant 'All files access' permission", Toast.LENGTH_LONG).show(); + } catch (Exception e) { + Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); + startActivity(intent); + } } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - // Android 6.0 - 12 + // Android 6.0 - 10 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, @@ -172,6 +175,15 @@ public class MainActivity extends AppCompatActivity { } private void startFTPServer() { + // Check permission first + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) { + Toast.makeText(this, "Please grant 'All files access' permission first", Toast.LENGTH_LONG).show(); + requestPermissions(); + return; + } + } + if (!config.hasRootDirectory()) { Toast.makeText(this, "Please select a root directory first", Toast.LENGTH_LONG).show(); return;