Flutter

Flutter 가이드 문서는 아래 2가지 라이브러리를 필수로 사용합니다.
WebView 패키지 (v6) :
flutter_inappwebview
v5를 사용하고 계신 클라이언트는 [Migration Guide] 링크를 참고하여 마이그레이션을 권장드립니다.
화면 활성화 여부 판단 패키지 :
visibility_detector
런처 화면이 백그라운드 모드로 전환될 때 WebView의
pause
,resume
상태 등을 체크하기 위해 필요합니다.
// pubspec.yaml
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
flutter_inappwebview: ^6.0.0
visibility_detector: ^0.4.0+2
1단계: 런처 위젯 추가
인앱 게임을 런처에 구동하기 위해서는 WebView를 사용하는 위젯을 생성해야 합니다. 다음 가이드를 따라 진행해주시기 바랍니다.
1. dart 파일 생성
기본적으로 lib
폴더 경로에 런처가 구동될 dart
파일을 생성합니다.
가이드에서는 screens
폴더를 생성 후 bleepy_screen.dart
파일을 생성하였습니다.
2. Navigator 추가
런처 페이지 위젯으로 이동하기 위한 router를 추가합니다.
3. InAppWebViewSettings 옵션 추가
WebView에 사용될 옵션 값을 정의합니다.
4. WebView에 런처 URL 로드
위젯 페이지 내 InAppWebView
를 추가하고 런처 호출 URL
을 요청합니다.
// lib/screens/bleepy_screen.dart
class _BleepyLauncherScreenState extends State<BleepyLauncherScreen> {
InAppWebViewController? webViewController;
@override
Widget build(BuildContext context) {
final GlobalKey webViewKey = GlobalKey();
// WebView 옵션
InAppWebViewSettings options = InAppWebViewSettings(
...
javaScriptEnabled: true, // javascript 실행 여부
useHybridComposition: true, // hybrid 사용을 위한 android 웹뷰 최적화
clearCache: true,
...
);
return InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri({런처 URL})),
initialSettings: options,
onWebViewCreated: (controller) {
webViewController = controller;
}
)
}
}
2단계: 위젯 백그라운드 처리 추가
WebView 내에 런처를 실행하면 자바스크립트 로직이 핑 전송 API를 주기적으로 호출합니다. 따라서 위젯이 백그라운드 모드로 이동되면 inactive
상태로 처리되어야 정상입니다.
그러나 런처 위젯에서 다른 위젯으로 Navigator
를 통한 라우팅 시 플랫폼에 따라 예외적인 케이스가 존재합니다.
AOS
의 경우 라우팅 시 inactive
상태로 변경되지 않는 이슈가 있어 직접 컨트롤이 필요합니다.
다음 가이드를 따라 코드를 추가해 주세요.
1. LiftCycle 감지 설정 추가
위젯의 LifeCycle 감지를 위해 WidgetsBindingObserver
를 사용합니다.
initState
에서addObserver
를 호출dispose
에서removeObserver
를 호출
해당 과정은 VisibilityDetector
라이브러리의 정상 동작을 위해 선행되어야 합니다.
// lib/screens/bleepy_screen.dart
class _BleepyLauncherScreenState extends State<BleepyLauncherScreen>
with WidgetsBindingObserver{
...
@override
void initState() {
super.initState();
// 최초 위젯 실행 시 호출
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
// 위젯이 메모리에서 제거될 때 호출
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
...
}
2. VisibilityDetector 라이브러리 추가
VisibilityDetector
라이브러리를 통해 현재 화면의 활성화 여부 판단이 필요합니다.
화면의 활성화/비활성화 여부에 따라 WebView에 아래와 같은 처리가 필요합니다.
화면 비활성화 시
WebView
pause
화면 활성화 시
WebView
resume
VisibilityDetector
라이브러리는 아래 옵션 표를 참고합니다.
key
key
필수 입력 값
onVisibilityChanged
void Function(VisibilityInfo)
visibilityInfo 내 visibleFraction으로 활성화 여부 판단
double
형1.0
- 활성화0.0
- 비활성화
// lib/screens/bleepy_screen.dart
@override
Widget build(BuildContext context) {
...
// VisibilityDetector 추가
return VisibilityDetector(
key: const Key("banner-screen-visibility-detector"),
onVisibilityChanged: (visibilityInfo) {
// visibility change event
var visibleFlag = visibilityInfo.visibleFraction.toInt();
if(visibleFlag == 1){
// 화면 보여질 때 실행
webViewController?.resume();
} else {
// 화면 안 보여질 때 실행
webViewController?.pause();
}
},
child: SafeArea(...)
);
}
3단계: Javascript Handler 추가
런처와 Flutter간의 통신을 수행하기 위해 Javascript Handler
추가가 필요합니다.
자바스크립트 핸들러 작성 시 handlerName 값은 BlpLauncher
로 작성해야 합니다.
다음은 런처에서 전달하는 이벤트 케이스 입니다.
handlerName:
BlpLauncher
closeLauncher
블리피 런처의 Back 버튼 UI 클릭 시 (뒤로가기 처리)
launcherLoaded
블리피 런처 로드가 완료된 시점에 호출
timerMissionComplete
타이머 미션이 완료 되었을 때 호출
giftReceived
육성완료 시 호출
// lib/screens/bleepy_screen.dart
InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri(widget.launcherUrl)),
initialSettings: options,
onWebViewCreated: (controller) {
webViewController = controller;
// 자바스크립트 핸들러 추가
controller.addJavaScriptHandler(handlerName: 'BlpLauncher', callback: (message) {
final data = jsonDecode(message[0]);
final key = data['type'];
switch (key) {
case "closeLauncher":
closeLauncher();
break;
case "launcherLoaded":
launcherLoaded();
break;
case "timerMissionComplete":
timerMissionComplete();
break;
case "giftReceived":
giftReceived();
break;
default:
break;
}
});
}
)
// lib/screens/bleepy_screen.dart
// 런처 종료
void closeLauncher() {
Navigator.of(context).pop();
}
// 런처 로드 완료
void closeLauncher() {
// 런처의 로드가 완료된 후 추가적인 처리 필요 시 사용
}
// 타이머 미션 완료
void closeLauncher() {
// 타이머 미션 완료 후 추가적인 처리 필요 시 사용
}
// 육성완료
void closeLauncher() {
// 육성완료 후 추가적인 처리 필요 시 사용
}
4단계: 런처 스크린 세로모드 고정 로직 추가
게임은 세로모드 해상도에 최적화 되어 스크린의 세로모드 고정이 필요합니다.
service.dart
패키지를 추가합니다.SystemChrome.setPreferredOrientations
메서드를 통해 세로 방향으로 고정합니다.
// lib/screens/bleepy_screen.dart
// 화면 고정을 위해 상단에 다음 패키지를 추가
import 'package:flutter/services.dart';
@override
Widget build(BuildContext context) {
// ...
// 세로 위아래 방향 고정
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
return VisibilityDetector(
...
child: SafeArea(...)
);
}
5단계: 화면 전환 설정
1. shouldOverrideUrlLoading 사용
inAppWebView
에서 제공되는 shouldOverrideUrlLoading
를 사용하여 딥링크 정보를 받을 수 있습니다. URI 정보를 받아 Screen 분기 처리를 진행합니다.
URI
정보 -navigationAction.request.url
scheme
- 딥링크 스키마host
- 딥링크 호스트queryParameters
- 딥링크 쿼리스트링
// WebView 선언 부분 코드 추가
InAppWebView(
...
shouldOverrideUrlLoading: (controller, navigationAction) async {
// uri 정보
var uri = navigationAction.request.url!;
// Deep Link scheme 값으로 조건문 추가
if (uri.scheme == {scheme}) {
// Deep Link host 값으로 조건문 추가
if (uri.host == {host}) {
// Query string 값을 전달하기 위해 arguments 추가
Navigator.pushNamed(context, '/{host}', arguments: uri.queryParameters);
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
...
)
Last updated