Я работал над Fedora Android App, в качестве своего проекта GSoC. Одна из наших основных целей - сделать приложение Fedora доступным для работы в автономном режиме. За время существования приложения мы делаем несколько вызовов API и загружаем несколько ресурсов из разных источников. Кэширование ответов API (которые были в JSON) было несложным, однако изображения были совершенно другой проблемой.

Проблема

Мы показываем несколько изображений в карусели заголовков. Мы получаем изображения из статей, размещенных в разделе Новое в Fedora журнала Fedora ». Мы хотим кэшировать изображения и сделать их доступными, даже если пользователь не в сети.

Ограничения

  1. Мы должны поддерживать Android 4.4 (Chrome 33). Его совместимость с современным ES6 аналогична уровням IE 11.
  2. Нам нужно кэшировать изображения из внешних сервисов, которые не поддерживают CORS.

Возможные решения

Сервисные работники

В прогрессивных веб-приложениях кеширование почти всегда реализуется с помощью Service Workers. Однако Кордова не поддерживает сервисных работников.

Получение в режиме «без корки» и CacheStorage API

Новые Fetch и CacheStorage API используют преимущества базового механизма кэширования браузера и избавляют нас от повторной реализации большого количества кода управления кешем. Однако он недоступен на Android 4.4.

Кеширование файловой системы

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

Выбранное решение

IndexedDB спешит на помощь! До Cache API решения на основе Service Worker полагались на хранение контента в IndexedDB. Это отличный метод хранения данных для браузера, которые можно запрашивать так же, как и в базе данных. Он также может хранить двоичные капли.

Мы напрямую не зависим от IndexedDB API, это чертовски сложно (об этом предупреждают даже MDN Docs). Мы полагаемся на Ionic Storage, чтобы предоставить IndexedDB как хранилище ключей и значений.

Вот как это работает:

  1. Мы получаем URL-адреса изображений, которые нам нужно отобразить.
  2. Если URL-адреса изображений уже кэшированы, мы возвращаем URI данных из кеша.
  3. Если URL-адрес не кэширован, мы загружаем URL-адрес и сохраняем значение в кеше.
  4. Мы сравниваем старый список URL-адресов с новым списком URL-адресов изображений. Мы удаляем ненужные нам данные.

Это дает нам очень точный контроль над тем, что и когда кэшировать. Наша логика кеширования реализована в CarouselProvider, простом Ionic-провайдере.

Начнем с модели, которая будет представлять изображение. Это тип, который будет передаваться компонентам, когда они запрашивают изображения карусели. Он содержит данные / ссылку изображения и связанные метаданные.

Функция loadFile класса CarouselProvider загружает URI данных в заданный объект Image, если он доступен. Он возвращает немодифицированный объект Image, если изображение не кэшировано. Это позволяет нам загружать только те изображения, которые еще не кэшированы, тем самым сохраняя данные пользователей.

Чтобы обойти проблему CORS при использовании live-reload во время разработки, мы переписываем URL-адрес, чтобы использовать наш Ionic прокси. Проблема CORS отсутствует при работе в качестве приложения Cordova.

Наш компонент сначала загружает кешированные изображения с помощью loadCachedPosts, а затем запрашивает обновленные изображения с помощью fetchPosts.

Вы можете увидеть полный код здесь: