> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 보상형 광고

> Flutter 앱에서 보상형 광고를 구현하는 방법을 안내합니다.

## 개요

보상형 광고는 사용자가 광고를 끝까지 시청하면 보상을 받는 형태의 풀스크린 광고입니다. 게임 내 아이템, 추가 콘텐츠 등의 보상을 제공할 때 사용합니다.

### 주요 특징

* 화면 전체를 덮는 풀스크린 광고
* 동영상 광고 지원
* 보상 이벤트 콜백 제공
* 보상 타입과 수량 정보 전달
* 로드와 표시를 분리하여 유연한 타이밍 제어

<Note>
  개발 환경에서는 테스트 유닛 ID를 사용하세요: `PUBLIC_TEST_UNIT_ID_REWARDED`
</Note>

***

## AdropRewardedAd

### 생성자

```dart theme={null}
AdropRewardedAd({
  required String unitId,
  AdropRewardedListener? listener,
})
```

**파라미터**

| 파라미터       | 타입                      | 필수 | 설명                   |
| ---------- | ----------------------- | -- | -------------------- |
| `unitId`   | `String`                | Y  | 애드컨트롤 콘솔에서 생성한 유닛 ID |
| `listener` | `AdropRewardedListener` | N  | 광고 이벤트 리스너           |

### 속성

| 속성                              | 타입                               | 설명                              |
| ------------------------------- | -------------------------------- | ------------------------------- |
| `isLoaded`                      | `bool`                           | 광고 로드 완료 여부                     |
| `unitId`                        | `String`                         | 광고 유닛 ID                        |
| `creativeId`                    | `String`                         | 크리에이티브 ID                       |
| `txId`                          | `String`                         | 트랜잭션 ID                         |
| `campaignId`                    | `String`                         | 캠페인 ID                          |
| `destinationURL`                | `String`                         | 목적지 URL                         |
| `browserTarget`                 | `BrowserTarget?`                 | 브라우저 타겟 (외부 또는 내부)              |
| `serverSideVerificationOptions` | `ServerSideVerificationOptions?` | 서버 측 검증 옵션 (userId, customData) |

### 메서드

| 메서드         | 반환 타입          | 설명            |
| ----------- | -------------- | ------------- |
| `load()`    | `Future<void>` | 광고를 로드합니다     |
| `show()`    | `Future<void>` | 광고를 화면에 표시합니다 |
| `dispose()` | `Future<void>` | 리소스를 해제합니다    |

***

## 기본 사용법

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class RewardedExample extends StatefulWidget {
  const RewardedExample({super.key});

  @override
  State<RewardedExample> createState() => _RewardedExampleState();
}

class _RewardedExampleState extends State<RewardedExample> {
  bool isLoaded = false;
  AdropRewardedAd? rewardedAd;

  @override
  void initState() {
    super.initState();
    _createRewardedAd();
  }

