tło
W systemie Android 4.4 (KitKat) Google ograniczył dostęp do karty SD.
Począwszy od Androida Lollipop (5.0), programiści mogą używać nowego interfejsu API, który prosi użytkownika o potwierdzenie zezwolenia na dostęp do określonych folderów, jak napisano w tym poście w Grupach dyskusyjnych Google .
Problem
Post kieruje do dwóch witryn:
To wygląda jak wewnętrzny przykład (być może zostanie pokazany później w demonstracjach API), ale dość trudno jest zrozumieć, co się dzieje.
To jest oficjalna dokumentacja nowego interfejsu API, ale nie zawiera ona wystarczających informacji o tym, jak z niego korzystać.
Oto, co ci mówi:
Jeśli naprawdę potrzebujesz pełnego dostępu do całego poddrzewa dokumentów, zacznij od uruchomienia ACTION_OPEN_DOCUMENT_TREE, aby umożliwić użytkownikowi wybranie katalogu. Następnie przekaż wynikową metodę getData () do fromTreeUri (Context, Uri), aby rozpocząć pracę z drzewem wybranym przez użytkownika.
Poruszając się po drzewie instancji DocumentFile, zawsze możesz użyć metody getUri (), aby uzyskać Uri reprezentujący dokument bazowy dla tego obiektu, do użycia z openInputStream (Uri) itp.
Aby uprościć kod na urządzeniach z systemem KITKAT lub starszym, możesz użyć fromFile (File), który emuluje zachowanie DocumentsProvider.
Pytania
Mam kilka pytań dotyczących nowego API:
- Jak naprawdę tego używasz?
- Zgodnie z postem system operacyjny zapamięta, że aplikacja otrzymała pozwolenie na dostęp do plików / folderów. Jak sprawdzić, czy masz dostęp do plików / folderów? Czy jest funkcja, która zwraca mi listę plików / folderów, do których mam dostęp?
- Jak radzisz sobie z tym problemem na KitKacie? Czy jest to część biblioteki wsparcia?
- Czy w systemie operacyjnym jest ekran ustawień, który pokazuje, które aplikacje mają dostęp do jakich plików / folderów?
- Co się stanie, jeśli aplikacja zostanie zainstalowana dla wielu użytkowników na tym samym urządzeniu?
- Czy jest jakaś inna dokumentacja / samouczek na temat tego nowego interfejsu API?
- Czy uprawnienia można cofnąć? Jeśli tak, czy istnieje zamiar, który jest wysyłany do aplikacji?
- Czy pytanie o pozwolenie działałoby rekurencyjnie w wybranym folderze?
- Czy użycie pozwolenia pozwoliłoby również użytkownikowi na wielokrotny wybór na podstawie jego wyboru? A może aplikacja musi wyraźnie informować intencję, które pliki / foldery mają zezwolić?
- Czy istnieje sposób na emulator, aby wypróbować nowy interfejs API? Mam na myśli, że ma partycję na kartę SD, ale działa jako główna pamięć zewnętrzna, więc cały dostęp do niej jest już udzielony (za pomocą prostego pozwolenia).
- Co się stanie, gdy użytkownik wymieni kartę SD na inną?
źródło
Odpowiedzi:
Wiele dobrych pytań, zagłębmy się. :)
Jak tego używasz?
Oto świetny samouczek dotyczący interakcji z platformą dostępu do magazynu w KitKat:
https://developer.android.com/guide/topics/providers/document-provider.html#client
Interakcja z nowymi interfejsami API w Lollipop jest bardzo podobna. Aby zachęcić użytkownika do wybrania drzewa katalogów, możesz uruchomić następującą intencję:
Następnie w swojej onActivityResult () możesz przekazać wybrany przez użytkownika Uri do nowej klasy pomocnika DocumentFile. Oto krótki przykład, który wyświetla listę plików w wybranym katalogu, a następnie tworzy nowy plik:
Zwracany identyfikator Uri
DocumentFile.getUri()
jest wystarczająco elastyczny, aby można go było używać z różnymi interfejsami API platformy. Na przykład możesz udostępnić go zaIntent.setData()
pomocąIntent.FLAG_GRANT_READ_URI_PERMISSION
.Jeśli chcesz uzyskać dostęp do tego Uri z kodu natywnego, możesz wywołać,
ContentResolver.openFileDescriptor()
a następnie użyćParcelFileDescriptor.getFd()
lub,detachFd()
aby uzyskać tradycyjną liczbę całkowitą deskryptora pliku POSIX.Jak sprawdzić, czy masz dostęp do plików / folderów?
Domyślnie Uris zwrócone przez intencje Storage Access Framework nie są utrwalane po ponownym uruchomieniu. Platforma „oferuje” możliwość utrwalenia pozwolenia, ale nadal musisz „odebrać” pozwolenie, jeśli chcesz. W naszym przykładzie powyżej zadzwoniłbyś:
Zawsze możesz dowiedzieć się, do czego utrzymywana aplikacja ma dostęp za pośrednictwem
ContentResolver.getPersistedUriPermissions()
interfejsu API. Jeśli nie potrzebujesz już dostępu do utrwalonego Uri, możesz go zwolnić za pomocąContentResolver.releasePersistableUriPermission()
.Czy to jest dostępne na KitKat?
Nie, nie możemy wstecznie dodawać nowych funkcji do starszych wersji platformy.
Czy mogę zobaczyć, które aplikacje mają dostęp do plików / folderów?
Obecnie nie ma interfejsu użytkownika, który to pokazuje, ale szczegóły można znaleźć w sekcji „Udzielone uprawnienia Uri” danych
adb shell dumpsys activity providers
wyjściowych.Co się stanie, jeśli aplikacja zostanie zainstalowana dla wielu użytkowników na tym samym urządzeniu?
Przyznania uprawnień Uri są izolowane dla poszczególnych użytkowników, podobnie jak wszystkie inne funkcje platformy dla wielu użytkowników. Oznacza to, że ta sama aplikacja działająca w ramach dwóch różnych użytkowników nie ma nakładających się ani współdzielonych uprawnień Uri.
Czy uprawnienia można cofnąć?
Wspierający DocumentProvider może odwołać uprawnienia w dowolnym momencie, na przykład w przypadku usunięcia dokumentu w chmurze. Najczęstszym sposobem na wykrycie tych odwołanych uprawnień jest ich zniknięcie z
ContentResolver.getPersistedUriPermissions()
wymienionych powyżej.Uprawnienia są również odwoływane za każdym razem, gdy dane aplikacji są czyszczone dla dowolnej aplikacji uczestniczącej w przyznaniu.
Czy pytanie o pozwolenie działałoby rekurencyjnie w wybranym folderze?
Tak,
ACTION_OPEN_DOCUMENT_TREE
intencja zapewnia rekurencyjny dostęp zarówno do istniejących, jak i nowo utworzonych plików i katalogów.Czy to pozwala na wielokrotny wybór?
Tak, wielokrotny wybór jest obsługiwany od KitKat i możesz na to zezwolić, ustawiając je
EXTRA_ALLOW_MULTIPLE
podczas rozpoczynaniaACTION_OPEN_DOCUMENT
zamiaru. Możesz użyćIntent.setType()
lub,EXTRA_MIME_TYPES
aby zawęzić typy plików, które można wybrać:http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT
Czy istnieje sposób na emulator, aby wypróbować nowy interfejs API?
Tak, podstawowe współdzielone urządzenie magazynujące powinno pojawić się w selektorze, nawet w emulatorze. Jeśli tylko Twoja aplikacja korzysta z dostępu do pamięci ram dostępu do pamięci współdzielonej, które nie są już potrzebne
READ/WRITE_EXTERNAL_STORAGE
uprawnienia na wszystkich i można je usunąć lub skorzystać zandroid:maxSdkVersion
funkcji, aby tylko zwrócić je w starszych wersjach platformy.Co się stanie, gdy użytkownik wymieni kartę SD na inną?
W przypadku nośnika fizycznego identyfikator UUID (taki jak numer seryjny FAT) nośnika podstawowego jest zawsze zapisywany w zwracanym identyfikatorze Uri. System wykorzystuje to, aby połączyć Cię z nośnikiem wybranym przez użytkownika, nawet jeśli użytkownik zamienia nośnik między wieloma gniazdami.
Jeśli użytkownik wymieni drugą kartę, musisz poprosić o dostęp do nowej karty. Ponieważ system zapamiętuje przyznane granty na podstawie identyfikatora UUID, nadal będziesz mieć wcześniej przyznany dostęp do oryginalnej karty, jeśli użytkownik włoży ją ponownie później.
http://en.wikipedia.org/wiki/Volume_serial_number
źródło
W moim projekcie na Androida na Githubie, do którego link znajdziesz poniżej, możesz znaleźć działający kod, który pozwala pisać na extSdCard w systemie Android 5. Zakłada on, że użytkownik daje dostęp do całej karty SD, a następnie pozwala pisać wszędzie na tej karcie. (Jeśli chcesz mieć dostęp tylko do pojedynczych plików, wszystko staje się łatwiejsze).
Główne fragmenty kodu
Wyzwalanie struktury dostępu do magazynu:
Obsługa odpowiedzi z Storage Access Framework:
Pobieranie strumienia wyjściowego dla pliku za pośrednictwem Storage Access Framework (przy użyciu przechowywanego adresu URL, zakładając, że jest to adres URL folderu głównego zewnętrznej karty SD)
Używa to następujących metod pomocniczych:
Odniesienie do pełnego kodu
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/fragments/SettingsFragment.java#L521
i
https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java
źródło
File
254 razy. Czy możesz sobie wyobrazić naprawienie tego? Android staje się koszmarem dla deweloperów z powodu całkowitego braku wstecznej kompatybilności. Nadal nie znalazłem miejsca, w którym wyjaśnią, dlaczego Google podjął te wszystkie głupie decyzje dotyczące pamięci zewnętrznej. Niektórzy twierdzą, że „bezpieczeństwo”, ale oczywiście jest to nonsensowne, ponieważ każda aplikacja może zepsuć pamięć wewnętrzną. Domyślam się, że spróbujemy zmusić nas do korzystania z ich usług w chmurze. Na szczęście rootowanie rozwiązuje problemy ... przynajmniej dla Androida <6 ....To tylko uzupełniająca odpowiedź.
Po utworzeniu nowego pliku może być konieczne zapisanie jego lokalizacji w bazie danych i przeczytanie go jutro. Możesz przeczytać odzyskać go ponownie za pomocą tej metody:
źródło