Failed to download https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle 超时 解决办法

flutter项目下执行 flutter run 提示信号灯超时时间已到

Failed to download https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle/+/8MSYGWVWzrTJIoVL00ZquruZs-weuwLBy1kt1AawJiIC. Ensure you have network connectivity and then try again. SocketException: 信号灯超时时间已到

1、问题截图如下:

2、解决办法

终端输入

export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

后回车

再次执行flutter run 启动项目即可成功。

注:

export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

为设置使用国内镜像

参考链接


Failed to download https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle 超时 解决办法

Flutter The Linux toolchain CMake build dependency (CMake 3.14 or higher is required. You are running version 3.10.2)

ubuntu 22.04 通过 snap 安装了 Flutter SDK(当前是Flutter 3.3.4),如果第三方的依赖了 CMake 3.10.2 更高的版本,会在编译的时候报错:

CMake 3.14 or higher is required. You are running version 3.10.2

这个报错的原因是由于 snap 安装的 Flutter SDK 构建了一个沙箱环境,在这个环境中的 CMake3.10.2 版本,不管系统安装的是哪个版本的 CMake ,都是无效的。

要解决这个问题,或者等待 snapFlutter SDK 更新版本,或者参照 Linux install Flutter 的说明,手工安装并配置 Flutter SDK

可以参考如下代码:

$ sudo snap remove flutter

$ sudo apt-get install curl

$ sudo apt-get install clang

$ sudo apt-get install git

$ sudo apt-get install ninja-build

$ sudo apt-get install pkg-config

$ sudo apt install gettext

$ sudo apt-get install libgtk-3-dev

$ sudo apt install libstdc++-12-dev

$ git clone https://github.com/flutter/flutter.git -b stable

$ export PATH="$PATH:`pwd`/flutter/bin"

$ cd `pwd`/flutter/bin 

$ ./flutter doctor

参考链接


Android各大市场更改APP名称

公司上架了一款App,因为产品运营需要去修改App名称,在iOS应用市场提交新版本的时候可以改App名称。那么Android 各大市场如何更改APP名称呢?

目前上架的Android 应用市场有:360手机助手、腾讯应用宝、百度手机助手、阿里应用分发市场(豌豆荚)、安智市场、小米应用商店、华为应用市场、OPPO商店、魅族应用商店、vivo应用市场、搜狗手机助手等平台。

每家Android应用市场的规则都不同,小编整理了Android 各大市场更改APP名称的规则。

1、 百度 : 百度平台的最简单。直接更新app的版本即可(应用名称是系统从您提交的应用中解析的,如需修改请联系贵司技术修改apk包内信息。)

百度如何修改app名称
百度如何修改app名称

2、应用宝: 用上线后,开发者可通过工单系统提交应用名称修改需求 (入口1:如图点击“名称更改指引”即可直接跳转到修改应用名称的工单系统;入口2:管理中心-->点击需要修改名称的应用-->基础服务-->工单系统-->应用宝商务类-->移动应用名称修改-->填单提交)。修改应用名称需要提供软件著作权; 若暂无软著,可提供此款应用在其他外市场,改过名字后的前后台上线管理截图(其他证明文件均不接受);

腾讯开放平台应用改名
腾讯开放平台应用改名

重要提示:根据平台规则,应用上线后,应用名称最多可支持修改2次,超过修改次数将不再受理,请谨慎确定好需要修改的应用名称后,再提交工单申请。

腾讯移动应用名称修改
腾讯移动应用名称修改

3、华为: 在开发者后台在该应用下点击上架或者升级,上传更名后的APK包,并在应用信息处更改应用名称,如应用分类涉及软著要求,请在“版本信息”的“应用版权证书或代理证书”处更新应用软著及免责函,提交应用审核。

华为应用商店应用改名
华为应用商店应用改名

4、360移动开放平台和百度移动开放平台是一样的,直接更新app的版本即可。

5、 vivo开放平台:

1)应用类APP需要修改名称: 直接在后台编辑更新,保证apk包内和在后台填写的名称一致即可;若名称相差较大,请在版权证明栏补充软著;游戏类APP(网游/单机)需要修改名称:需联系对接商务处理。

2)若需要更改应用包名,请联系贵司技术人员;更改之后再在平台创建应用提交新包名应用,旧包名应用需申请下架(登录平台--管理中心--点击您的应用--“下架申请”即可)。

6、 OPPO开放平台:也是上传后将自动解析包名。

7、魅族开放平台:也是上传后将自动解析包名。

8、小米市场: 应用名称修改需于应用包内及应用信息一同更改。应用包内名称更改还请贵司技术开发人员自行更改。(可以试一下直接上传后将自动解析包名。)

9、豌豆荚(阿里云应用分发平台):也是上传后将自动解析包名。

参考链接


Android 各大市场更改APP名称

Flutter-从数据库中获取记录并使用ListView Builder显示出来

数据保存在数据库中,根据表名称获取所有记录的列表,并在"ListView.builder"中显示的代码如下:

class _EmployeesListScreenState extends State<EmployeesListScreen> {
  var db = new DatabaseHelper(); // CALLS FUTURE

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('List Of Employees'),
      ),
      body: FutureBuilder<List>(
        future: db.getAllRecords("tabEmployee"),
        initialData: const [],
        builder: (context, snapshot) {
          return snapshot.hasData ? ListView.builder(
            itemCount: snapshot.data?.length,
            itemBuilder: (_, int position) {
              final item = snapshot.data?.elementAt(position);
              //get your item data here ...
              return Card(child: ListTile(
                  title: Text('Employee Name: ${item?.row[1]}'),
                ),
              );
              },
          );
        },
      ),
    );
  }
}

参考链接


Flutter 3.0实现Windows本地化/国际化

参照 Flutter 2.8.1本地化/国际化应用程序名称 可以实现 Android/macOS/iOS/Web 的应用名称相关的国际化。Linux 参考 Flutter 3.0实现Linux本地化/国际化

那么在 Windows 应用上如何相同的功能呢?

下面我们探讨一下一个比较简单的解决方案,就是直接修改RC文件,这个方案适用于涉及到的语言类型不太多的情况

Windows 代码编译,需要安装 Microsoft Visual Studio 2022 Community,但是不能直接使用 Microsoft Visual Studio 2022 Community 编辑 RC 文件,打开就会报错

fatal error RC1015: cannot open include flie 'winres.h'

具体的操作方法如下:

我们假定工程的名字为 LanauageTest

首先在项目根目录下,执行

$ flutter build windows 

生成 build 目录,然后使用 Microsoft Visual Studio 2022 Community 打开 build\windows\LanauageTest.sln 文件。

接着在资源视图中找到字符串资源,选择默认的 StringTable ,然后右键选择 “插入副本

虽然可以使用上面的操作来添加语言,但是只能作为参考,原因在于 Microsoft Visual Studio 2022 CommunityRC 文件编辑器在修改 LanauageTest.RC 文件的时候,把预定义的宏进行了展开,直接使用宏的实际值替代了宏本身,导致这些数据失去动态变化的能力。我们只能手工再编辑一次,恢复原来的宏才可以。

至于使用的话,可以通过 LoadString 加载定义的字符串资源,更详细参考 Using Resources

参考链接


Flutter 3.0实现Linux本地化/国际化

参照 Flutter 2.8.1本地化/国际化应用程序名称 可以实现 Android/macOS/iOS/Web 的应用名称相关的国际化。但是在 Linux 应用上如何相同的功能,目前暂时没有一个统一的标准。

研究了许久,终于基本上算是搞定,解决方案如下:

使用 gettext 来实现国际化相关的功能。

首先配置,调整工程的目录如下:

project/
project/linux
project/linux/flutter
project/linux/flutter/CMakeLists.txt
project/linux/locale/en_US/app.po
project/linux/locale/zh_CN/app.mo
project/linux/locale/CMakeLists.txt
project/linux/CMakeLists.txt
project/linux/main.cc
project/linux/my_application.cc
project/linux/my_application.h

对应语言 i18n 相关配置文件的内容如下:

# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.10)

set(OUTPUT_NAME "app")
set(LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(LOCALE_BUILD_DIR "${CMAKE_BINARY_DIR}/locale")
set(LOCALE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/locale")

# Setting up Internationalisation (i18n)
find_package (Intl REQUIRED)
if (Intl_FOUND)
    message(STATUS "Internationalization (i18n) found:")
    message(STATUS " INTL_INCLUDE_DIRS: ${Intl_INCLUDE_DIRS}")
    message(STATUS " INTL_LIBRARIES: ${Intl_LIBRARIES}")
    message(STATUS " Version: ${Intl_VERSION}")
    include_directories(${Intl_INCLUDE_DIRS})
    link_directories(${Intl_LIBRARY_DIRS})
else ()
    message(STATUS "Internationalization (i18n) Not found!")
endif ()

find_package(Gettext REQUIRED)
if (Gettext_FOUND)
    message(STATUS "Gettext found:")
    message(STATUS " Version: ${GETTEXT_VERSION_STRING}")
else ()
    message(STATUS "Gettext Not found!")
endif ()

find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)

if (GETTEXT_XGETTEXT_EXECUTABLE)

    message(DEBUG " xgettext: ${GETTEXT_XGETTEXT_EXECUTABLE}")
    file(GLOB_RECURSE PO_FILES RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/*.po)
    add_custom_target(
        pot-update
        COMMENT "pot-update: Done."
        DEPENDS ${LOCALE_DIR}/${OUTPUT_NAME}.pot
    )
    add_custom_command(
        TARGET pot-update
        PRE_BUILD
        COMMAND
            ${GETTEXT_XGETTEXT_EXECUTABLE}
            --from-code=utf-8
            --force-po
            --output=${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
            --keyword=_
            --width=80
            ${PO_FILES}
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        COMMENT "pot-update: Pot file generated: ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot"
    )
else ()
    message(STATUS "pot-update not created!")
endif (GETTEXT_XGETTEXT_EXECUTABLE)

if (GETTEXT_MSGMERGE_EXECUTABLE)

    message(DEBUG " msgmerge: ${GETTEXT_MSGMERGE_EXECUTABLE}")

    add_custom_target(
        pot-merge
        COMMENT "pot-merge: Done."
        DEPENDS ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
    )

    file(GLOB PO_FILES ${LOCALE_DIR}/*/${OUTPUT_NAME}.po)
    message(TRACE " PO_FILES: ${PO_FILES}")

    foreach(PO_FILE IN ITEMS ${PO_FILES})
        message(DEBUG " Adding msgmerge for: ${PO_FILE}")
        add_custom_command(
            TARGET pot-merge
            PRE_BUILD
            COMMAND
                ${GETTEXT_MSGMERGE_EXECUTABLE} ${PO_FILE}
                ${LOCALE_BUILD_DIR}/${OUTPUT_NAME}.pot
            COMMENT "pot-merge: ${PO_FILE}"
        )
    endforeach()
else ()
    message(STATUS "pot-merge not created!")
endif (GETTEXT_MSGMERGE_EXECUTABLE)

if (GETTEXT_MSGFMT_EXECUTABLE)

    message(DEBUG " msgmerge: ${GETTEXT_MSGFMT_EXECUTABLE}")

    file(GLOB PO_LANGS LIST_DIRECTORIES true ${LOCALE_DIR}/*)
    message(TRACE " PO_LANGS: ${PO_LANGS}")

    add_custom_target(
        po-compile
        COMMENT "po-compile: Done."
    )

    foreach(PO_LANG IN ITEMS ${PO_LANGS})
        if(IS_DIRECTORY ${PO_LANG})
            message(STATUS " Adding msgfmt for: ${PO_LANG}")

            file(RELATIVE_PATH REL_PO_LANG "${LOCALE_DIR}" "${PO_LANG}")
            set(MO_BUILD_DIR "${LOCALE_BUILD_DIR}/${REL_PO_LANG}")
            file(MAKE_DIRECTORY "${MO_BUILD_DIR}")
            set(MO_NAME "${MO_BUILD_DIR}/${OUTPUT_NAME}.mo")

            add_custom_command(
                TARGET po-compile
                PRE_BUILD
                COMMAND
                    ${GETTEXT_MSGFMT_EXECUTABLE}
                    --output-file=${MO_NAME}
                    ${OUTPUT_NAME}.po
                WORKING_DIRECTORY "${PO_LANG}"
                COMMENT "po-compile: ${PO_LANG}"
            )

            install(FILES "${LOCALE_BUILD_DIR}/${REL_PO_LANG}/${OUTPUT_NAME}.mo"
                DESTINATION "${LOCALE_INSTALL_DIR}/${REL_PO_LANG}/LC_MESSAGES"
                COMPONENT Runtime)
        endif()
    endforeach()
else ()
    message(STATUS "pot-compile not created!")
endif (GETTEXT_MSGFMT_EXECUTABLE)

接下来,修改 Linux 工程的配置文件,增加对 本地化(i18n) 文件的引用,在合适的位置增加如下代码:

# locale build and install
set(FLUTTER_LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale")
add_subdirectory(${FLUTTER_LOCALE_DIR})

完整的代码参考如下:

# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)

# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "abc")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "xxx.xxx.xxx")

# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(SET CMP0063 NEW)

# Load bundled libraries from the lib/ directory relative to the binary.
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")

# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()

# Define build configuration options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE "Debug" CACHE
    STRING "Flutter build mode" FORCE)
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
    "Debug" "Profile" "Release")
endif()

# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
  target_compile_features(${TARGET} PUBLIC cxx_std_14)
  target_compile_options(${TARGET} PRIVATE -Wall -Werror)
  target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
  target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()

# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})

# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)

add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")

# Define the application target. To change its name, change BINARY_NAME above,
# not the value here, or `flutter run` will no longer work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME}
  "main.cc"
  "my_application.cc"
  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)

# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})

# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)

# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
  PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)

# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} po-compile)

# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()

# locale build and install
set(FLUTTER_LOCALE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale")
add_subdirectory(${FLUTTER_LOCALE_DIR})

# Start with a clean build bundle directory every time.
install(CODE "
  file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
  " COMPONENT Runtime)

set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")

install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
  COMPONENT Runtime)

install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
  COMPONENT Runtime)

install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
  COMPONENT Runtime)

foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
  install(FILES "${bundled_library}"
    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
    COMPONENT Runtime)
endforeach(bundled_library)

# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
  " COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)

# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
  install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
    COMPONENT Runtime)
endif()

使用多语言的代码如下:

#include "my_application.h"

#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif

#include <sys/stat.h>
#include <libgen.h>
#include <locale.h>
#include <libintl.h>

#include "flutter/generated_plugin_registrant.h"

#define LOCALE_DIR "/locale/"
#define PACKAGE "app"
#define _(String) gettext(String)

struct _MyApplication
{
  GtkApplication parent_instance;
  char **dart_entrypoint_arguments;
};

G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)

// 118n
static void setup_app_locale()
{
  struct stat sb;
  const char *proc_name = "/proc/self/exe";

  if (lstat(proc_name, &sb) >= 0)
  {

    /* Add one to the link size, so that we can determine whether
    the buffer returned by readlink() was truncated. */
    ssize_t bufsiz = sb.st_size + 1;

    /* Some magic symlinks under (for example) /proc and /sys
    report 'st_size' as zero. In that case, take PATH_MAX as
    a "good enough" estimate. */
    if (0 == sb.st_size)
    {
      bufsiz = PATH_MAX;
    }

    ssize_t loc_dir_len = bufsiz + strlen(LOCALE_DIR) + 1;
    char *buf = (char *)malloc(loc_dir_len);
    if (NULL != buf)
    {
      ssize_t nbytes = readlink(proc_name, buf, bufsiz);
      if (nbytes >= 0)
      {
        /* If the return value was equal to the buffer size, then the
        the link target was larger than expected (perhaps because the
        target was changed between the call to lstat() and the call to
        readlink()). Warn the user that the returned target may have
        been truncated. */

        if (nbytes == bufsiz)
        {
          g_message("(Returned buffer may have been truncated)\n");
        }

        if (nbytes <= bufsiz)
        {
          buf[nbytes] = '\0';
        }

        char *dir = dirname(buf);

        strncat(dir, LOCALE_DIR, strlen(LOCALE_DIR));

        char *loc = setlocale(LC_ALL, NULL);

        g_message("current locale is:%s", loc);
        g_message("locale files dir is:%s", buf);

        setlocale(LC_ALL, "");

        bindtextdomain(PACKAGE, buf);

        textdomain(PACKAGE);
      }
      free(buf);
    }
  }
}