  void _createRewardedAd() {
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          debugPrint('보상형 광고 로드 성공: ${ad.creativeId}');
          setState(() {
            isLoaded = true;
          });
        },
        onAdFailedToReceive: (ad, errorCode) {
          debugPrint('보상형 광고 로드 실패: $errorCode');
        },
        onAdClicked: (ad) {
          debugPrint('보상형 광고 클릭');
        },
        onAdDidPresentFullScreen: (ad) {
          debugPrint('보상형 광고 표시됨');
        },
        onAdDidDismissFullScreen: (ad) {
          debugPrint('보상형 광고 닫힘');
        },
        onAdFailedToShowFullScreen: (ad, errorCode) {
          debugPrint('보상형 광고 표시 실패: $errorCode');
        },
        onAdEarnRewardHandler: (ad, type, amount) {
          debugPrint('보상 획득: 타입=$type, 수량=$amount');
          _giveReward(type, amount);
        },
      ),
    );
  }

  void _giveReward(int type, int amount) {
    // 보상 지급 로직 구현
    // 예: 코인, 아이템, 추가 생명 등
  }

  void loadAd() {
    rewardedAd?.load();
  }

  void showAd() {
    if (isLoaded) {
      rewardedAd?.show();
    }
  }

  @override
  void dispose() {
    rewardedAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('보상형 광고 예제')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: loadAd,
              child: const Text('광고 로드'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: isLoaded ? showAd : null,
              child: const Text('광고 보고 보상 받기'),
            ),
          ],
        ),
      ),
    );
  }
}
```

***

## AdropRewardedListener

보상형 광고 이벤트를 처리하는 리스너입니다.

### 콜백 함수

```dart theme={null}
AdropRewardedListener(
  onAdReceived: (AdropAd ad) {
    // 광고 로드 성공
  },
  onAdClicked: (AdropAd ad) {
    // 광고 클릭
  },
  onAdImpression: (AdropAd ad) {
    // 광고 노출
  },
  onAdWillPresentFullScreen: (AdropAd ad) {
    // 광고가 표시되기 직전 (iOS 전용)
  },
  onAdDidPresentFullScreen: (AdropAd ad) {
    // 광고가 표시됨
  },
  onAdWillDismissFullScreen: (AdropAd ad) {
    // 광고가 닫히기 직전 (iOS 전용)
  },
  onAdDidDismissFullScreen: (AdropAd ad) {
    // 광고가 닫힘
  },
  onAdFailedToReceive: (AdropAd ad, AdropErrorCode errorCode) {
    // 광고 로드 실패
  },
  onAdFailedToShowFullScreen: (AdropAd ad, AdropErrorCode errorCode) {
    // 광고 표시 실패
  },
  onAdEarnRewardHandler: (AdropAd ad, int type, int amount) {
    // 보상 획득
  },
)
```

### 콜백 설명

| 콜백                           | 설명                      |
| ---------------------------- | ----------------------- |
| `onAdReceived`               | 광고 로드 성공 시 호출           |
| `onAdClicked`                | 광고 클릭 시 호출              |
| `onAdImpression`             | 광고 노출 시 호출              |
| `onAdWillPresentFullScreen`  | 광고가 표시되기 직전 호출 (iOS 전용) |
| `onAdDidPresentFullScreen`   | 광고가 표시된 후 호출            |
| `onAdWillDismissFullScreen`  | 광고가 닫히기 직전 호출 (iOS 전용)  |
| `onAdDidDismissFullScreen`   | 광고가 닫힌 후 호출             |
| `onAdFailedToReceive`        | 광고 로드 실패 시 호출           |
| `onAdFailedToShowFullScreen` | 광고 표시 실패 시 호출           |
| `onAdEarnRewardHandler`      | 보상 획득 시 호출              |

***

## 보상 처리

### 보상 콜백

`onAdEarnRewardHandler` 콜백에서 보상 정보를 받아 처리합니다.

```dart theme={null}
onAdEarnRewardHandler: (ad, type, amount) {
  debugPrint('보상 획득: 타입=$type, 수량=$amount');

  // 보상 타입에 따른 처리
  switch (type) {
    case 1:
      // 코인 보상
      _addCoins(amount);
      break;
    case 2:
      // 아이템 보상
      _addItem(amount);
      break;
    default:
      // 기본 보상
      _giveDefaultReward(amount);
  }
}
```

### 보상 지급 시점

<Warning>
  보상은 반드시 `onAdEarnRewardHandler` 콜백에서 지급해야 합니다. 광고가 완전히 시청되기 전에 닫히면 이 콜백이 호출되지 않습니다.
</Warning>

```dart theme={null}
class RewardManager {
  bool _rewardEarned = false;

