Szukam sposobu na poprawne udostępnienie (nie OTWÓRZ) wewnętrznego pliku z zewnętrzną aplikacją za pomocą FileProvider biblioteki Android Support .
Idąc za przykładem w dokumentach,
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.supportv4.my_files"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/my_paths" />
</provider>
i używając ShareCompat do udostępniania pliku innym aplikacjom w następujący sposób:
ShareCompat.IntentBuilder.from(activity)
.setStream(uri) // uri from FileProvider
.setType("text/html")
.getIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
nie działa, ponieważ FLAG_GRANT_READ_URI_PERMISSION udziela tylko pozwolenia na Uri podanego w data
intencji, a nie na wartość EXTRA_STREAM
dodatkowego (jak zostało ustawione przez setStream
).
Próbowałem bezpieczeństwa kompromisowego ustawiając android:exported
się true
do usługodawcy, ale FileProvider
wewnętrznie sprawdza, czy sama jest eksportowany, jeśli tak, to zgłasza wyjątek.
android
android-contentprovider
android-support-library
android-fileprovider
Randy Sugianto „Yuku”
źródło
źródło
Odpowiedzi:
Korzystając
FileProvider
z biblioteki pomocy technicznej, musisz ręcznie przyznać i odwołać uprawnienia (w czasie wykonywania) dla innych aplikacji do odczytu określonego Uri. Użyj metod Context.grantUriPermission i Context.revokeUriPermission .Na przykład:
W ostateczności, jeśli nie możesz podać nazwy pakietu, możesz przyznać uprawnienia wszystkim aplikacjom, które obsługują określone intencje:
Alternatywna metoda wg dokumentacji :
Przy okazji. jeśli potrzebujesz, możesz skopiować źródło FileProvider i zmienić
attachInfo
metodę, aby uniemożliwić dostawcy sprawdzanie, czy jest eksportowany.źródło
grantUriPermission
metody, musimy podać nazwę pakietu aplikacji, do której chcemy udzielić pozwolenia. Jednak podczas udostępniania zwykle nie wiemy, jaka aplikacja jest miejscem docelowym udostępniania.W pełni działający przykład kodu, jak udostępniać plik z wewnętrznego folderu aplikacji. Testowane na Androidzie 7 i Androidzie 5.
AndroidManifest.xml
xml / provider_paths
Sam kod
źródło
ShareCompat.IntentBuilder
i pozwolenie na odczyt URI w końcu zrobiło to za mnie.FileProvider
że działa. W przypadku innych odpowiedzi intencja jest niewłaściwa (nie używają jejShareCompat.IntentBuilder
), a aplikacje zewnętrzne nie mogą jej otworzyć w żaden znaczący sposób. Spędziłem dosłownie większość dnia na tych bzdurach, aż w końcu znalazłem twoją odpowiedź.To rozwiązanie działa dla mnie od wersji OS 4.4. Aby działało na wszystkich urządzeniach, dodałem obejście dla starszych urządzeń. Dzięki temu zawsze stosowane jest najbezpieczniejsze rozwiązanie.
Manifest.xml:
file_paths.xml:
Jawa:
Uprawnienie jest cofane za pomocą revokeFileReadPermission () w metodach onResume i onDestroy () fragmentu lub działania.
źródło
file
nie zmieni się zonResume
naonDestroy
?Ponieważ, jak mówi Phil w swoim komentarzu do pierwotnego pytania, jest to wyjątkowe i nie ma innych informacji na temat SO w Google, pomyślałem, że powinienem również podzielić się moimi wynikami:
W mojej aplikacji FileProvider działał po wyjęciu z pudełka, aby udostępniać pliki przy użyciu zamiaru udostępniania. Nie była wymagana żadna specjalna konfiguracja ani kod, poza tym, aby skonfigurować FileProvider. W moim manifest.xml umieściłem:
W my_paths.xml mam:
W swoim kodzie mam:
Mogę bez problemu udostępniać mój magazyn plików w prywatnej pamięci aplikacji aplikacjom takim jak Gmail i Dysk Google.
źródło
O ile wiem, będzie to działać tylko w nowszych wersjach Androida, więc prawdopodobnie będziesz musiał wymyślić inny sposób, aby to zrobić. To rozwiązanie działa dla mnie w 4.4, ale nie w 4.0 lub 2.3.3, więc nie będzie to przydatny sposób udostępniania treści dla aplikacji, która ma działać na dowolnym urządzeniu z Androidem.
W manifest.xml:
Zwróć szczególną uwagę na sposób określenia uprawnień. Musisz określić działanie, na podstawie którego utworzysz identyfikator URI, i uruchomić zamiar udziału, w tym przypadku działanie to nazywa się SharingActivity. Ten wymóg nie jest oczywisty z dokumentów Google!
file_paths.xml:
Uważaj, jak określasz ścieżkę. Powyższe domyślnie dotyczy katalogu głównego Twojej prywatnej pamięci wewnętrznej.
W SharingActivity.java:
W tym przykładzie udostępniamy obraz JPEG.
Na koniec prawdopodobnie dobrym pomysłem jest upewnienie się, że plik został prawidłowo zapisany i można uzyskać do niego dostęp za pomocą czegoś takiego:
źródło
W mojej aplikacji FileProvider działa dobrze i mogę dołączyć wewnętrzne pliki przechowywane w katalogu plików do klientów poczty e-mail, takich jak Gmail, Yahoo itp.
W moim manifeście, jak wspomniano w dokumentacji Androida, umieściłem:
Ponieważ moje pliki były przechowywane w katalogu głównym plików, pliki filepaths.xml wyglądały następująco:
Teraz w kodzie:
To zadziałało dla mnie, mam nadzieję, że to pomoże :)
źródło
Jeśli otrzymasz obraz z kamery, żadne z tych rozwiązań nie działa w systemie Android 4.4. W takim przypadku lepiej sprawdzić wersje.
źródło
tylko po to, aby poprawić odpowiedź podaną powyżej: jeśli otrzymujesz NullPointerEx:
możesz także użyć getApplicationContext () bez kontekstu
źródło
Chcę udostępnić coś, co blokowało nas na kilka dni: kod dostawcy plików MUSI być wstawiony między znaczniki aplikacji, a nie po nim. Może to trywialne, ale nigdy nie zostało określone i pomyślałem, że mógłbym komuś pomóc! (dzięki jeszcze raz piolo94)
źródło