Slide 1

Slide 1 text

Flutter Web 을 활용해 제품 개발 환경 개선하기 김종식, ABC Studio @LINE

Slide 2

Slide 2 text

목차 1. 소개 2. 웹 빌드 및 배포 시도 소개 3. 요약 4. Q&A

Slide 3

Slide 3 text

소개

Slide 4

Slide 4 text

Demaecan (出前館)

Slide 5

Slide 5 text

Timeline 2022.05 DriverApp and Flutter Newbie 2023.04 ConsumerApp 2024.07 RetailApp 현 재 Flutter 엔지니어로 직무 전환한 이 야기

Slide 6

Slide 6 text

Flutter Web 을 활용해 제품 개발 환경 개선하 기 앱 제품 개선 과정 효율화 물리적 제약사항 극복 프로덕션 수준으로 서비스 출시 x

Slide 7

Slide 7 text

(Appendix) improve app install and test environment 앱 개발은 테스트 -> 피드백 -> 개선 사이클 과정에 큰 허들이 있음 (경험적으로, 동료들은 앱 개발 과정에서 테스트 참여하는 것을 훨씬 어렵고 허들이 높음) 해결하기 위한 관심사 DeviceFarm Flutter Web … 코로나 시대 원격 QA! 오픈소스 디바이스팜 STF 도입기

Slide 8

Slide 8 text

웹 빌드 및 배포 시도 사례

Slide 9

Slide 9 text

드라이버 앱의 웹 빌드 및 배포 시도 2022.05 DriverApp 2023.04 ConsumerApp 2024.07 RetailApp 현 재

Slide 10

Slide 10 text

첫 번째 Flutter web 시도 DriverApp to Web Flutter Newbie Web 실행 환경 구축을 목표로 사이드 프로젝트로 진행 멀쩡한 앱을 Flutter 앱으로 다시 짠 이유 – 일본 1위 배달앱, 두 번 째 Recode

Slide 11

Slide 11 text

Unsupported operation: Platform._operatingSystem 플랫폼 분기를 위해 사용중인 Platform.isAndroid, Platform.isIOS 코드에서 오류 발생 사용 코드가 제법 많은 상황 defaultTargetPlatform 을 사용하여 플랫폼 분기 코드 대응

Slide 12

Slide 12 text

AS-IS TO-BE

Slide 13

Slide 13 text

h3_flutter package update Uber 에서 개발한 지구를 계층을 갖는 육각형 그리드로 매핑해 놓은 것 h3_flutter 0.4.2 사용중 0.6.0 부터 웹 지원 확인 -> Android 빌드 오류 발생 이슈 리포트 -> 0.6.2 버전으로 대응 완료 H3: Uber-s Hexagonal Hierarchical Spatial Index

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Unsupported operation: Trying to use the default webview … 개인정보 취급방침, 이용약관, 공지사항 등 WebView 화면에서 오류 webview_flutter: ^3.0.4 webview_flutter_web: ^0.1.0+4 추가 웹뷰 위젯 구현부를 조건부 임포트를 통해 구현체 분기 처리

Slide 16

Slide 16 text

Conditional import Conditional imports across Flutter and Web

Slide 17

Slide 17 text

flutter_secure_storage - DomException 데이터를 암호화하여 저장 및 사용을 위해 flutter_secure_storage 사용 특정 데이터를 읽어올 경우 DomException 발생 키가 `{category}::{keyName}` 형식인 경우 이슈 발생 키를 `{keyName}` 형식으로 수정

Slide 18

Slide 18 text

Window.localStorage In flutter_secure_storage_web

Slide 19

Slide 19 text

XMLHttpRequest error 웹에서 API 통신을 시도할 경우 오류 발생 CORS (Cross-Origin Resource Sharing) issue 로컬 개발 환경에서 chrome 실행 시 --disable-web-security 설정 하여 이슈 대응 Flutter Web – XMLHttpRequest error

Slide 20

Slide 20 text

Set --disable-web-security options 1. flutter\bin\cache 이동 후 flutter_tools.stamp 제거 2. flutter\packages\flutter_tools\lib\src\web\chrome.dart 파일 열기 3. --disable-web-security 옵션 추가 How to solve flutter web api cors error only with dart code? 로컬 개발 환경에서 chrome 실행 시 보안 설정을 수정하는 것 실제 배포 환경을 말하는 것이 아님 (혼동 주의)