  void setupRewardedAd() {
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdEarnRewardHandler: (ad, type, amount) {
          // 보상 플래그 설정
          _rewardEarned = true;
        },
        onAdDidDismissFullScreen: (ad) {
          // 광고가 닫힌 후 보상 지급 확인
          if (_rewardEarned) {
            _giveReward();
            _rewardEarned = false;
          }
        },
      ),
    );
  }
}
```

***

## 광고 재생성

보상형 광고는 일회성입니다. 한 번 표시된 광고는 다시 표시할 수 없으므로, 새로운 광고를 로드하려면 인스턴스를 재생성해야 합니다.

```dart theme={null}
class _RewardedState extends State<RewardedWidget> {
  bool isLoaded = false;
  bool isShown = false;
  AdropRewardedAd? rewardedAd;

  @override
  void initState() {
    super.initState();
    _createRewardedAd();
  }

  void _createRewardedAd() {
    rewardedAd?.dispose();
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          setState(() {
            isLoaded = true;
          });
        },
        onAdDidPresentFullScreen: (ad) {
          setState(() {
            isShown = true;
          });
        },
        onAdEarnRewardHandler: (ad, type, amount) {
          _giveReward(type, amount);
        },
        onAdDidDismissFullScreen: (ad) {
          // 광고가 닫힌 후 새 광고 준비
          _createRewardedAd();
          rewardedAd?.load();
        },
      ),
    );

    setState(() {
      isLoaded = false;
      isShown = false;
    });
  }

  @override
  void dispose() {
    rewardedAd?.dispose();
    super.dispose();
  }
}
```

***

## 에러 처리

```dart theme={null}
class _RewardedState extends State<RewardedWidget> {
  bool isLoaded = false;
  AdropErrorCode? errorCode;
  AdropRewardedAd? rewardedAd;

