首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 打開所有類型文件選擇器:ACTION_GET_CONTENT 與第三方文件管理器協作

     編輯:程式設計綜合問答

現象

Intent.ACTION_GET_CONTENT 配合 setType("image/*") 僅能選圖片,需選擇任意類型文件 (PDF、ZIP、APK 等)。

核心限制:Android 無內置通用文件選擇器

Android 系統不提供統一的「所有文件」選擇器 UI。ACTION_GET_CONTENT 依賴安裝的應用響應,僅有圖庫/文件管理器等應用註冊了特定 MIME 類型。

方案一:設置 MIME 為 */* (嘗試匹配所有)


Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*"); // 理論匹配所有類型
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "選擇文件"), REQUEST_CODE);

缺點:很多文件管理器未正確註冊 */*,彈出選擇器為空或僅顯示圖庫。

方案二:指定常見 MIME 類型集合 (較穩健)


Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// 明確列出常見類型,提高匹配率
String[] mimeTypes = {
    "application/pdf",
    "application/zip",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "application/vnd.android.package-archive", // APK
    "text/plain",
    "image/*",
    "video/*",
    "audio/*"
};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "選擇文件"), REQUEST_CODE);

方案三:Storage Access Framework (API 19+,現代標準)


// 打開系統文件選擇器 (DocumentPicker)
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*"); // 或具體類型
// 可選:指定初始目錄 (API 21+)
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, DocumentsContract.buildRootsUri("com.android.externalstorage.documents"));
startActivityForResult(intent, REQUEST_CODE_DOCUMENT);

// onActivityResult
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK && data != null) {
        Uri uri = data.getData();
        // 獲取持久化權限
        getContentResolver().takePersistableUriPermission(uri, 
            Intent.FLAG_GRANT_READ_URI_PERMISSION);
        // 使用 ContentResolver 讀取流
        InputStream is = getContentResolver().openInputStream(uri);
    }
}

優勢:系統級 UI、支援雲端/網絡存儲、持久化 URI 權限、無需讀取存儲權限。

方案四:第三方文件選擇器庫 (推薦複雜需求)

  • MaterialFilePicker:Material Design 風格、單文件/多選、過濾器
  • FilePicker (by DroidNinja):支援雲端、圖片預覽、高度可定制
  • Android-FilePicker:輕量、無依賴

舊版兼容:ACTION_GET_CONTENT + ACTION_OPEN_DOCUMENT 兜底


public void openFilePicker() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // API 19+ 優先用 SAF
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        startActivityForResult(intent, REQUEST_SAF);
    } else {
        // 老版本兜底
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        startActivityForResult(Intent.createChooser(intent, "選擇文件"), REQUEST_LEGACY);
    }
}

權限說明

方案需權限備註
ACTION_GET_CONTENT無 (臨時 URI 權限)返回 URI 臨時有效
ACTION_OPEN_DOCUMENT無 (持久化 URI 權限)takePersistableUriPermission 長期訪問
文件管理器 AppREAD_EXTERNAL_STORAGEAndroid 10+ 分區存儲限制

總結建議

  1. API 19+ 首選 ACTION_OPEN_DOCUMENT (SAF):系統標準、體驗一致、權限模型清晰
  2. 需自定義 UI/雲端/多選:集成成熟第三方庫
  3. 不要指望系統有完美的 */* 選擇器:生態碎片化導致體驗參差不齊
  4. Android 10+ (Q) 分區存儲:直接訪問文件路徑已不可行,必須用 SAF / MediaStore / ContentResolver
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved