flutter initialization 적용하기

이우길·2024년 7월 26일
0

flutter

목록 보기
8/9
post-thumbnail

flutter web app initialization 적용하기

flutter로 만든 web app에 처음 진입했을 때 보여줄 loading indicator를 적용하자.

해당 글은 flutter version 3.22 이상 환경에서 작성하였으며 3.22 이하의 경우 legacy문서를 확인하면 된다.


Goal

  • 공식문서를 보며 web app이 켜질 때 이벤트 처리에 대한 내용 이해하기
  • 웹의 리소스를 다운로드 하는 동안 보여질 loading indicator 적용하기

개요

flutter Web를 빌드할때 dart2js가 dart 코드 전체를 javascript로 컴파일한 다음 결과를 build/web/main.dart.js로 저장한다.

index.html에서는 js를 불러와서 화면을 그리게 되는데 이 때 사용자에게는 계속해서 하얀색의 화면이 노출되게 되는데 사용자 경험을 좋지 않게 만들고 있다.

이것을 해결하기 위해 initialization를 적용해보고자 한다.


initialization

공식문서를 보면 웹 앱이 초기화 될 때 커스텀을 할 수 있는 방법을 제공해주고 있다.


프로젝트 생성 및 초기 구조

먼저 프로젝트를 생성하였을 때 web디렉토리에 있는 index.html의 코드를 보면 아래와 같이 스크립트 하나가 정의되어 있는 것을 볼 수 있다.

<html>
  <!-- ... -->
  <body>
    <script src="flutter_bootstrap.js" async></script>
  </body>
  <!-- ... -->
</html>

위 코드에서 볼 수 있듯 flutter_bootstrap.jsinitialization을 처리할 수 있는데 해당 파일은 flutter의 web이 빌드 될 때 build 파일 안에 자동으로 생긴다. 해당 파일의 역할은 앱을 초기화 하고 실행하는데 필요한 정보들이 들어있는 파일이라고 생각하면 된다.


만약 web 디렉토리 내부에 flutter_bootstrap.js를 새로 정의했다면 빌드 시 오버라이딩되며 적용된다. 기본적으로 flutter에서 빌드 시 자동으로 생성해주는 flutter_bootstrap.js는 아래와 같다.

// 1
{{flutter_js}}

// 2 
{{flutter_build_config}}

// 3
_flutter.loader.load();
  1. flutter_jsFlutterLoader object를 사용 가능하게 만들어준다. FlutterLoader 내부에는 _flutter.loader가 글로벌 변수로 존재한다.

  2. flutter_build_config는 빌드 과정에서 생성된 메타데이터를 설정하는 역할을 한다. 앱이 정상적으로 부트스트랩되기 위해 FlutterLoader에 데이터를 제공해준다.

  3. 앱을 초기화 하기 호출되는 함수이며 초기화 시 사용할 옵션들을 받는다.

  • config: 앱의 구성
  • onEntrypointLoaded: 엔진 초기화 준비가 되면 호출 될 콜백함수
  • serviceWorkerSettings: 서비스 워커 구성

onEntrypointLoaded

목표를 이루기 위해서 중요하게 볼 부분이 onEntrypointLoaded 콜백이다. 위에서도 적은 것 처럼 엔진의 초기화 준비가 되면 해당 콜백이 호출되게 되는데 해당 콜백 내부에서 runApp()이 호출 되기 전까지 유저에게 흰 화면이 보여지게 되는 것이다.

앱이 실행 되기 전에 초기화 및 로딩 처리에 대한 부분을 해당 콜백에서 정의하면 된다.


loading indicator적용하기

progress-indicator예시에 나온 것 처럼 먼저 document.bodydiv를 심고 해당 요소를 loading indicator로 사용하고자 한다.

// fluter_bootstrap.js
{{flutter_js}}
{{flutter_build_config}}


const loadingDiv = document.createElement("div");
loadingDiv.className = "loading";
document.body.appendChild(loadingDiv);
const loaderDiv = document.createElement("div");
loaderDiv.className = "loader";
loadingDiv.appendChild(loaderDiv);

// Customize the app initialization process
_flutter.loader.load();

필자는 css-loaders에서 loading indicator의 css를 가져와 사용하으며 해당 코드를 index.html에 추가하였다.

/* style.css */
.loading {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}


.loader {
  width: 50px;
  aspect-ratio: 1;
  color:#dc1818;
  background:
    radial-gradient(circle at 60% 65%, currentColor 62%, #0000 65%) top left,
    radial-gradient(circle at 40% 65%, currentColor 62%, #0000 65%) top right,
    linear-gradient(to bottom left, currentColor 42%,#0000 43%) bottom left ,
    linear-gradient(to bottom right,currentColor 42%,#0000 43%) bottom right;
  background-size: 50% 50%;
  background-repeat: no-repeat;
  position: relative;
}
.loader:after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  opacity: 0.4;
  animation: l3 1s infinite;
}
@keyframes l3 {
  to {transform:scale(1.8);opacity:0}
}

위와 같이 작성하면 앱에 들어왔을 때 해당 loading indicator가 보여질 것이다. loading indicator는 엔진이 준비되기 전까지 보여주고 사라져야 하기 때문에 onEntrypointLoaded 콜백을 이용하여 loading indicator로 사용되는 div요소를 제거해주면 된다.

{{flutter_js}}
{{flutter_build_config}}


const loadingDiv = document.createElement("div");
loadingDiv.className = "loading";
document.body.appendChild(loadingDiv);
const loaderDiv = document.createElement("div");
loaderDiv.className = "loader";
loadingDiv.appendChild(loaderDiv);

_flutter.loader.load({
  onEntrypointLoaded: async function (engineInitializer) {
    const appRunner = await engineInitializer.initializeEngine();
    if (document.body.contains(loadingDiv)) {
      document.body.removeChild(loadingDiv);
    }
    await appRunner.runApp();
  },
});

REFERENCES

profile
leewoooo

0개의 댓글