콘텐츠로 이동

이 퀵가이드는 NetFUNNEL Flutter 에이전트를 처음 적용하는 개발자가 빠르게 시작할 수 있도록 필수 구현 사항을 간략히 안내합니다.

아래는 예제의 기본 디렉터리 구조입니다. 각 파일은 에이전트 초기화, 진입 요청, 진입 완료 처리를 담당합니다.

├── pubspec.yaml // netfunnel_flutter 경로 의존성
├── android/app/src/main/
│ └── AndroidManifest.xml // 인터넷 권한
└── lib/
├── main.dart // initialize 호출 - 에이전트 초기화
├── main_screen.dart // nfStart 호출 - 진입 요청
└── event_screen.dart // nfStop 호출 - 진입 완료 처리

Flutter 에이전트는 안정적인 동작을 위해 앱 실행 시 가장 먼저 초기화되어야 합니다. 따라서 main()에서 runApp() 전에 초기화 함수를 호출합니다. (패키지 추가와 자세한 초기화 설정은 통합 가이드를 참고하세요.)

lib/main.dart
import 'package:netfunnel_flutter/netfunnel_flutter.dart';
void main() async {
await Netfunnel.instance.initialize(
clientId: '{{CLIENT_ID}}',
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NetFUNNEL Sample App',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomeScreen(),
);
}
}

Android에서 NetFUNNEL 서버와 통신할 수 있도록 인터넷 권한을 추가합니다.

android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 인터넷 접속 권한 허용 -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

시작 함수(nfStart, nfStartSection)에 전달한 NetfunnelCallback으로 넷퍼넬 서버의 응답을 받습니다. 응답은 콜백 메서드와 상태 코드(statusCode), 메시지(message)로 전달되며, 콜백에 따라 분기 처리합니다.

  • onSuccess: 진입 또는 우회 응답. 화면 이동·함수 실행 등 기존 서비스 로직을 실행합니다.
  • onError: 시스템 에러. 원활한 이용을 위해 onSuccess와 동일하게 기존 로직을 실행합니다.
  • onNetworkError: 네트워크 장애. 기존 로직을 실행하거나, 악용 방지를 위해 다시 대기하도록 처리할 수 있습니다.
import 'package:netfunnel_flutter/netfunnel_flutter.dart';
class NetfunnelHandler extends NetfunnelCallback {
final BuildContext context;
NetfunnelHandler({required this.context});
static const String _tag = "[APP]";
@override
void onSuccess(int statusCode, String message) {
/// 대기열 통과 시 처리할 로직
/// ex - 서비스 화면 진입 처리
print('$_tag onSuccess: $statusCode $message');
navigateToEventScreen();
}
@override
void onError(int statusCode, String message) {
/// 에러 발생 시 처리할 로직
/// ex - 사용자에게 오류 메시지 표시 또는 바이패스
print('$_tag onError: $statusCode $message');
navigateToEventScreen();
}
@override
void onNetworkError(int statusCode, String message) {
/// 네트워크 에러 발생 시 처리할 로직
/// ex - 네트워크 재연결 안내 또는 재시도 화면으로 이동
print('$_tag onNetworkError: $statusCode $message');
if (statusCode == 1001) {
showSnackBar("네트워크 연결에 실패했습니다. 네트워크 설정을 확인해 주세요.");
} else if (statusCode == 1002) {
navigateToEventScreen();
}
}
@override
void onBlock(int statusCode, String message) {
/// 사용자 진입 차단 시 처리할 로직
/// ex - 접근 제한 메시지 표시
print('$_tag onBlock: $statusCode $message');
}
@override
void onClose(int statusCode, String message) {
/// 사용자가 대기를 취소한 경우 처리할 로직
/// ex - 종료 안내 메시지 표시
print('$_tag onClose: $statusCode $message');
}
@override
void onContinue(int statusCode, String message, int aheadWait, int behindWait, String waitTime, int progressRate) {
/// 대기 진행 중 UI 업데이트 로직 (자체 커스텀 대기실 사용 시에만 해당)
/// ex - 실시간 대기 정보를 커스텀 대기 화면에 업데이트
print('$_tag onContinue: $statusCode $message');
}
void navigateToEventScreen() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => EventScreen(),
),
);
}
void showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}
}

nfStart(기본 제어), nfStartSection(구간 제어)는 대기 상태를 감지하고 필요 시 대기실을 띄우는 함수입니다. 대기실을 띄울 화면의 context를 함께 전달합니다.