Slide 21

Slide 21 text

Cross-Origin Resource Sharing (CORS) ? 브라우저가 자신의 출처(Origin)가 아닌 다른 출처로부터 자원 로드를 허용하도록 서버가 허가해주는 HTTP 헤더 기반의 메커니즘 => 출처가 다른 서버간의 리소스 공유를 허용하는 것 https://future-flutter.dev:8080/sessions/detail?page=3#flutter_web Protocol Host Port Path Query String Fragment Origin(출처) ? URL (Uniform Resource Location) 구조에 서 Protocol + Host + Port 교차 출처 리소스 공유 (CORS)

Slide 22

Slide 22 text

CORS – flow of preflight request case Browser Source Code (index.html) Browser Engine Cloud Server Server 1) GET ‘list’ 2) OPTION ‘list’ 3) Response with allowed options 4) If not allowed 4) GET ‘list’ (if allowed) 5) Response with allow options 6) Result https://helloworld.com CORS, Preflight, 인증 처리 관련 삽질

Slide 23

Slide 23 text

Enabling --disable-web-secure Browser Source Code (index.html) Browser Engine 1) GET ‘list’ 2) GET ‘list’ 3) Response with allow options 4) Result https://localhost:12345 Cloud Server Server

Slide 24

Slide 24 text

(Tip) use flutter_cors tools 여러 버전의 flutter SDK 를 사용할 경우 유용함 // install ‘flutter_cors’ $ dart pub global activate flutter_cors // disable chrome web security option $ fluttercors -d –p {flutter_sdk_path} // enable chrome web security option $ fluttercors -e –p {flutter_sdk_path} flutter_cors

Slide 25

Slide 25 text

Permission acquisition scenario (reviewing) 권한획득 시나리오가 복잡하고, 웹에서 어떻게 대응해야 할 지 고민 Android iOS

Slide 26

Slide 26 text

Web support platform not available (reviewing) 웹을 미지원 하는 패키지 이슈 당시에는 기기 의존적인 패키지들은 잘 지원하지 않는 상황 웹에서 지도를 어떻게 표현해야 할 지 가장 큰 고민거리

Slide 27

Slide 27 text

Web support platform not available (reviewing)

Slide 28

Slide 28 text

드라이버 앱의 웹 시도 결과 Flutter web 빌드 및 로컬 개발환경까지 준비 웹 환경에서 드라이버 앱 사용 가능한 수준까지 진행하지 못함 이 때 경험은 나중에 Flutter Web 과제에 큰 도움이 됨

Slide 29

Slide 29 text

컨슈머 앱의 웹 빌드 및 배포 시도 2022.05 DriverApp 2023.04 ConsumerApp 2024.07 RetailApp 현 재

Slide 30

Slide 30 text

두 번째 Flutter web 시도 Recode & UI/UX 리뉴얼 과제 진행 UI/UX 리뉴얼 과제를 통해 제품 개선과정의 동기화가 쉽지 않다고 느낌 Flutter 전환의 마침표 – 일본 1위 배달 앱, 세 번째 Recode

Slide 31

Slide 31 text

Flutter 웹 환경 구축 과제 목적 재택근무로 인한 물리적 제약사항 기획자 및 관계자들을 위한 앱의 동작 테스트 수단이 필요 Flutter Web 시도 경험을 바탕으로 PoC 진행 컨슈머 앱을 웹에서 확인 가능한 환경을 제공하여 앱 동작 확인할 수 있는 수단을 제공 [오사카 /교토] 서버/앱 [도쿄] 서버/앱/ QA/기획 [후쿠오카/ 가고시마] QA/CS ABC Consumer 기획/디자인 /개발

Slide 32

Slide 32 text

ConsumerApp 웹 버전의 목표가 아닌 것 기존 웹 서비스를 대체하는 것 모바일 기기와 완전히 동일하게 동작하는 것 업무 프로세스에 최적화 하는 것 Flutter Web or React Native Web: Who Will Win the Battle?

Slide 33

Slide 33 text

Unsupported operation: Platform._operatingSystem CustomLint 추가

Slide 34

Slide 34 text

Use custom_lint package Flutter에서 커스텀 린트 활용하기

Slide 35

