> ## 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.

# WebView 가이드

> Flutter WebView에서 백필 광고를 표시하는 방법

## 개요

Flutter 앱의 WebView에서 `Adrop.registerWebView`를 사용하여 백필 광고를 표시할 수 있습니다.

***

## 사전 요구사항

프로젝트에 다음 패키지를 추가하세요:

```bash theme={null}
flutter pub add webview_flutter webview_flutter_android webview_flutter_wkwebview
```

<Warning>
  WebView 백필 광고는 Android와 iOS 모두에서 `adrop-ads-backfill` 설정이 필요합니다. 설정 방법은 [시작하기](/ko/sdk/flutter/overview)를 참고하세요.
</Warning>

***

## 플랫폼 설정

WebView에서 백필 광고를 활성화하려면 네이티브 플랫폼 설정이 필요합니다.

<Tabs>
  <Tab title="Android">
    `android/app/src/main/AndroidManifest.xml`에 다음을 추가하세요:

    ```xml AndroidManifest.xml theme={null}
    <manifest>
        <application>
            <!-- WebView 백필 광고 통합 -->
            <meta-data
                android:name="com.google.android.gms.ads.INTEGRATION_MANAGER"
                android:value="webview"/>
        </application>
    </manifest>
    ```
  </Tab>

  <Tab title="iOS">
    `ios/Runner/Info.plist`에 다음 키를 추가하세요:

    ```xml Info.plist theme={null}
    <key>GADIntegrationManager</key>
    <string>webview</string>
    ```
  </Tab>
</Tabs>

<Warning>
  이 설정은 WebView에서 백필 광고가 정상적으로 작동하는 데 필요합니다. 설정이 없으면 백필 광고가 표시되지 않을 수 있습니다.
</Warning>

***

## WebView 등록

`WebViewController`를 생성하고, 플랫폼별 식별자를 추출한 후, 콘텐츠를 로드하기 전에 `Adrop.registerWebView`로 등록하세요.

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

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

  @override
  State<WebViewScreen> createState() => _WebViewScreenState();
}

class _WebViewScreenState extends State<WebViewScreen> {
  late final WebViewController _controller;
  bool _isReady = false;

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

    final PlatformWebViewControllerCreationParams params;
    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      params = WebKitWebViewControllerCreationParams(
        allowsInlineMediaPlayback: true,
        mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
      );
    } else {
      params = const PlatformWebViewControllerCreationParams();
    }

    _controller = WebViewController.fromPlatformCreationParams(params)
      ..setJavaScriptMode(JavaScriptMode.unrestricted);

    _registerAndLoad();
  }

  Future<void> _registerAndLoad() async {
    final int identifier;
    if (Platform.isAndroid) {
      identifier =
          (_controller.platform as AndroidWebViewController).webViewIdentifier;
    } else if (Platform.isIOS) {
      identifier =
          (_controller.platform as WebKitWebViewController).webViewIdentifier;
    } else {
      return;
    }

    await Adrop.registerWebView(identifier);

    setState(() => _isReady = true);
    _controller.loadRequest(Uri.parse('https://your-website.com'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _isReady
          ? WebViewWidget(controller: _controller)
          : const Center(child: CircularProgressIndicator()),
    );
  }
}
```

***

## WebView 식별자 추출

`webViewIdentifier`는 플랫폼별로 다르게 추출합니다:

| 플랫폼     | 컨트롤러                       | 프로퍼티                 |
| ------- | -------------------------- | -------------------- |
| Android | `AndroidWebViewController` | `.webViewIdentifier` |
| iOS     | `WebKitWebViewController`  | `.webViewIdentifier` |

```dart theme={null}
if (Platform.isAndroid) {
  identifier =
      (_controller.platform as AndroidWebViewController).webViewIdentifier;
} else if (Platform.isIOS) {
  identifier =
      (_controller.platform as WebKitWebViewController).webViewIdentifier;
}
```

<Note>
  `Adrop.registerWebView()`는 웹 콘텐츠를 로드하기 전에 호출하세요. 등록이 완료된 후에 URL을 로드해야 합니다.
</Note>

***

## iOS WebView 설정

iOS에서는 `WebKitWebViewControllerCreationParams`를 사용하여 인라인 미디어 재생을 설정하세요:

```dart theme={null}
final params = WebKitWebViewControllerCreationParams(
  allowsInlineMediaPlayback: true,
  mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);

_controller = WebViewController.fromPlatformCreationParams(params)
  ..setJavaScriptMode(JavaScriptMode.unrestricted);
```

<Warning>
  WebView 백필 광고는 `adrop-ads-backfill` 모듈이 필요합니다. 모듈이 설치되지 않은 경우 `registerWebView()`는 무시됩니다.
</Warning>

***

## 외부 URL 처리

앱에서 자사 도메인이 아닌 URL을 외부 브라우저로 여는 로직이 있는 경우, 광고 리소스 요청(예: `googleads.g.doubleclick.net`)이 차단되지 않도록 해야 합니다.

광고 리소스(iframe, 스크립트 등)는 광고 SDK가 자동으로 로드하며, 사용자가 직접 클릭한 것이 아닙니다. **메인 프레임 이동에 한해서만** 외부 브라우저로 전환하세요.

```dart theme={null}
import 'package:url_launcher/url_launcher.dart';

const allowedHost = 'my-domain.com';

_controller = WebViewController.fromPlatformCreationParams(params)
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..setNavigationDelegate(
    NavigationDelegate(
      onNavigationRequest: (NavigationRequest request) {
        final host = Uri.parse(request.url).host;

        // 메인 프레임 이동에 한해서만 외부 브라우저로 이동
        // 광고 리소스(예: googleads.g.doubleclick.net)는 iframe/스크립트로 로드되므로 차단하지 않음
        if (!host.contains(allowedHost) && request.isMainFrame) {
          launchUrl(Uri.parse(request.url), mode: LaunchMode.externalApplication);
          return NavigationDecision.prevent;
        }
        return NavigationDecision.navigate;
      },
    ),
  );
```

<Warning>
  자사 도메인이 아닌 모든 요청을 차단하거나 리다이렉트하지 마세요. `googleads.g.doubleclick.net` 같은 광고 리소스는 백필 광고 과정에서 자동으로 로드되며, WebView 내에서 정상적으로 로드되어야 합니다.
</Warning>

***

## 관련 문서

<CardGroup cols={2}>
  <Card title="배너 광고" icon="rectangle-ad" href="/ko/sdk/flutter/banner">
    배너 광고 연동 방법
  </Card>

  <Card title="레퍼런스" icon="book" href="/ko/sdk/flutter/reference">
    API 레퍼런스
  </Card>

  <Card title="예제" icon="code" href="/ko/sdk/flutter/examples">
    예제 코드
  </Card>
</CardGroup>
