Aplikasi mogok ketika saya mencoba membuka file. Ini bekerja di bawah Android Nougat, tetapi pada Android Nougat macet. Hanya macet ketika saya mencoba membuka file dari kartu SD, bukan dari partisi sistem. Ada masalah izin?
Kode sampel:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Catatan:
android.os.FileUriExposedException: file: ///storage/emulated/0/test.txt diekspos di luar aplikasi melalui Intent.getData ()
Edit:
Saat menargetkan Android Nougat, file://
URI tidak lagi diizinkan. Kita harus menggunakan content://
URI saja. Namun, aplikasi saya perlu membuka file di direktori root. Ada ide?
android
android-file
android-7.0-nougat
Thomas Vos
sumber
sumber
Jawaban:
Jika Anda
targetSdkVersion >= 24
, maka kita harus menggunakanFileProvider
kelas untuk memberikan akses ke file atau folder tertentu agar dapat diakses oleh aplikasi lain. Kami membuat kelas kami sendiri yang mewarisiFileProvider
untuk memastikan FileProvider kami tidak bertentangan dengan FileProviders yang dideklarasikan dalam dependensi yang diimpor seperti dijelaskan di sini .Langkah-langkah untuk mengganti
file://
URI dengancontent://
URI:Tambahkan perluasan kelas
FileProvider
Tambahkan
<provider>
tag FileProvider diAndroidManifest.xml
bawah<application>
tag. Tentukan otoritas unik untukandroid:authorities
atribut untuk menghindari konflik, dependensi yang diimpor mungkin menentukan${applicationId}.provider
dan otoritas lain yang umum digunakan.provider_paths.xml
file dires/xml
folder. Folder mungkin diperlukan untuk dibuat jika tidak ada. Konten file ditunjukkan di bawah ini. Ini menjelaskan bahwa kami ingin berbagi akses ke Penyimpanan Eksternal di folder root(path=".")
dengan nama external_files .Langkah terakhir adalah mengubah baris kode di bawah
untuk
Sunting: Jika Anda menggunakan maksud untuk membuat sistem membuka file Anda, Anda mungkin perlu menambahkan baris kode berikut:
Silakan merujuk, kode lengkap dan solusinya telah dijelaskan di sini.
sumber
(Build.VERSION.SDK_INT > M)
kondisinya tidak berguna.FileProvider
harus diperluas hanya jika Anda ingin menimpa salah satu perilaku default, jika tidak gunakanandroid:name="android.support.v4.content.FileProvider"
. Lihat developer.android.com/reference/android/support/v4/content/…Selain solusi menggunakan
FileProvider
, ada cara lain untuk mengatasi ini. Sederhananyadi
Application.onCreate()
. Dengan cara ini VM mengabaikanURI
eksposur file .metode
mengaktifkan pemeriksaan eksposur file, yang juga merupakan perilaku default jika kita tidak menyiapkan VmPolicy.
Saya mengalami masalah bahwa jika saya menggunakan
content://
URI
untuk mengirim sesuatu, beberapa aplikasi tidak dapat memahaminya. Dan menurunkantarget SDK
versi tidak diizinkan. Dalam hal ini solusi saya bermanfaat.Memperbarui:
Seperti disebutkan dalam komentar, StrictMode adalah alat diagnostik, dan tidak seharusnya digunakan untuk masalah ini. Ketika saya memposting jawaban ini setahun yang lalu, banyak aplikasi hanya dapat menerima file uris. Mereka hanya crash ketika saya mencoba mengirim uri FileProvider kepada mereka. Ini sudah diperbaiki di sebagian besar aplikasi sekarang, jadi kita harus pergi dengan solusi FileProvider.
sumber
VmPolicy
.StrictMode.enableDefaults();
, yang saya jalankan hanya di build pengembangan saya membuat crash ini tidak terjadi - jadi saya sekarang memiliki aplikasi produksi yang crash tetapi tidak crash ketika dalam pengembangan. Jadi pada dasarnya, mengaktifkan alat diagnostik di sini menyembunyikan masalah serius. Terima kasih @hqzxzwb untuk membantu saya menghilangkan bukti ini.Jika
targetSdkVersion
lebih tinggi dari 24 , maka FileProvider digunakan untuk memberikan akses.Buat file xml (Path: res \ xml) provider_paths.xml
Tambahkan Penyedia di AndroidManifest.xml
Jika Anda menggunakan Androidx , jalur FileProvider seharusnya:
dan ganti
untuk
Sunting: Saat Anda termasuk URI dengan
Intent
pastikan untuk menambahkan baris di bawah ini:dan kamu baik untuk pergi. Semoga ini bisa membantu.
sumber
Jika aplikasi Anda menargetkan API 24+, dan Anda masih ingin / perlu menggunakan file: // intents, Anda dapat menggunakan cara hacky untuk menonaktifkan pemeriksaan runtime:
Metode
StrictMode.disableDeathOnFileUriExposure
disembunyikan dan didokumentasikan sebagai:Masalahnya adalah aplikasi saya tidak lumpuh, tetapi tidak ingin dilumpuhkan dengan menggunakan konten: // maksud yang tidak dipahami oleh banyak aplikasi di luar sana. Misalnya, membuka file mp3 dengan konten: // skema menawarkan aplikasi jauh lebih sedikit daripada saat membuka file over yang sama: // skema. Saya tidak ingin membayar kesalahan desain Google dengan membatasi fungsionalitas aplikasi saya.
Google ingin pengembang menggunakan skema konten, tetapi sistem tidak siap untuk ini, selama bertahun-tahun aplikasi dibuat untuk menggunakan File bukan "konten", file dapat diedit dan disimpan kembali, sementara file yang disajikan di atas skema konten tidak dapat (bisa mereka?).
sumber
ContentResolver
memiliki keduanyaopenInputStream()
danopenOutputStream()
. Cara yang tidak terlalu meretas untuk melakukan ini adalah dengan hanya mengkonfigurasi aturan VM sendiri , dan tidak mengaktifkanfile
Uri
aturan.Jika Anda
targetSdkVersion
berusia 24 tahun atau lebih, Anda tidak dapat menggunakanfile:
Uri
nilai diIntents
perangkat Android 7.0+ .Pilihan Anda adalah:
Drop Anda
targetSdkVersion
ke 23 atau lebih rendah, atauLetakkan konten Anda di penyimpanan internal, lalu gunakan
FileProvider
untuk membuatnya tersedia secara selektif untuk aplikasi lainSebagai contoh:
(dari proyek sampel ini )
sumber
/system
partisi? Setiap aplikasi harus dapat mengakses partisi ini tanpa root./system
bisa dibaca dunia. Yang sedang berkata, saya kira Anda masih akan mendapatkan pengecualian ini. Saya menduga mereka hanya memeriksa skema dan tidak mencoba untuk menentukan apakah file tersebut benar-benar dapat dibaca dunia. Namun,FileProvider
tidak akan membantu Anda, karena Anda tidak dapat mengajarinya untuk melayani/system
. Anda dapat membuat strategi khusus untuk sayaStreamProvider
, atau memutar sendiriContentProvider
, untuk menyelesaikan masalah./data
,/system
), karena "perubahan yang baik" ini.Pertama, Anda perlu menambahkan penyedia ke AndroidManifest Anda
sekarang buat file di folder sumber daya xml (jika menggunakan android studio Anda dapat menekan Alt + Enter setelah menyorot file_paths dan pilih buat opsi sumber daya xml)
Selanjutnya dalam file_paths masukkan file
Contoh ini untuk jalur eksternal yang dapat Anda refere di sini untuk lebih banyak opsi. Ini akan memungkinkan Anda untuk berbagi file yang ada di folder itu dan sub-foldernya.
Sekarang yang tersisa adalah menciptakan maksud sebagai berikut:
EDIT : Saya menambahkan folder root kartu sd di file_paths. Saya telah menguji kode ini dan itu berhasil.
sumber
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
Juga, saya sarankan siapa pun yang mencari jawaban untuk membaca FileProvider terlebih dahulu dan memahami apa yang Anda hadapi di sini dengan izin file di Android N dan di atas. Ada opsi untuk penyimpanan internal vs penyimpanan eksternal dan juga untuk jalur file biasa vs jalur cache.java.lang.IllegalArgumentException: Failed to find configured root ...
dan satu-satunya hal yang berhasil adalah<files-path path="." name="files_root" />
pada file xml bukan<external-path ...
. File saya disimpan di penyimpanan internal.@palash k jawaban sudah benar dan berfungsi untuk file penyimpanan internal, tetapi dalam kasus saya, saya ingin membuka file dari penyimpanan eksternal juga, aplikasi saya macet ketika membuka file dari penyimpanan eksternal seperti sdcard dan usb, tetapi saya berhasil menyelesaikan masalah dengan memodifikasi provider_paths.xml dari jawaban yang diterima
ubah provider_paths.xml seperti di bawah ini
dan di kelas java (Tidak ada perubahan karena jawaban yang diterima hanya edit kecil)
Ini membantu saya untuk memperbaiki crash untuk file dari penyimpanan eksternal, Semoga ini akan membantu seseorang yang memiliki masalah yang sama dengan saya :)
sumber
<root-path
tolong? Bekerja.<external-path path="Android/data/${applicationId}/" name="files_root" />
tidak berpengaruh untuk file terbuka dari penyimpanan eksternal.Android/data/${applicationId}/
di SDcard.Solusi saya adalah 'Uri.parse' Path File sebagai String, alih-alih menggunakan Uri.fromFile ().
Tampaknya fromFile () menggunakan pointer file, yang saya kira bisa jadi tidak aman ketika alamat memori terpapar ke semua aplikasi. Tapi Sebuah path file String tidak pernah menyakiti siapa pun, jadi itu berfungsi tanpa melempar FileUriExposedException.
Diuji pada level API 9 hingga 27! Berhasil membuka file teks untuk diedit di aplikasi lain. Tidak memerlukan FileProvider, atau Pustaka Dukungan Android sama sekali.
sumber
Cukup tempel kode di bawah ini dalam aktivitas onCreate ()
Ini akan mengabaikan paparan URI
sumber
Cukup tempel kode di bawah ini dalam aktivitas
onCreate()
.Ini akan mengabaikan paparan URI.
Selamat coding :-)
sumber
Menggunakan fileProvider adalah caranya. Tetapi Anda dapat menggunakan solusi sederhana ini:
menggantikan:
oleh
sumber
Saya menggunakan jawaban Palash yang diberikan di atas tetapi itu agak tidak lengkap, saya harus memberikan izin seperti ini
sumber
Cukup tempel kode di bawah ini dalam aktivitas onCreate ()
Ini akan mengabaikan paparan URI
sumber
tambahkan dua baris ini di onCreate
Metode berbagi
sumber
Di sini solusi saya:
di Manifest.xml
di res / xml / provider_paths.xml
dalam fragmen saya, saya memiliki kode berikut:
Тhat itu semua yang kamu butuhkan.
Juga tidak perlu dibuat
Saya menguji pada Android 5.0, 6.0 dan Android 9.0 dan ini berhasil.
sumber
Untuk mengunduh pdf dari server, tambahkan kode di bawah ini dalam kelas layanan Anda. Semoga ini bermanfaat bagi Anda.
Dan ya, jangan lupa untuk menambahkan izin dan penyedia di manifes Anda.
sumber
@xml/provider_paths
?Saya tidak tahu mengapa, saya melakukan semuanya persis sama dengan Pkosta ( https://stackoverflow.com/a/38858040 ) tetapi terus mendapatkan kesalahan:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
Saya menghabiskan waktu berjam-jam untuk masalah ini. Pelakunya? Kotlin.
intent
sebenarnya pengaturangetIntent().addFlags
bukannya beroperasi pada playIntent saya yang baru dinyatakan.sumber
saya meletakkan metode ini sehingga jalur imageuri dengan mudah mendapatkan konten.
sumber
Ada 3 langkah utama di sini seperti yang disebutkan di bawah ini
Langkah 1: Manifest Masuk
Langkah 2: Buat file XML res / xml / provider_paths.xml
Langkah 3: Perubahan kode
sumber
Saya tahu ini adalah pertanyaan yang cukup lama tetapi jawaban ini untuk pemirsa di masa depan. Jadi saya mengalami masalah yang sama dan setelah meneliti, saya menemukan alternatif untuk pendekatan ini.
Maksud Anda di sini misalnya: Untuk melihat gambar Anda dari jalur Anda di Kotlin
Fungsi Utama di bawah ini
Demikian juga, alih-alih gambar, Anda dapat menggunakan format file lain seperti pdf dan dalam kasus saya, itu berfungsi dengan baik
sumber
Saya menghabiskan hampir satu hari mencoba mencari tahu mengapa saya mendapatkan pengecualian ini. Setelah banyak perjuangan, konfigurasi ini bekerja dengan sempurna ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Niat itu sendiri
Saya jelaskan seluruh proses di sini .
sumber
https://stackoverflow.com/a/38858040/395097 jawaban ini selesai.
Jawaban ini untuk - Anda sudah memiliki aplikasi yang menargetkan di bawah 24, dan sekarang Anda meningkatkan ke targetSDKVersion> = 24.
Di Android N, hanya file uri yang terpapar ke aplikasi pihak ketiga yang diubah. (Bukan cara kami menggunakannya sebelumnya). Jadi ubah hanya tempat-tempat di mana Anda berbagi jalur dengan aplikasi pihak ke-3 (Kamera dalam kasus saya)
Di aplikasi kami, kami mengirim uri ke aplikasi Kamera, di lokasi itu kami mengharapkan aplikasi kamera untuk menyimpan gambar yang diambil.
Sekarang kami memiliki 2 uri berbeda untuk file yang sama. # 1 dibagikan dengan aplikasi Kamera. Jika niat kamera berhasil, kita dapat mengakses gambar dari # 2.
Semoga ini membantu.
sumber
Xamarin. Android
Catatan: Jalur xml / provider_paths.xml (.axml) tidak dapat diatasi, bahkan setelah membuat folder xml di bawah Sumber Daya (mungkin dapat diletakkan di lokasi yang ada seperti Nilai , tidak mencoba), jadi saya terpaksa ini yang berfungsi untuk saat ini. Pengujian menunjukkan bahwa itu hanya perlu dipanggil sekali per aplikasi dijalankan (yang masuk akal adalah bahwa ia mengubah keadaan operasional VM host).
Catatan: xml perlu dikapitalisasi, jadi Resources / Xml / provider_paths.xml
sumber
@Pkosta menjawab adalah salah satu cara untuk melakukan ini.
Selain menggunakan
FileProvider
, Anda juga dapat memasukkan file keMediaStore
(terutama untuk file gambar dan video), karena file di MediaStore dapat diakses oleh setiap aplikasi:Misalnya, Anda dapat memasukkan file video ke MediaStore seperti ini:
contentUri
seperticontent://media/external/video/media/183473
, yang dapat diteruskan langsung keIntent.putExtra
:Ini bekerja untuk saya, dan menyimpan kerepotan menggunakan
FileProvider
.sumber
Biarkan saja mengabaikan URI Exposure ... Tambahkan setelah di buat
sumber
Coba solusi ini
TETAPKAN IZIN INI DALAM MANIFEST
Niat UNTUK MENANGKAP GAMBAR
DAPATKAN GAMBAR YANG DITAMBAH DALAM HASIL ONACTIVITY
METODE UNTUK MENDAPATKAN GAMBAR URI
sumber
Dalam kasus saya, saya menyingkirkan pengecualian dengan mengganti
SetDataAndType
dengan justSetData
.sumber