5992052687_5fb63cb687_b

Продолжение.

Что пользователи думают про «съемное хранилище» ?

У многих ваших пользователей будет устройство, имеющее какие-то съемные носители. Часто это микро SD-карта. Некоторые планшеты или доки имеют full слот для SD-карт. Кроме того, USB-накопитель можно использовать через USB-разъемы On-The-Go и USB Type C (не говоря уже о устройствах или доках с полным USB-портом). Ваши пользователи будут думать, что они могут работать со съемным хранилищем, как они это делают на настольном ПК или ноутбуке. К сожалению, пользователи в основном ошибаются и даже больше ошибаются в Android 4.4+. Это потому, что подход Google к съемному хранилищу … нетрадиционный.

 

Как Google понимает «съемное хранилище» ?

Как  я уже говорил, внешнее хранилище часто было в виде съемной микро SD-карты. В то время многие разработчики привыкли думать, что внешнее хранилище == съемное хранилище. Однако, когда Android 3.0 и выше начали массово развертываться, разработчики вскоре начали понимать две вещи:

  • Внешнее хранилище != Съемное хранилище на большинстве этих устройств
  • В Android SDK ничего нет о съемном хранилище

 

Лолшто?

Всё правильно: до Android 4.4 официальная поддержка съемных носителей в Android не производилась.

Цитата Dianne Hackborn:

… имейте в виду: до Android 4.4 официальная платформа Android не поддерживала SD-карты вообще, за исключением двух особых случаев: old school storage , где внешнее хранилище является SD-картой (которая по-прежнему поддерживается платформой сегодня) и небольшая функция, добавленная в Android 3.0, где он будет сканировать дополнительные SD-карты и добавлять их к медиа-провайдеру и предоставлять приложениям доступ только для чтения к своим файлам (который также поддерживается на платформе сегодня).

Android 4.4 — это первая версия платформы, которая фактически позволила приложениям использовать SD-карты для хранения. Любой доступ к ним до этого был через частные, неподдерживаемые API. Теперь у нас есть довольно богатый API на платформе, который позволяет приложениям использовать SD-карты поддерживаемым образом, лучшими способами, чем это было раньше: они могут свободно использовать свою область хранения приложений, не требуя каких-либо разрешений в приложении и может получить доступ к любым другим файлам на SD-карте, если они проходят через файл пикер, без каких-либо специальных разрешений.

 

Но … Но … Но … Что обо всех этих приложениях, которые используют съемные носители?

Они попадают в три группы:

  • Некоторые просто полагаются на индексацию MediaStore. Так, например, видеопроигрыватель может узнать о видео на всех доступных носителях, запросив MediaStore, и если производитель устройства не нарушил индексацию MediaStore сменных носителей, плеер сможет воспроизводить видео на съемных носителях ,
  • Некоторые из них — приложения, которые поставляются с оборудованием. Производитель оборудования знает устройство и правила игры для этого устройства. Производитель оборудования также гораздо меньше обеспокоен совместимостью между устройствами, так как их приложения обычно не поставляются в Play Маркете. Следовательно, производитель оборудования имеет карт-бланш для работы со съемными носителями.
  • Некоторые из них — приложения, написанные разработчиками, которые решили выйти за границы Android SDK. Существуют различные рецепты онлайн для изучения различных системных файлов Linux (и файлов-подобных субстанций), чтобы определить, какие «точки монтирования» существуют, и оттуда применяют некоторые эвристики для определения того, что представляет собой съемные носители. В то время как надежность на всех устройствах может быть легко проблемой, кроме того, эти техники  работали … до Android 4.4, когда все изменилось.

 

Читать ещё :   Использование Optional в Android сегодня

Что произошло в Android 4.4: хорошие новости

В Android 4.4 произошли две вещи, которые влияют на съемные носители.

С положительной стороны, мы получили определенную меру официальной поддержки Android SDK для съемных носителей. В частности, getExternalFilesDirs() и getExternalCacheDirs() (обратите внимание на множественную форму) будут не только возвращать каталоги, которые мы можем использовать на «реальном» внешнем хранилище, но и возвращать каталоги, которые мы можем использовать на любом доступном и поддерживаемом съемном носителе. Наши приложения не нуждаются в каких-либо конкретных разрешениях для использования каких-либо из этих каталогов.

Кроме того, Storage Access Framework предоставляет разработчикам устройств некоторые опции для более удобного отображения съемных носителей в наших приложениях. Цитата Jeff Sharkey:

Тем не менее, приложения могут создавать / записывать файлы за пределами своих каталогов конкретных пакетов на вторичных внешних устройствах хранения, используя новый намерение CREATE_DOCUMENT, которое включает пользователя в процесс создания файла.

 

Что произошло в Android 4.4: страшно-запутанные новости

Начиная с Android 4.2, у разработчиков устройств был запрос на блокировку съемных носителей. Как правило, это игнорировалось.

В Android 4.4+ компания Google внесла поправки в комплект тестирования совместимости (CTS), который должен выполнить производитель устройств, чтобы выпустить устройство, содержащее собственные приложения Google (например, Play Store, Карты, Gmail, иначе известный как «GMS»).

