Android'de FileUriExposedException olmadan güvenli dosya paylaşımı

Kerem Aydın·7 Temmuz 2026·⏱2 dk

Harici uygulamalara file:// URI göndermek yasaktır — bu durum Android 7+ üzerinde FileUriExposedException hatasına yol açar; çözüm, FileProvider aracılığıyla content:// URI sağlamak ve Intent.FLAG_GRANT_READ_URI_PERMISSION / FLAG_GRANT_WRITE_URI_PERMISSION eklemektir. Aşağıda minimum konfigürasyon, kod ve hızlı kontroller yer almaktadır.

FileProvider kurulumu (manifest ve file_paths.xml)

  1. Manifest dosyasında etiketi içine provider ekleyin (AndroidX):
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.example.myapp.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
  1. res/xml/file_paths.xml oluşturun — yalnızca gerçekten izin vermek istediğiniz dizinleri belirtin:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="internal_files" path="." />
    <cache-path name="internal_cache" path="." />
    <external-files-path name="external_files" path="." />
    <external-cache-path name="external_cache" path="." />
</paths>

Son çare olmadıkça root-path eklemeyin — cihazın kök dosya sistemini açar.

URI oluşturma ve Intent gönderme — pratik örnekler

  1. Bir File için content:// URI elde etme

Kotlin:

val file = File(context.filesDir, "reports/report1.pdf")
val uri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", file)

Java:

File file = new File(context.getFilesDir(), "reports/report1.pdf");
Uri uri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", file);
  1. ACTION_SEND (paylaşım) — mutlaka okuma izni bayrağını ekleyin:
val send = Intent(Intent.ACTION_SEND).apply {
    type = "application/pdf"
    putExtra(Intent.EXTRA_STREAM, uri)
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(Intent.createChooser(send, "Share file"))
  1. ACTION_VIEW:
val view = Intent(Intent.ACTION_VIEW).apply {
    setDataAndType(uri, "image/*")
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(view)
  1. Kamera — EXTRA_OUTPUT (dosyanıza yazma):
val photoFile = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "shot.jpg")
val photoUri = FileProvider.getUriForFile(context, AUTHORITY, photoFile)
val takePic = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
    putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
    addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
startActivityForResult(takePic, REQ_CAMERA)

getUriForFile, dosya file_paths.xml içindeki tanımlara uymuyorsa IllegalArgumentException fırlatır — yol eşleşmelerini kontrol edin.

Erişim garantisi: grantUriPermission ve ClipData

Intent birden fazla uygulama tarafından işlenebiliyorsa (chooser) — tüm potansiyel alıcılara açıkça izin verin:

val resList = context.packageManager.queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY)
for (res in resList) {
    val pkg = res.activityInfo.packageName
    context.grantUriPermission(pkg, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}

Gerekirse revokeUriPermission yapmayı unutmayın. Modern API'lerde ClipData ile ayarlanan bayraklar genellikle izinleri otomatik olarak yayar, ancak açık grant uyumluluğu artırır.

file_paths.xml temel etiketlerinin karşılaştırılması

EtiketNe sağlarNe zaman kullanılır
files-pathgetFilesDir()Dahili özel dosyalar
cache-pathgetCacheDir()Geçici dosyalar
external-files-pathgetExternalFilesDir()Kullanıcı dosyaları, dışarıdan görünür (ancak uygulama için özeldir)
external-cache-pathgetExternalCacheDir()Harici depolamadaki önbellek

Sık yapılan hatalar

  • Manifest ve getUriForFile() içindeki authority eşleşmemesi → IllegalArgumentException veya erişim reddi.
  • file_paths.xml res/xml/ içinde yok veya meta-data adı eşleşmiyor.
  • FLAG_GRANT_READ_URI_PERMISSION / WRITE unutuldu → alıcıda SecurityException.
  • Uri.fromFile() kullanımı → API ≥ 24 üzerinde FileUriExposedException.
  • Çok geniş root-path → istenmeyen dosyalara rastgele erişim.

Hata ayıklama sırasında logcat'te FileUriExposedException, IllegalArgumentException ve SecurityException arayın — bu durum sorunu hızla gösterir.

SSS

  • Provider için android:exported="true" gerekli mi?
    Hayır — false bırakmak ve erişimi grantUriPermission/Intent bayrakları ile vermek daha iyidir.

  • URI'ye kalıcı erişim verilebilir mi?
    FileProvider için kalıcı persisted izinler genellikle mevcut değildir; uzun süreli erişim için DocumentsProvider ve CONTENT_RESOLVER.takePersistableUriPermission yöntemlerine bakın.

  • Scoped Storage (Android 10+) ile dosyalar nerede saklanmalı?
    getFilesDir(), getCacheDir(), getExternalFilesDir() ve file_paths.xml içindeki ilgili etiketleri kullanın.

İsterseniz, kullanım durumunuz için hazır bir file_paths.xml veya Kotlin üzerinde getShareIntent(File) yardımcı programını hazırlayabilirim.