Slide 35 text

Update packages 웹 빌드 시 패키지 내부에서 오류가 발생 참조 패키지에서 ‘dart:ffi’ import 중 오류 발생 참조 패키지 버전 업데이트

Slide 36

Slide 36 text

newrelic_mobile: 1.0.1

Slide 37

Slide 37 text

newrelic_mobile: 1.0.6 Added ‘import dart:ffi;’ at (1.0.1) - https://github.com/newrelic/newrelic-flutter-agent/commit/2690bc968ba1833bbf80618f19bafc1bc70840c4 Removed ‘import dart:ffi;’ at (1.0.3) - https://github.com/newrelic/newrelic-flutter-agent/commit/017416eb6bede3de86319807ab52568a91223063

Slide 38

Slide 38 text

Support web platform flutter_inappwebview: 6.0.0 웹 실행 시 오류 발생 index.html 에 web_support.js 추가 Flutter InAppWebView 6 > Web Support

Slide 39

Slide 39 text

Support web platform fpjs_pro_flugin: ^3.0.0 전화번호 인증 flow 에서 오류 발생 index.html 에 index.js 추가 Fingerprint Pro Flutter > Web Support

Slide 40

Slide 40 text

Do not use package when run on web 웹 환경에서는 앱의 기능을 제공할 수 없는 패키지가 존재 의도적으로 미지원 처리 필요한 상황 플랫폼 별 다른 구현체를 반환하는 패턴으로 수정 패키지 인터페이스를 직접 사용하지 못하도록 Custom Lint 추가

Slide 41

Slide 41 text

Case of flutter_app_badger usage app_badger.dart app_badger_impl.dart app_badger_web.dart

Slide 42

Slide 42 text

$ getter pattern 플랫폼 별 다른 기능을 제공하는 경우 $ getter 형식을 사용하는 것으로 정리 Package Name AS-IS TO-BE Support Custom Lint adjust_sdk Adjust.*** $adjustUtil.*** O newrelic_mobile NewrelicMobile.*** $newrelicUtil.*** O flutter_inapwebview ChromeSafariBrowser() $chromeSafariBrowser O flutter_app_badger FlutterAppBadger.*** $appBadger.*** O firebase_core Firebase.*** FirebaseUtil.*** X firebase_analytics FirebaseAnalytics.instance.*** $firebaseAnalytics.*** O firebase_auth FirebaseAuth.instance.*** $firebaseAuth.*** O firebase_crashlytics FirebaseCrashlytics.instance.*** $firebaseCrashlytics.*** O firebase_messaging FirebaseMessaging.instance.*** $firebaseMessaging.*** O firebase_remote_config FirebaseRemoteConfig.instance.*** $firebaseRemoteConfig.*** O rokt_sdk RoktSdk.*** $roktSdkUtil.*** X

Slide 43

Slide 43 text

Support MapView platform_maps_flutter: ^1.0.2 요구사항: iOS – AppleMapView / Android – GoogleMapView 웹에서는 google_maps_flutter 를 이용해 맵뷰가 표시되도록 개선 google_maps_flutter_web > usage

Slide 44

Slide 44 text

In platform_maps_flutter

Slide 45

Slide 45 text

Refactor MapView 앱에서는 platform_maps_flutter / 웹에서는 google_maps_flutter 로 맵뷰 구현

Slide 46

Slide 46 text

Add Google Maps JavaScript API index.html 에 Google Maps JavaScript API 추가 로컬 개발환경에서는 ReferrerNotAllowedMapError 발생 배포 환경에서 정상동작 확인 Google Maps Platform > RefererNotAllowedMapError

Slide 47

Slide 47 text

Build web --base-href 설정할 경우 web_support.js 경로 오류 발생 빌드 완료 후 index.html 파일 수정 스크립트 작성

Slide 48

Slide 48 text

Web rendering option changed build web --web-renderer 기본값 auto > canvaskit 변경됨 SDK 3.22 부터 --wasm 사용 가능 AS-IS TO-BE --web-renderer {value} auto – 모바일 브라우저에서는 html, 데스크탑 브라 우저에서는 canvaskit 으로 동작 html – 경량적, 웹 표준기술을 사용 canvaskit – 고품질 그래픽, 일관된 렌더링 --wasm 브라우저가 wasm 지원할 경우 wasm, 아닐 경우 canvaskit 이 옵션을 설정하지 않을 경우 canvaskit flutter build web –help 로 옵션 지원여부 확인 가능 Intent to deprecate and remove the HTML renderer in Flutter Web

