Udostępnij za pośrednictwem


Magazyn zewnętrzny

Magazyn zewnętrzny odnosi się do magazynu plików, który nie znajduje się w magazynie wewnętrznym i nie jest dostępny wyłącznie dla aplikacji odpowiedzialnej za ten plik. Głównym celem magazynu zewnętrznego jest zapewnienie miejsca do umieszczania plików, które mają być udostępniane między aplikacjami lub które są zbyt duże, aby zmieścić się w magazynie wewnętrznym.

W przeszłości magazyn zewnętrzny odnosił się do partycji dysku na nośnikach wymiennych, takich jak karta SD (była również nazywana magazynem przenośnym). To rozróżnienie nie jest już tak istotne, jak urządzenia z systemem Android ewoluowały, a wiele urządzeń z systemem Android nie obsługuje już magazynu wymiennego. Zamiast tego niektóre urządzenia przydzielą część wewnętrznej pamięci nietrwałej do systemu Android, która może wykonywać tę samą funkcję co nośniki wymienne. Jest to nazywane emulowanym magazynem i nadal jest uważane za magazyn zewnętrzny. Alternatywnie niektóre urządzenia z systemem Android mogą mieć wiele zewnętrznych partycji magazynu. Na przykład tablet z systemem Android (oprócz magazynu wewnętrznego) mógł emulować magazyn i co najmniej jedno gniazdo dla karty SD. Wszystkie te partycje są traktowane przez system Android jako magazyn zewnętrzny.

Na urządzeniach, które mają wielu użytkowników, każdy użytkownik będzie miał dedykowany katalog na podstawowej partycji magazynu zewnętrznego dla ich magazynu zewnętrznego. Aplikacje uruchomione jako jeden użytkownik nie będą miały dostępu do plików od innego użytkownika na urządzeniu. Pliki dla wszystkich użytkowników są nadal czytelne dla świata i zapisywalne na świecie; Jednak system Android będzie piaskownicą każdego profilu użytkownika z innych.

Odczytywanie i zapisywanie w plikach jest prawie identyczne w środowisku Xamarin.Android, podobnie jak w przypadku dowolnej innej aplikacji .NET. Aplikacja Xamarin.Android określa ścieżkę do pliku, który będzie manipulowany, a następnie używa standardowych idiomów platformy .NET na potrzeby dostępu do plików. Ponieważ rzeczywiste ścieżki do magazynu wewnętrznego i zewnętrznego mogą się różnić w zależności od urządzenia do urządzenia lub wersji systemu Android do wersji systemu Android, nie zaleca się kodowania ścieżki do plików. Zamiast tego platforma Xamarin.Android uwidacznia natywne interfejsy API systemu Android, które pomogą określić ścieżkę do plików w magazynie wewnętrznym i zewnętrznym.

W tym przewodniku omówiono pojęcia i interfejsy API w systemie Android specyficzne dla magazynu zewnętrznego.

Publiczne i prywatne pliki w magazynie zewnętrznym

Istnieją dwa różne typy plików, które aplikacja może przechowywać w magazynie zewnętrznym:

  • Pliki prywatne — pliki prywatne są plikami specyficznymi dla aplikacji (ale nadal można je odczytywać i zapisywać na świecie). System Android oczekuje, że pliki prywatne są przechowywane w określonym katalogu w magazynie zewnętrznym. Mimo że pliki są nazywane "prywatnymi", są one nadal widoczne i dostępne dla innych aplikacji na urządzeniu, nie są one objęte żadną specjalną ochroną przez system Android.

  • Pliki publiczne — są to pliki, które nie są uważane za specyficzne dla aplikacji i mają być swobodnie udostępniane.

Różnice między tymi plikami są przede wszystkim koncepcyjne. Pliki prywatne są prywatne w tym sensie, że są uważane za część aplikacji, podczas gdy pliki publiczne są wszelkimi innymi plikami, które istnieją w magazynie zewnętrznym. System Android udostępnia dwa różne interfejsy API do rozpoznawania ścieżek do plików prywatnych i publicznych, ale w przeciwnym razie te same interfejsy API platformy .NET są używane do odczytywania i zapisywania w tych plikach. Są to te same interfejsy API, które zostały omówione w sekcji dotyczącej czytania i pisania.