  void _createRewardedAd() {
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          setState(() {
            isLoaded = true;
            errorCode = null;
          });
        },
        onAdFailedToReceive: (ad, error) {
          setState(() {
            isLoaded = false;
            errorCode = error;
          });
          _handleError(error);
        },
        onAdFailedToShowFullScreen: (ad, error) {
          setState(() {
            errorCode = error;
          });
          _handleError(error);
        },
      ),
    );
  }

  void _handleError(AdropErrorCode error) {
    switch (error) {
      case AdropErrorCode.network:
        debugPrint('네트워크 오류가 발생했습니다.');
        break;
      case AdropErrorCode.adNoFill:
        debugPrint('노출할 광고가 없습니다.');
        break;
      case AdropErrorCode.adShown:
        debugPrint('이미 표시된 광고입니다.');
        break;
      default:
        debugPrint('오류 발생: ${error.code}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: rewardedAd?.load,
          child: const Text('광고 로드'),
        ),
        ElevatedButton(
          onPressed: isLoaded ? rewardedAd?.show : null,
          child: const Text('광고 보고 보상 받기'),
        ),
        if (errorCode != null)
          Text(
            '에러: ${errorCode?.code}',
            style: const TextStyle(color: Colors.red),
          ),
      ],
    );
  }
}
```

***

## 모범 사례

### 1. 미리 로드하기

사용자가 보상을 요청할 때 즉시 광고를 보여줄 수 있도록 미리 로드합니다.

```dart theme={null}
class GameScreen extends StatefulWidget {
  @override
  State<GameScreen> createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> {
  AdropRewardedAd? rewardedAd;
  bool isAdReady = false;

  @override
  void initState() {
    super.initState();
    _preloadAd();
  }

  void _preloadAd() {
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          setState(() {
            isAdReady = true;
          });
        },
        onAdEarnRewardHandler: (ad, type, amount) {
          _giveReward(type, amount);
        },
        onAdDidDismissFullScreen: (ad) {
          // 다음 광고 미리 로드
          _preloadAd();
        },
      ),
    );
    rewardedAd?.load();
  }

  void showRewardedAd() {
    if (isAdReady) {
      rewardedAd?.show();
      setState(() {
        isAdReady = false;
      });
    }
  }

  @override
  void dispose() {
    rewardedAd?.dispose();
    super.dispose();
  }
}
```

### 2. 사용자에게 보상 안내

광고 시청 전 받을 수 있는 보상을 명확히 안내합니다.

```dart theme={null}
void showRewardDialog() {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('보상 받기'),
      content: const Text('광고를 시청하면 100 코인을 받을 수 있습니다!'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('취소'),
        ),
        ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
            showRewardedAd();
          },
          child: const Text('광고 보기'),
        ),
      ],
    ),
  );
}
```

### 3. 광고 가용성 표시

광고가 준비되었을 때만 보상 버튼을 활성화합니다.

```dart theme={null}
Widget buildRewardButton() {
  return ElevatedButton.icon(
    onPressed: isAdReady ? showRewardedAd : null,
    icon: const Icon(Icons.play_circle_outline),
    label: Text(isAdReady ? '광고 보고 보상 받기' : '광고 로딩 중...'),
    style: ElevatedButton.styleFrom(
      backgroundColor: isAdReady ? Colors.green : Colors.grey,
    ),
  );
}
```

### 4. 보상 지급 신뢰성

보상 지급은 서버에서 검증하는 것이 좋습니다.

```dart theme={null}
onAdEarnRewardHandler: (ad, type, amount) async {
  try {
    // 서버에 보상 지급 요청
    await _api.grantReward(
      userId: currentUserId,
      transactionId: ad.txId,
      rewardType: type,
      amount: amount,
    );

    // 로컬 상태 업데이트
    _updateLocalBalance(amount);
  } catch (e) {
    debugPrint('보상 지급 실패: $e');
    // 재시도 또는 오류 처리
  }
}
```

### 5. 리소스 관리

사용하지 않는 광고 인스턴스는 반드시 해제하세요.

```dart theme={null}
@override
void dispose() {
  rewardedAd?.dispose();
  super.dispose();
}
```

***

## 전체 예제

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class RewardedAdPage extends StatefulWidget {
  const RewardedAdPage({super.key});

  @override
  State<RewardedAdPage> createState() => _RewardedAdPageState();
}

class _RewardedAdPageState extends State<RewardedAdPage> {
  bool isLoaded = false;
  bool isLoading = false;
  bool isShown = false;
  int coins = 0;
  AdropErrorCode? errorCode;
  AdropRewardedAd? rewardedAd;

  @override
  void initState() {
    super.initState();
    _createRewardedAd();
  }

  void _createRewardedAd() {
    rewardedAd?.dispose();
    rewardedAd = AdropRewardedAd(
      unitId: 'PUBLIC_TEST_UNIT_ID_REWARDED', // 테스트 유닛 ID
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          debugPrint('광고 로드 성공');
          debugPrint('크리에이티브 ID: ${ad.creativeId}');
          debugPrint('캠페인 ID: ${ad.campaignId}');
          setState(() {
            isLoaded = true;
            isLoading = false;
            errorCode = null;
          });
        },
        onAdClicked: (ad) {
          debugPrint('광고 클릭: ${ad.destinationURL}');
        },
        onAdImpression: (ad) {
          debugPrint('광고 노출: ${ad.creativeId}');
        },
        onAdWillPresentFullScreen: (ad) {
          debugPrint('광고 표시 예정');
        },
        onAdDidPresentFullScreen: (ad) {
          debugPrint('광고 표시됨');
          setState(() {
            isShown = true;
          });
        },
        onAdWillDismissFullScreen: (ad) {
          debugPrint('광고 닫힘 예정');
        },
        onAdDidDismissFullScreen: (ad) {
          debugPrint('광고 닫힘');
          // 새 광고 준비
          _createRewardedAd();
        },
        onAdFailedToReceive: (ad, error) {
          debugPrint('광고 로드 실패: $error');
          setState(() {
            isLoaded = false;
            isLoading = false;
            errorCode = error;
          });
        },
        onAdFailedToShowFullScreen: (ad, error) {
          debugPrint('광고 표시 실패: $error');
          setState(() {
            errorCode = error;
          });
        },
        onAdEarnRewardHandler: (ad, type, amount) {
          debugPrint('보상 획득: 타입=$type, 수량=$amount');
          setState(() {
            coins += amount;
          });
          _showRewardNotification(amount);
        },
      ),
    );

    setState(() {
      isLoaded = false;
      isShown = false;
      errorCode = null;
    });
  }

  void loadAd() {
    setState(() {
      isLoading = true;
      errorCode = null;
    });
    rewardedAd?.load();
  }

  void showAd() {
    if (isLoaded) {
      rewardedAd?.show();
    }
  }

  void _showRewardNotification(int amount) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('$amount 코인을 획득했습니다!'),
        backgroundColor: Colors.green,
        duration: const Duration(seconds: 2),
      ),
    );
  }

  @override
  void dispose() {
    rewardedAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('보상형 광고 예제'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // 코인 표시
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.amber.shade100,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const Icon(Icons.monetization_on, color: Colors.amber),
                    const SizedBox(width: 8),
                    Text(
                      '$coins 코인',
                      style: const TextStyle(
                        fontSize: 24,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 32),

              // 로드 버튼
              ElevatedButton(
                onPressed: isLoading ? null : loadAd,
                child: Text(isLoading ? '로딩 중...' : '광고 로드'),
              ),
              const SizedBox(height: 16),

              // 표시 버튼
              ElevatedButton.icon(
                onPressed: isLoaded ? showAd : null,
                icon: const Icon(Icons.play_circle_outline),
                label: const Text('광고 보고 보상 받기'),
                style: ElevatedButton.styleFrom(
                  backgroundColor: isLoaded ? Colors.green : Colors.grey,
                ),
              ),
              const SizedBox(height: 16),

              // 재설정 버튼
              TextButton(
                onPressed: (isShown || errorCode != null)
                    ? () => _createRewardedAd()
                    : null,
                child: const Text('재설정'),
              ),
              const SizedBox(height: 24),

              // 상태 표시
              Text('로드됨: ${isLoaded ? "예" : "아니오"}'),
              Text('표시됨: ${isShown ? "예" : "아니오"}'),

              // 에러 표시
              if (errorCode != null) ...[
                const SizedBox(height: 16),
                Text(
                  '에러: ${errorCode?.code}',
                  style: const TextStyle(color: Colors.red),
                ),
              ],
            ],
          ),
        ),
      ),
    );
  }
}
```