Процитируем Dave Smith :

Тем не менее, новые тесты были добавлены в CTS для 4.4, которые подтверждают, имеет ли вторичное хранилище правильные разрешения только для чтения в каталогах, не относящихся к конкретным приложениям, по-видимому, из-за новых API, чтобы, наконец, показать эти пути для разработчиков приложений. Как только CTS включит в себя эти правила, OEM-производители должны поддерживать их, чтобы поддерживать устройства доставки с GMS (Google Play и т. Д.) на борту.

В результате приложения могут читать файлы на съемных носителях, используя различные недокументированные и неподдерживаемые трюки для поиска сменных носителей. Однако приложения не могут писать или иным образом модифицировать такое съемное хранилище. Обратите внимание, что у самих производителей устройств могут быть способы борьбы с этим, но обычные разработчики приложений этого не делают.

Google Group android-platform была домом для довольно эпической дискуссии по поводу решения Google здесь, в том числе записи Dianne Hackborn, процитированной ранее в этом посте.

Несмотря на выкручивание рук, я не ожидаю, что Google поддержит эту проблему. На каждого пользователя, который жалуется на то, что Android 4.4+ делает их карту micro SD бесполезной, есть эксперт, жалующийся на то, как Android позволяет любому приложению запускать amok и читать вещи из памяти, повышая проблемы конфиденциальность и безопасности. На самом деле, я бы ничуть не удивился, если в будущем доступ к доступу к съемным носителям будет заблокирован, за пределами собственного каталога приложения на этом носителе.

 

Где я могу узнать больше?

Два из лучших ресурсов для этой темы — те, которые я проциттировал ранее в этом посте:

 

Читать ещё :   Android External Storage

Хорошо, что мы можем сделать?

 

В идеале используйте Storage Access Framework :

  • ACTION_OPEN_DOCUMENT (сродни устаревшему системному файл-open диалогу)
  • ACTION_OPEN_DOCUMENT_TREE (аналогично устаревшему диалогу открытия системного каталога)
  • ACTION_CREATE_DOCUMENT (сродни устаревшему диалогу “сохранить как”)

В Android 7.0+ вы также можете использовать StorageVolume для запроса доступа к определенным деревьям каталогов на съемном носителе.

Все это возвращает Uri, представляя документ или дерево документов. Вы должны использовать их с такими вещами, как DocumentFile и ContentResolver, для работы с контентом (или деревом контента).

Большим преимуществом такого подхода является то, что ваш код теперь не зависит от  хранилище. Тот же код будет работать с:

  • Внешним хранилищем
  • Съемным хранилищем
  • Гугл Диском
  • Сетевым файловым сервером Samba / CIFS (если у пользователя есть соответствующее приложение)
  • Все остальное, предоставляемое сторонним поставщиком документов

Хотя ваш код будет несколько иным, чем при использовании java.io.File, но это не настолько отлично :

  • Вы все еще используете InputStream и OutputStream для чтения и записи контента, но вы получаете их из ContentResolver (например, openInputStream()), а не из FileInputStream и FileOutputStream
  • Вы по-прежнему можете перемещать деревья документов, но вы делаете это с помощью DocumentFile, а не File.

Самое большое различие заключается в том, что вы больше не должны предполагать, что имеется значимое имя файла, используя DocumentFile, чтобы получить «отображаемое имя» (display name), чтобы показать пользователю.

Некоторые типы приложений, например медиаплееры, могут быть лучше использованы с использованием MediaStore и полностью игнорируют файловую систему. Мало того, что вы можете запросить MediaStore, чтобы узнать доступный носитель информации, но вы можете создать MediaStore Uri, из которого MediaStore передаст вам контент, даже для контента, доступа к которому вы, возможно, не имеете.

 

Но это не подходит к моему UI

Из того, что я видел, источник жалобы №1 о «потерянном» съемном хранилище поступает от разработчиков файловых менеджеров. Их аргумент заключается в том, что они должны иметь возможность перечислять все источники файлов и перемещаться по ним.

Это просто не работает в Android. С некоторыми изменениями в UX вы можете получить то, что намного более Android-friendly.

Например, вместо того, чтобы считать ваше приложение «источником правды» для дерева документов, дайте пользователю сделать это в виде системы «закладок». Ваше приложение будет иметь предварительно настроенную закладку для внешнего хранилища. Если пользователь добавляет элемент панели действий (или что-то еще) для добавления новой закладки, вы используете ACTION_OPEN_DOCUMENT_TREE и позволяете им выбирать дерево из того, что они хотят. Вы получаете постоянные разрешения (permissions) на Uri, на которые вы вернетесь, а затем сохраните Uri как часть ваших данных приложения (например, в базе данных). Затем вы используете DocumentFile для обхода дерева документов для показа в пользовательском интерфейсе.

С помощью этого подхода вы лучше подойдете к Android, используя Storage Access Framework. Вы предлагаете пользователям больше функциональности, так как теперь ваш «файловый менеджер» может управлять контентом из разных мест, включая вещи, которые не являются локальными файлами. Подобные подходы можно использовать для других типов приложений, переключаясь с метафоры «файл» на метафору «контент» и используя Storage Access Framework.