// Implements GApplication::activate.
static void my_application_activate(GApplication *application)
{
  MyApplication *self = MY_APPLICATION(application);
  GtkWindow *window =
      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

  // Use a header bar when running in GNOME as this is the common style used
  // by applications and is the setup most users will be using (e.g. Ubuntu
  // desktop).
  // If running on X and not using GNOME then just use a traditional title bar
  // in case the window manager does more exotic layout, e.g. tiling.
  // If running on Wayland assume the header bar will work (may need changing
  // if future cases occur).
  gboolean use_header_bar = TRUE;

  setup_app_locale();

#ifdef GDK_WINDOWING_X11
  GdkScreen *screen = gtk_window_get_screen(window);
  if (GDK_IS_X11_SCREEN(screen))
  {
    const gchar *wm_name = gdk_x11_screen_get_window_manager_name(screen);
    if (g_strcmp0(wm_name, "GNOME Shell") != 0)
    {
      use_header_bar = FALSE;
    }
  }
#endif
  if (use_header_bar)
  {
    GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
    gtk_widget_show(GTK_WIDGET(header_bar));
    gtk_header_bar_set_title(header_bar, _("app_name"));
    gtk_header_bar_set_show_close_button(header_bar, TRUE);
    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
  }
  else
  {
    gtk_window_set_title(window, _("app_name"));
  }

  gtk_window_set_default_size(window, 1280, 720);
  gtk_widget_show(GTK_WIDGET(window));

  g_autoptr(FlDartProject) project = fl_dart_project_new();
  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);

  FlView *view = fl_view_new(project);
  gtk_widget_show(GTK_WIDGET(view));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));

  fl_register_plugins(FL_PLUGIN_REGISTRY(view));

  gtk_widget_grab_focus(GTK_WIDGET(view));
}

// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status)
{
  MyApplication *self = MY_APPLICATION(application);
  // Strip out the first argument as it is the binary name.
  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);

  g_autoptr(GError) error = nullptr;
  if (!g_application_register(application, nullptr, &error))
  {
    g_warning("Failed to register: %s", error->message);
    *exit_status = 1;
    return TRUE;
  }

  g_application_activate(application);
  *exit_status = 0;

  return TRUE;
}

// Implements GObject::dispose.
static void my_application_dispose(GObject *object)
{
  MyApplication *self = MY_APPLICATION(object);
  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}

static void my_application_class_init(MyApplicationClass *klass)
{
  G_APPLICATION_CLASS(klass)->activate = my_application_activate;
  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}

static void my_application_init(MyApplication *self) {}

MyApplication *my_application_new()
{
  return MY_APPLICATION(g_object_new(my_application_get_type(),
                                     "application-id", APPLICATION_ID,
                                     "flags", G_APPLICATION_NON_UNIQUE,
                                     nullptr));
}

参考链接