***

## 서버 측 검증 (SSV)

서버 측 검증을 사용하면 서버에서 보상 지급을 안전하게 검증할 수 있습니다. 광고가 로드될 때 서버 간 콜백에 `userId`와 `customData`를 포함하려면 `ServerSideVerificationOptions`를 설정하세요.

<Note>
  서버에서 SSV 콜백을 수신하려면 콘솔 **\[관리] > \[연동] > 리워드 광고 SSV**에서 콜백 URL을 등록해야 해요. 여기서 설정한 `userId`와 `customData`는 해당 URL로 전송되는 암호화 페이로드에 포함됩니다. 페이로드 복호화 및 설정 방법은 [리워드 광고 SSV 가이드](/ko/integrations/ssv)를 참고하세요.
</Note>

### 설정

`load()`를 호출하기 전에 `serverSideVerificationOptions`를 설정하세요.

```dart theme={null}
final rewardedAd = AdropRewardedAd(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropRewardedListener(
    onAdReceived: (ad) {
      setState(() {
        isLoaded = true;
      });
    },
    onAdEarnRewardHandler: (ad, type, amount) {
      debugPrint('보상 획득: type=$type, amount=$amount');
      // 서버에서 보상 검증
    },
  ),
);

// load() 호출 전에 SSV 옵션 설정
rewardedAd.serverSideVerificationOptions = ServerSideVerificationOptions(
  userId: 'user_123',
  customData: 'level_5_reward',
);

await rewardedAd.load();
```