Prywatne pliki zewnętrzne

Prywatne pliki zewnętrzne są uważane za specyficzne dla aplikacji (podobnej do plików wewnętrznych), ale są przechowywane w magazynie zewnętrznym z dowolnej liczby powodów (takich jak zbyt duże dla magazynu wewnętrznego). Podobnie jak pliki wewnętrzne, te pliki zostaną usunięte po odinstalowaniu aplikacji przez użytkownika.

Lokalizacja podstawowa prywatnych plików zewnętrznych jest znaleziona przez wywołanie metody Android.Content.Context.GetExternalFilesDir(string type). Ta metoda zwróci Java.IO.File obiekt reprezentujący prywatny katalog magazynu zewnętrznego dla aplikacji. Przekazanie null do tej metody spowoduje zwrócenie ścieżki do katalogu magazynu użytkownika dla aplikacji. Na przykład w przypadku aplikacji o nazwie com.companyname.apppakietu katalog "root" prywatnych plików zewnętrznych będzie następujący:

/storage/emulated/0/Android/data/com.companyname.app/files/

Ten dokument będzie odwoływać się do katalogu magazynu dla plików prywatnych w magazynie zewnętrznym jako PRIVATE_EXTERNAL_STORAGE.

Parametr dla GetExternalFilesDir() jest ciągiem określającym katalog aplikacji. Jest to katalog przeznaczony do zapewnienia standardowej lokalizacji dla logicznej organizacji plików. Wartości ciągu są dostępne za pośrednictwem stałych w Android.OS.Environment klasie:

Android.OS.Environment Katalog
KatalogAlarms PRIVATE_EXTERNAL_STORAGE/alarmy
DirectoryDcim PRIVATE_EXTERNAL_STORAGE/DCIM
DirectoryDownloads PRIVATE_EXTERNAL_STORAGE/pobierz
DirectoryDocuments PRIVATE_EXTERNAL_STORAGE/Dokumenty
DirectoryFilmy PRIVATE_EXTERNAL_STORAGE/filmy
KatalogMusic PRIVATE_EXTERNAL_STORAGE/Muzyka
DirectoryNotifications PRIVATE_EXTERNAL_STORAGE/powiadomienia
KatalogPodcasts PRIVATE_EXTERNAL_STORAGE/Podcasty
DirectoryRingtones PRIVATE_EXTERNAL_STORAGE/dzwonki
DirectoryPictures PRIVATE_EXTERNAL_STORAGE/Zdjęcia

W przypadku urządzeń z wieloma partycjami magazynu zewnętrznego każda partycja będzie mieć katalog przeznaczony dla plików prywatnych. Metoda Android.Content.Context.GetExternalFilesDirs(string type) zwróci tablicę Java.IO.Files. Każdy obiekt będzie reprezentować katalog specyficzny dla aplikacji prywatnej na wszystkich udostępnionych/zewnętrznych urządzeniach magazynujących, na których aplikacja może umieścić pliki, których jest właścicielem.

Ważne

Dokładna ścieżka do prywatnego katalogu magazynu zewnętrznego może się różnić od urządzenia do urządzenia i między wersjami systemu Android. W związku z tym aplikacje nie mogą trwale kodować ścieżki do tego katalogu, a zamiast tego używają interfejsów API platformy Xamarin.Android, takich jak Android.Content.Context.GetExternalFilesDir().

Publiczne pliki zewnętrzne

Pliki publiczne to pliki, które istnieją w magazynie zewnętrznym, które nie są przechowywane w katalogu, który system Android przydziela dla plików prywatnych. Pliki publiczne nie zostaną usunięte po odinstalowaniu aplikacji. Aplikacje systemu Android muszą mieć uprawnienia, zanim będą mogły odczytywać lub zapisywać dowolne pliki publiczne. Istnieje możliwość, że pliki publiczne istnieją w dowolnym miejscu w magazynie zewnętrznym, ale zgodnie z konwencją system Android oczekuje, że pliki publiczne istnieją w katalogu zidentyfikowanym przez właściwość Android.OS.Environment.ExternalStorageDirectory. Ta właściwość zwróci Java.IO.File obiekt reprezentujący podstawowy katalog magazynu zewnętrznego. Na przykład Android.OS.Environment.ExternalStorageDirectory może się odwoływać do następującego katalogu:

/storage/emulated/0/

Ten dokument będzie odwoływać się do katalogu magazynu dla plików publicznych w magazynie zewnętrznym jako PUBLIC_EXTERNAL_STORAGE.

System Android obsługuje również koncepcję katalogów aplikacji w PUBLIC_EXTERNAL_STORAGE. Te katalogi są dokładnie takie same jak katalogi aplikacji i PRIVATE_EXTERNAL_STORAGE są opisane w tabeli w poprzedniej sekcji. Metoda Android.OS.Environment.GetExternalStoragePublicDirectory(string directoryType) zwróci Java.IO.File obiekt odpowiadający katalogowi aplikacji publicznej. Parametr directoryType jest obowiązkowym parametrem i nie może być null.

Na przykład wywołanie Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDocuments).AbsolutePath zwróci ciąg podobny do następującego:

/storage/emulated/0/Documents

Ważne

Dokładna ścieżka do publicznego katalogu magazynu zewnętrznego może się różnić od urządzenia do urządzenia i między wersjami systemu Android. W związku z tym aplikacje nie mogą trwale kodować ścieżki do tego katalogu, a zamiast tego używają interfejsów API platformy Xamarin.Android, takich jak Android.OS.Environment.ExternalStorageDirectory.

Praca z magazynem zewnętrznym

Gdy aplikacja platformy Xamarin.Android uzyska pełną ścieżkę do pliku, powinna korzystać z dowolnych standardowych interfejsów API platformy .NET do tworzenia, odczytywania, zapisywania lub usuwania plików. Pozwala to zmaksymalizować ilość kodu zgodnego z wieloma platformami dla aplikacji. Jednak przed podjęciem próby uzyskania dostępu do pliku aplikacja Xamarin.Android musi upewnić się, że jest możliwe uzyskanie dostępu do tego pliku.

  1. Zweryfikuj magazyn zewnętrzny — w zależności od charakteru magazynu zewnętrznego możliwe jest, że nie można go montować i używać przez aplikację. Przed podjęciem próby użycia wszystkich aplikacji należy sprawdzić stan magazynu zewnętrznego.
  2. Sprawdzanie uprawnień środowiska uruchomieniowego — aplikacja systemu Android musi zażądać uprawnień od użytkownika w celu uzyskania dostępu do magazynu zewnętrznego. Oznacza to, że należy wykonać żądanie uprawnień w czasie wykonywania przed dowolnym dostępem do pliku. Przewodnik Uprawnienia na platformie Xamarin.Android zawiera więcej szczegółów na temat uprawnień systemu Android.

Każde z tych dwóch zadań zostanie omówione poniżej.

Sprawdzanie, czy magazyn zewnętrzny jest dostępny

Pierwszym krokiem przed zapisaniem w magazynie zewnętrznym jest sprawdzenie, czy jest możliwe do odczytu lub zapisu. Właściwość Android.OS.Environment.ExternalStorageState zawiera ciąg identyfikujący stan magazynu zewnętrznego. Ta właściwość zwróci ciąg reprezentujący stan. Ta tabela jest listą ExternalStorageState wartości, które mogą być zwracane przez :Environment.ExternalStorageState

ExternalStorageState opis
MediaBadRemoval Nośnik został nagle usunięty bez prawidłowego odłączenia.
Sprawdzanie multimediów Nośnik jest obecny, ale przechodzi kontrolę dysku.
MediaEjecting Nośnik jest w trakcie instalacji i wyrzucenia.
Zainstalowane nośniki Nośnik jest zainstalowany i może być odczytywany lub zapisywany.
MediaMountedReadOnly Nośnik jest zainstalowany, ale można go odczytywać tylko z.
MediaNofs Nośnik jest obecny, ale nie zawiera systemu plików odpowiedniego dla systemu Android.
MediaRemoved Brak mediów.
MediaShared Nośnik jest obecny, ale nie jest zainstalowany. Jest on udostępniany za pośrednictwem portu USB z innym urządzeniem.
MediaUnknown Stan mediów jest nierozpoznany przez system Android.
MediaUnmountable Nośnik jest obecny, ale nie może być zainstalowany przez system Android.
MediaUnmounted Nośnik jest obecny, ale nie jest zainstalowany.