import 'package:netfunnel_flutter/netfunnel_flutter.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
Netfunnel.instance.nfStart(
projectKey: '{{PROJECT_KEY}}',
segmentKey: '{{SEGMENT_KEY}}',
callback: NetfunnelHandler(context: context),
context: context,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Home Screen")),
body: const Center(
child: Text("Home Screen"),
),
);
}
}

nfStop(기본 제어), nfStopSection(구간 제어)은 대기 완료 후 서버에 진입 키를 반납하는 함수입니다. 키를 반납해 다음 사용자가 진입할 수 있게 하며, 일반적으로 서비스 진입 직후 실행합니다.

import 'package:flutter/material.dart';
import 'package:flutter_sample/utils/constants.dart';
import 'package:netfunnel_flutter/netfunnel_flutter.dart';
class EventScreen extends StatefulWidget {
const EventScreen({super.key});
@override
State<EventScreen> createState() => _EventScreenState();
}
class _EventScreenState extends State<EventScreen> {
@override
void initState() {
super.initState();
Netfunnel.instance.nfStop(
projectKey: '{{PROJECT_KEY}}',
segmentKey: '{{SEGMENT_KEY}}',
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Event Screen")),
body: const Center(
child: Text("Event Screen"),
),
);
}
}

6.1 MainScreen에서 EventScreen으로 이동

섹션 제목: “6.1 MainScreen에서 EventScreen으로 이동”

MainScreen의 버튼에서 시작 함수를 호출해 대기열을 적용하고, onSuccess 응답을 받으면 EventScreen으로 이동합니다. EventScreen이 표시되면 종료 함수를 호출해 키를 반납합니다. (기본 제어와 구간 제어의 적용 방식은 동일합니다.)

lib/main_screen.dart
import 'package:flutter/material.dart';
import 'package:netfunnel_flutter/netfunnel_flutter.dart';
import 'event_screen.dart';
class MainScreen extends StatelessWidget {
const MainScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => Netfunnel.instance.nfStart(
projectKey: '{PROJECT_KEY}',
segmentKey: '{SEGMENT_KEY}',
callback: _EnterCallback(context),
context: context,
),
child: const Text('Go to Event'),
),
),
);
}
}
class _EnterCallback extends NetfunnelCallback {
_EnterCallback(this.context);
final BuildContext context;
void _goToEvent() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => const EventScreen()));
}
@override
void onSuccess(int statusCode, String message) => _goToEvent();
// 시스템 에러 시에도 서비스 이용을 위해 이동
@override
void onError(int statusCode, String message) => _goToEvent();
@override
void onNetworkError(int statusCode, String message) => _goToEvent();
}
lib/event_screen.dart
import 'package:flutter/material.dart';
import 'package:netfunnel_flutter/netfunnel_flutter.dart';
class EventScreen extends StatefulWidget {
const EventScreen({super.key});
@override
State<EventScreen> createState() => _EventScreenState();
}
class _EventScreenState extends State<EventScreen> {
@override
void initState() {
super.initState();
// 화면 진입 후 진입 키 반납
Netfunnel.instance.nfStop(projectKey: '{PROJECT_KEY}', segmentKey: '{SEGMENT_KEY}');
}
@override
Widget build(BuildContext context) {
return const Scaffold(body: Center(child: Text('Event')));
}
}

6.2 하나의 화면 안에서 함수를 실행

섹션 제목: “6.2 하나의 화면 안에서 함수를 실행”

한 화면 안에서 시작 함수 호출 후, onSuccess에서 서비스 로직(예: 주문 요청)을 처리한 뒤 적절한 위치에서 종료 함수를 실행합니다.

lib/order_screen.dart
class _OrderCallback extends NetfunnelCallback {
@override
void onSuccess(int statusCode, String message) async {
await requestOrder();
// 주문 처리가 끝나면 진입 키 반납
await Netfunnel.instance.nfStop(projectKey: '{PROJECT_KEY}', segmentKey: '{SEGMENT_KEY}');
}
@override
void onError(int statusCode, String message) => requestOrder();
@override
void onNetworkError(int statusCode, String message) => requestOrder();
}
void onOrderPressed(BuildContext context) {
Netfunnel.instance.nfStart(
projectKey: '{PROJECT_KEY}',
segmentKey: '{SEGMENT_KEY}',
callback: _OrderCallback(),
context: context,
);
}