### ServerSideVerificationOptions

| 속성           | 타입        | 설명                     |
| ------------ | --------- | ---------------------- |
| `userId`     | `String?` | 서버 측 검증을 위한 사용자 식별자    |
| `customData` | `String?` | 서버 콜백에 포함할 커스텀 데이터 문자열 |

### 전체 예제

```dart theme={null}
class _RewardedSSVState extends State<RewardedSSVWidget> {
  bool isLoaded = false;
  AdropRewardedAd? rewardedAd;

  void _createRewardedAd() {
    rewardedAd?.dispose();
    rewardedAd = AdropRewardedAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropRewardedListener(
        onAdReceived: (ad) {
          setState(() {
            isLoaded = true;
          });
        },
        onAdEarnRewardHandler: (ad, type, amount) {
          // 서버에서 보상 검증
          _verifyRewardOnServer(
            transactionId: ad.txId,
            rewardType: type,
            amount: amount,
          );
        },
        onAdDidDismissFullScreen: (ad) {
          // 다음 광고 준비
          _createRewardedAd();
          rewardedAd?.load();
        },
      ),
    );

    // SSV 옵션 설정
    rewardedAd!.serverSideVerificationOptions = ServerSideVerificationOptions(
      userId: currentUserId,
      customData: 'reward_context_data',
    );
  }

  Future<void> _verifyRewardOnServer({
    required String transactionId,
    required int rewardType,
    required int amount,
  }) async {
    // 서버에 보상 검증 요청 전송
    try {
      await api.verifyReward(
        transactionId: transactionId,
        rewardType: rewardType,
        amount: amount,
      );
      _updateLocalBalance(amount);
    } catch (e) {
      debugPrint('보상 검증 실패: $e');
    }
  }

  @override
  void dispose() {
    rewardedAd?.dispose();
    super.dispose();
  }
}
```

<Warning>
  `serverSideVerificationOptions`는 `load()` 호출 전에 설정해야 합니다. `load()` 이후에 설정한 옵션은 해당 광고 요청에 적용되지 않습니다.
</Warning>

***

## 백필 광고

백필 광고가 활성화된 경우, 직광고가 없을 때 자동으로 백필 광고가 로드됩니다. 에러 코드를 통해 백필 관련 상태를 처리할 수 있습니다.

```dart theme={null}
rewardedAd = AdropRewardedAd(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropRewardedListener(
    onAdReceived: (ad) {
      debugPrint('광고 로드됨: ${ad.creativeId}');
    },
    onAdFailedToReceive: (ad, errorCode) {
      switch (errorCode) {
        case AdropErrorCode.adNoFill:
          debugPrint('직광고 없음');
          break;
        case AdropErrorCode.backfillNoFill:
          debugPrint('백필 광고도 없습니다');
          break;
        default:
          debugPrint('광고 로드 실패: ${errorCode.code}');
      }
    },
  ),
);
```

<Note>
  백필 광고를 사용하려면 네이티브 플랫폼에 백필 의존성을 추가해야 합니다. [시작하기](/ko/sdk/flutter/overview)를 참고하세요.
</Note>

***

## 다음 단계

<CardGroup cols={2}>
  <Card title="팝업 광고" href="/ko/sdk/flutter/popup">
    팝업 형태로 표시되는 광고 구현하기
  </Card>

  <Card title="타겟팅" href="/ko/sdk/flutter/targeting">
    맞춤형 광고를 위한 타겟팅 설정하기
  </Card>

  <Card title="레퍼런스" href="/ko/sdk/flutter/reference">
    타입, 메서드, 에러 코드 참고하기
  </Card>
</CardGroup>