Większość aplikacji systemu Android będzie musiała sprawdzić tylko, czy jest zainstalowany magazyn zewnętrzny. Poniższy fragment kodu pokazuje, jak sprawdzić, czy magazyn zewnętrzny jest zainstalowany na potrzeby dostępu tylko do odczytu lub dostępu do odczytu i zapisu:

bool isReadonly = Environment.MediaMountedReadOnly.Equals(Environment.ExternalStorageState);
bool isWriteable = Environment.MediaMounted.Equals(Environment.ExternalStorageState);

Uprawnienia magazynu zewnętrznego

System Android uważa, że dostęp do magazynu zewnętrznego jest niebezpiecznym uprawnieniem, które zazwyczaj wymaga od użytkownika udzielenia uprawnień dostępu do zasobu. Użytkownik może w dowolnym momencie odwołać to uprawnienie. Oznacza to, że należy wykonać żądanie uprawnień w czasie wykonywania przed dowolnym dostępem do pliku. Aplikacje są automatycznie przyznawane uprawnienia do odczytywania i zapisywania własnych plików prywatnych. Aplikacje mogą odczytywać i zapisywać pliki prywatne należące do innych aplikacji po udzieleniu użytkownikowi uprawnień .

Wszystkie aplikacje systemu Android muszą zadeklarować jedno z dwóch uprawnień do magazynu zewnętrznego w AndroidManifest.xml . Aby zidentyfikować uprawnienia, należy dodać jeden z następujących dwóch uses-permission elementów, aby AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Uwaga

Jeśli użytkownik przyznaje WRITE_EXTERNAL_STORAGEelement , READ_EXTERNAL_STORAGE jest również niejawnie udzielany. Nie jest konieczne zażądanie obu uprawnień w AndroidManifest.xml.

Uprawnienia można również dodać przy użyciu karty Manifest systemu Android we właściwościach rozwiązania:

Solution Explorer - Required Permissions for Visual Studio

Ogólnie rzecz biorąc, wszystkie niebezpieczne uprawnienia muszą być zatwierdzone przez użytkownika. Uprawnienia do magazynu zewnętrznego są anomalią w tym, że istnieją wyjątki od tej reguły, w zależności od wersji systemu Android uruchomionej przez aplikację:

Flowchart of external storage permission checks

Aby uzyskać więcej informacji na temat wykonywania żądań uprawnień środowiska uruchomieniowego, zapoznaj się z przewodnikiem Uprawnienia na platformie Xamarin.Android. Monodroid-sample LocalFiles demonstruje również jeden ze sposobów przeprowadzania kontroli uprawnień środowiska uruchomieniowego.

Udzielanie i odwołowanie uprawnień za pomocą usługi ADB

W trakcie tworzenia aplikacji dla systemu Android może być konieczne przyznanie i odwołanie uprawnień do testowania różnych przepływów pracy związanych z kontrolą uprawnień środowiska uruchomieniowego. Można to zrobić w wierszu polecenia przy użyciu usługi ADB. Poniższe fragmenty kodu wiersza polecenia pokazują, jak udzielić lub odwołać uprawnienia przy użyciu usługi ADB dla aplikacji systemu Android, której nazwa pakietu jest com.companyname.app:

$ adb shell pm grant com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE

$ adb shell pm revoke com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE

Usuwanie plików

Dowolny ze standardowych interfejsów API języka C# może służyć do usuwania pliku z magazynu zewnętrznego, takiego jak System.IO.File.Delete. Istnieje również możliwość korzystania z interfejsów API języka Java kosztem przenośności kodu. Na przykład:

System.IO.File.Delete("/storage/emulated/0/Android/data/com.companyname.app/files/count.txt");