我正在尝试在flutter web中实现多种口味(比如口味,因为口味来自android),但我找不到正确的方法。
我想做的事:
我添加了 dart-defines 来动态自定义应用程序的主题,但很少有东西保持不变,比如我在 index.html 文件中的样式(我更改了它以便有一个加载页面而不是白屏)。
我还尝试在 web 文件夹中创建两个文件夹,但风格仍然不起作用。
这个问题有什么解决办法吗?
有人遇到过这种情况吗?
截至目前,Flutter Web 并不直接支持flavor。
作为一种解决方法,可以通过在 CI 管道中创建不同的构建(在您的情况下为不同的 index.html 文件)来实现风格。本质上,您现在可以拥有不同口味的不同应用程序。
将index.html保存为项目中的模板(例如index.html.template),并将所有可修改的配置(标题、主题、颜色等)定义为环境变量,并替换这些环境变量以生成实际索引。在构建期间生成 html。
现在您可以控制这些构建,以根据您的口味进行不同的配置并满足您的用例。
例如- 要控制应用程序名称,您可以使用,
<title>"${CUSTOM_TITLE}"</title>
并在管道构建期间根据风格配置此 CUSTOM_TITLE。
类似的控制问题和解决方案在这里得到解答:https://stackoverflow.com/a/71538173/11675085
我使用的方法是
--dart-define-from-file=configfile.json
,并将变量放入configfile.json
。
参见 https://itnext.io/flutter-1-17-no-more-flavors-no-more-ios-schemas-command-argument-that-solves-everything-8b145ed4285d 和 https://itnext .io/flutter-3-7-and-a-new-way-of-defining-compile-time-variables-f63db8a4f6e2 有关使用 dart-defines 的信息。
dart-define-from-file 允许配置变量在您的应用程序代码中可用,也可以作为 iOS 和 Android 构建的编译时变量。
不幸的是不适用于网络,至少不是开箱即用,
对于网络,
然后,我将
index.html
中的大部分静态 HTML 从 HEAD 和 BODY 转换为 Javascript 字符串,一旦 Flutter 加载到 dart-defines
变量中,我就将这些字符串注入到页面中。
我使用了here描述的方法来创建触发器并传递变量。
因为变量可以作为 HTML 全局变量使用,所以您会自动获得模板。
这是一个示例,我将 APP_NAME 传入但要使用。不同的
manifest.json
或在各种图标文件上有后缀就像在模板中放置 $MANIFEST_FILE
或 $ICON_SUFFIX
一样简单,并确保这些变量通过 --dart-define-from-file
传递。
document.addEventListener("dart_loaded", function (){
console.log("dart_loaded event");
const headTemplate = `
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="${APP_DESCRIPTION}">
<link rel="apple-touch-icon" sizes="57x57" href="icons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="icons/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="icons/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="icons/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="icons/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="icons/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="icons/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="icons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="icons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="icons/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<title>${APP_NAME}</title>
`;
const bodyTemplate = `
<picture id="splash">
<source srcset="splash/img/light-1x.png 1x, splash/img/light-2x.png 2x, splash/img/light-3x.png 3x, splash/img/light-4x.png 4x" media="(prefers-color-scheme: light)">
<source srcset="splash/img/dark-1x.png 1x, splash/img/dark-2x.png 2x, splash/img/dark-3x.png 3x, splash/img/dark-4x.png 4x" media="(prefers-color-scheme: dark)">
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
</picture>
`;
document.head.insertAdjacentHTML('beforeend', headTemplate);
document.body.insertAdjacentHTML('beforeend', bodyTemplate);
});
请注意,使用此方法确实会丢失加载图像,因为在 Flutter 代码完全加载之前不会生成 HTML。
顺便说一句,Flutter 代码如下所示:
void main() async {
if (kIsWeb) {
js.context["APP_DESCRIPTION"] = const String.fromEnvironment("APP_DESCRIPTION");
js.context["APP_NAME"] = const String.fromEnvironment("APP_NAME");
// etc..
//Custom DOM event to signal to js the execution of the dart code
html.document.dispatchEvent(html.CustomEvent("dart_loaded"));
}
(另请参阅此线程,我也发布了此方法)
注意:此方法中不使用香料 - 不需要它们。