Slide 49

Slide 49 text

Deploy to web AWS S3 static page 배포 CORS issue - BFF (API Server) - Image Server 인프라팀을 통해 리소스 접근 설정으로 이슈 해결

Slide 50

Slide 50 text

컨슈머 앱의 웹 시도 결과 웹 배포 후 팀 내부에서 활용 중 - 과제별 개발 진행상황 확인 - 앱 제품에 대한 접근성 대폭 개선 - 주문 ~ 배달 완료 주문 흐름 테스트가 편해짐 동료를 유저로 확장하는 경험 Flutter Web을 활용해 제품 개발 환경 개선하기

Slide 51

Slide 51 text

리테일 앱의 웹 빌드 및 배포 시도 2022.05 DriverApp and Flutter Newbie 2023.04 ConsumerApp 2024.07 RetailApp 현 재

Slide 52

Slide 52 text

RetailApp Y!Shopping (LINEヤフー & Demae-can) 매장에서 주문을 수주하고, 주문을 배달로 연계 LINEヤフーと出前館、最短30分で届く即配サービス「Yahoo!クイックマート」の提供を開始

Slide 53

Slide 53 text

세 번째 Flutter web 시도 RetailApp to Web QA팀에서 웹으로 배포 요청 개발 과정에서 활용하는 사례 소개

Slide 54

Slide 54 text

Web build & deploy when Pull-Request created. PR 생성 시, 작업 내용을 실제로 확인하기 위해 Flutter Web 내부 배 포 실행 - flutter analyze, flutter test, spell check 등 실행 - 플랫폼 별 빌드 실행 <- Web 빌드 시 배포 수행 - 테스트 실행 결과 및 Web 빌드 결과 확인 URL을 PR Comment 추가 - 매일 업로드된 버킷 목록과 PR 목록을 확인하여 자동으로 클라우드 저장소에 업로드된 웹 빌드물 삭제

Slide 55

Slide 55 text

Deploy to web Verda cloud 배포 CORS issue - CORS header issue - CORS preflight issue BFF (API Server) 이슈 수정으로 대응 SpringBoot 에서 CORS 할 때 header, preflight 이슈 해결하기

Slide 56

Slide 56 text

Flutter app 을 web 으로 활용 시 고려 사항

Slide 57

Slide 57 text

Do not use Platform.*** Platform.isAndroid, Platform.isIOS 사용하지 마세요 Use defaultTargetPlatform Use debugDefaultTargetPlatformOverride for Test Code debugDefaultTargetPlatformOverride top-level property

Slide 58

Slide 58 text

Consider each package using within the app ① 웹에서 오류가 발생하는지 확인한다. 로컬 개발 환경에서 우선 확인 패키지 추가 시, 웹 환경 설정을 누락했을 가능성이 높 다. ② 관련 기능이 반드시 필요한지 확인한다. 패키지가 웹을 지원하는지 확인하고, 가급적 지원하도록 대 응하자. (생각보다 많은) 패키지가 웹 환경을 지원한다. 만약 웹을 지원하지 않을 경우, Mock 활용 고려하자. 패키지를 업데이트 했으면, 모바일 환경에서 한번 더 체크 하자. ③ 반대로, 굳이 필요하지 않은지 판단한다. 관련 기능을 웹환경에서 의도적으로 제공하지 않는다. 인터페이스 호출 시 플랫폼별로 다르게 동작하도록 구성 한다. 앱과 웹의 실행 환경은 다르다는 것을 항상 염두한다. ④ 웹에서 제약사항을 잘 공유한다. 기술적으로 지원이 불가능한 경우가 있을 수 있다. 앱과 동작이 완벽히 동일하지 않을 수 있다. 브라우저 쿠키 & 캐시 제거 방법 공유하자.

Slide 59

Slide 59 text

Cross-Origin Resource Sharing (CORS) ? 브라우저가 자신의 출처(Origin)가 아닌 다른 출처로부터 자원 로드를 허용하도록 서버가 허가해주는 HTTP 헤더 기반의 메커니즘 => 출처가 다른 서버간의 리소스 공유를 허용하는 것 https://future-flutter.dev:8080/sessions/detail?page=3#flutter_web Protocol Host Port Path Query String Fragment Origin(출처) ? URL (Uniform Resource Location) 구조에 서 Protocol + Host + Port 교차 출처 리소스 공유 (CORS)

Slide 60

Slide 60 text

Enabling --disable-web-secure Browser Source Code (index.html) Browser Engine 1) GET ‘list’ 2) GET ‘list’ 3) Response with allow options 4) Result https://localhost:12345 Cloud Server Server

Slide 61

Slide 61 text

Server-Side configuration XMLHttpRequest, unauthorized 200 응답과 함께 데이터가 없는 현상 등 서버 담당자에게 배포된 웹에서의 접근 허용 작업을 요청 - DevOps Engineer - Server Engineer Cloud Server Server ① ②

Slide 62

Slide 62 text

Use Proxy Server 만약 웹 서비스도 운영 중이면, proxy server 가 존재할 가능성이 높음 - Front-end Engineer Browser Source Code (index.html) Browser Engine Cloud Server Server Request Result Proxy Server Request Result

Slide 63

Slide 63 text

(Appendix) 참조 링크 (1) https://youtu.be/By9k4vZ__Mk Flutter 엔지니어로 직무 전환한 이 야기 https://engineering.linecorp.com/ko/blog/demaecan-2nd-recode-kmm-to-flutter 멀쩡한 앱을 Flutter 앱으로 다시 짠 이유 – 일본 1위 배달앱, 두 번째 Recode https://www.uber.com/en-KR/blog/h3/ H3: Uber-s Hexagonal Hierarchical Spatial Index https://medium.com/flutter-community/conditional-imports-across-flutter-and-web-4b88885a886e Conditional imports across Flutter and Web https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage Window.localStorage

Slide 64

Slide 64 text

(Appendix) 참조 링크 (2) https://github.com/cfug/dio/issues/750 Flutter Web – XMLHttpRequest error https://stackoverflow.com/questions/65630743/how-to-solve-flutter-web-api-cors-error-only- with-dart-code/66879350#66879350 How to solve flutter web api cors error only with dart code? https://pub.dev/packages/flutter_cors flutter_cors https://techblog.lycorp.co.jp/ko/demaecan-3rd-recode-react-native-to-flutter Flutter 전환의 마침표 – 일본 1위 배달 앱, 세 번째 Recode https://www.expertappdevs.com/blog/flutter-web-vs-react-native-web Flutter Web or React Native Web: Who Will Win the Battle?

Slide 65

Slide 65 text

(Appendix) 참조 링크 (3) https://techblog.lycorp.co.jp/ko/using-custom-lint-in-flutter Flutter에서 커스텀 린트 활용하기 https://inappwebview.dev/blog/flutter-inappwebview-6#web-support Flutter InAppWebView 6 > Web Support https://pub.dev/packages/fpjs_pro_plugin#web-platform Fingerprint Pro Flutter > web support https://pub.dev/packages/google_maps_flutter_web#usage google_maps_flutter_web > usage https://developers.google.com/maps/documentation/javascript/error-messages#referer-not-allowed-map-error Google Maps Platform > RefererNotAllowedMapError

Slide 66

Slide 66 text

(Appendix) 참조 링크 (4) https://docs.google.com/document/d/1DGamHsa2lz_Qtgfrfa3j3fRaEopJXc7tCFVM1TQlck8 Intent to deprecate and remove the HTML renderer in Flutter Web https://techblog.lycorp.co.jp/ko/improve-development-experience-with-flutter-web Flutter Web을 활용해 제품 개발 환경 개선하기 https://developer.mozilla.org/ko/docs/Web/HTTP/CORS 교차 출처 리소스 공유 (CORS) https://www.popit.kr/cors-preflight-%EC%9D%B8%EC%A6%9D-%EC%B2%98%EB%A6%AC- %EA%B4%80%EB%A0%A8-%EC%82%BD%EC%A7%88/ CORS, Preflight, 인증 처리 관련 삽질 https://velog.io/@ojwman/spring-boot-cors-header-preflight SpringBoot에서 CORS할 때 header, preflight 이슈 해결하기

Slide 67

Slide 67 text

감사합니다