Flutter InAppWebView 연동
Flutter inappWebView를 사용하는 환경에서의 연동 지원 가이드
Flutter InAppWebView를 사용하는 개발 환경에서 전면, 전면 비디오, 리워드 비디오, 비디오 믹스를 연동하고자 할 경우에는 아래의 과정으로 연동을 진행합니다.
1. 기본 준비사항
1.1 flutter plugin 설치
아래 연동 진행을 위해서는 애드팝콘에서 제공하는 adpopcornssp_flutter 플러그인 설치는 필수입니다.
아래 링크의 가이드를 보고 adpopcornssp_flutter 를 설치하세요.
Flutter1.2 flutter_inappwebview 선언 및 연결
아래 샘플을 참고하여, AdPopcornInAppWebViewBridgeHandler에 InAppWebViewController 를 연결합니다.
late AdPopcornInAppWebViewBridgeHandler bridgeHandler;
InAppWebViewController? webViewController;
...
@override
void initState() {
super.initState();
bridgeHandler = AdPopcornInAppWebViewBridgeHandler();
}
....
@override
Widget build(BuildContext context){
onWebViewCreated: (controller) {
webViewController = controller;
bridgeHandler.setWebViewController(controller);
bridgeHandler.registerJavaScriptHandlers(controller);
},
}
...
전체 예시>
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/services.dart';
import 'package:adpopcornssp_flutter/adpopcornssp_flutter.dart';
import 'adpopcornssp_flutter_inappwebview_handler.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'dart:convert';
void main() {
runApp(const AdPopcornWebViewPage());
}
class AdPopcornWebViewPage extends StatefulWidget {
const AdPopcornWebViewPage({super.key});
@override
State<AdPopcornWebViewPage> createState() => _AdPopcornWebViewPageState();
}
class _AdPopcornWebViewPageState extends State<AdPopcornWebViewPage> {
InAppWebViewController? webViewController;
late AdPopcornInAppWebViewBridgeHandler bridgeHandler;
bool isLoading = true;
String eventLog = '';
@override
void initState() {
super.initState();
bridgeHandler = AdPopcornInAppWebViewBridgeHandler();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('AdPopcorn SSP Test'),
backgroundColor: const Color(0xFF667EEA),
actions: [
if (isLoading)
const Padding(
padding: EdgeInsets.all(16.0),
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
webViewController?.reload();
},
),
],
),
body: InAppWebView(
initialData: InAppWebViewInitialData(
data: _generateHtmlContent(),
),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
javaScriptEnabled: true,
useShouldOverrideUrlLoading: false,
clearCache: false,
cacheEnabled: true,
supportZoom: true,
useOnLoadResource: false,
useOnDownloadStart: false,
mediaPlaybackRequiresUserGesture: false,
),
android: AndroidInAppWebViewOptions(
useHybridComposition: true,
domStorageEnabled: true,
allowContentAccess: true,
allowFileAccess: true,
useWideViewPort: true,
loadWithOverviewMode: true,
builtInZoomControls: true,
displayZoomControls: false,
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
allowsBackForwardNavigationGestures: true,
),
),
onWebViewCreated: (controller) {
webViewController = controller;
bridgeHandler.setWebViewController(controller);
bridgeHandler.registerJavaScriptHandlers(controller);
},
onLoadStart: (controller, url) {
setState(() {
isLoading = true;
});
},
onLoadStop: (controller, url) {
setState(() {
isLoading = false;
});
},
onLoadError: (controller, url, code, message) {
setState(() {
isLoading = false;
});
},
onLoadHttpError: (controller, url, statusCode, description) {
setState(() {
isLoading = false;
});
},
onConsoleMessage: (controller, consoleMessage) {
print('Console: ${consoleMessage.message}');
},
),
));
}
1.3 adpopcornssp_flutter_inappwebview_handler.dart 추가
import 'package:flutter/services.dart';
import 'dart:convert';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:adpopcornssp_flutter/adpopcornssp_flutter.dart';
class AdPopcornInAppWebViewBridgeHandler {
InAppWebViewController? _webViewController;
AdPopcornInAppWebViewBridgeHandler();
void setWebViewController(InAppWebViewController controller) {
_webViewController = controller;
}
String returnMessageFormat(String eventName, Map<String, dynamic> eventData) {
final messageMap = {
"EventName": eventName,
"Data": jsonEncode(eventData),
};
return jsonEncode(messageMap);
}
String publishEvent(String functionName, String data) {
final jsonStringLiteral = jsonEncode(data);
return """
(function() {
try {
const event = new CustomEvent("$functionName", {
detail: { data: $jsonStringLiteral }
});
window.dispatchEvent(event);
} catch(e) {
console.error('Error dispatching event:', e);
}
})();
""";
}
void _handleNativeEvent(String data) {
if (_webViewController != null) {
_webViewController!.evaluateJavascript(
source: publishEvent("NativeEvent", data),
);
}
}
void registerJavaScriptHandlers(InAppWebViewController controller) {
_webViewController = controller;
controller.addJavaScriptHandler(
handlerName: 'init',
callback: (args) {
String appKey = args[0] as String;
AdPopcornSSP.init(appKey);
AdPopcornSSP.onInitializeListener = () {
_handleNativeEvent(returnMessageFormat("AdPopcornSSPSDKDidInitialize", {}));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'setUserId',
callback: (args) {
String userId = args[0] as String;
AdPopcornSSP.setUserId(userId);
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'loadInterstitial',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.loadInterstitial(appKey, placementId);
AdPopcornSSP.interstitialAdLoadSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
print('[AdPopcornSSP] interstitialAdLoadSuccessListener called: $placementId');
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdLoadSuccess", dataJson));
};
AdPopcornSSP.interstitialAdLoadFailListener = (placementId, errorCode) {
final dataJson = {
"placementId": placementId,
"errorCode": errorCode
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdLoadFail", dataJson));
};
print('[AdPopcornSSP] loadInterstitial called: $placementId');
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'showInterstitial',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.showInterstitial(appKey, placementId);
AdPopcornSSP.interstitialAdShowSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdShowSuccess", dataJson));
};
AdPopcornSSP.interstitialAdShowFailListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdShowFail", dataJson));
};
AdPopcornSSP.interstitialAdClickedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdClicked", dataJson));
};
AdPopcornSSP.interstitialAdClosedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialAdClosed", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'loadInterstitialVideo',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.loadInterstitialVideo(appKey, placementId);
AdPopcornSSP.interstitialVideoAdLoadSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialVideoAdLoadSuccess", dataJson));
};
AdPopcornSSP.interstitialVideoAdLoadFailListener = (placementId, errorCode) {
final dataJson = {
"placementId": placementId,
"errorCode": errorCode
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialVideoAdLoadFail", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'showInterstitialVideo',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.showInterstitialVideo(appKey, placementId);
AdPopcornSSP.interstitialVideoAdShowSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialVideoAdShowSuccess", dataJson));
};
AdPopcornSSP.interstitialVideoAdShowFailListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialVideoAdShowFail", dataJson));
};
AdPopcornSSP.interstitialVideoAdClosedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPInterstitialVideoAdClosed", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'loadRewardVideo',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.loadRewardVideo(appKey, placementId);
AdPopcornSSP.rewardVideoAdLoadSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdLoadSuccess", dataJson));
};
AdPopcornSSP.rewardVideoAdLoadFailListener = (placementId, errorCode) {
final dataJson = {
"placementId": placementId,
"errorCode": errorCode
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdLoadFail", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'showRewardVideo',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.showRewardVideo(appKey, placementId);
AdPopcornSSP.rewardVideoAdShowSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdShowSuccess", dataJson));
};
AdPopcornSSP.rewardVideoAdShowFailListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdShowFail", dataJson));
};
AdPopcornSSP.rewardVideoAdClosedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdClosed", dataJson));
};
AdPopcornSSP.rewardVideoAdCompletedListener = (placementId, adNetworkNo, completed) {
final dataJson = {
"placementId": placementId,
"adNetworkNo": adNetworkNo,
"completed": completed
};
_handleNativeEvent(returnMessageFormat("APSSPRewardVideoAdPlayCompleted", dataJson));
};
AdPopcornSSP.rewardPlusCompletedListener = (result, resultCode, reward) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPRewardPlusCompleted", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'loadVideoMix',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.loadVideoMix(appKey, placementId);
AdPopcornSSP.videoMixAdLoadSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdLoadSuccess", dataJson));
};
AdPopcornSSP.videoMixAdLoadFailListener = (placementId, errorCode) {
final dataJson = {
"placementId": placementId,
"errorCode": errorCode
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdLoadFail", dataJson));
};
return null;
},
);
controller.addJavaScriptHandler(
handlerName: 'showVideoMix',
callback: (args) {
String appKey = args[0] as String;
String placementId = args[1] as String;
AdPopcornSSP.showVideoMix(appKey, placementId);
AdPopcornSSP.videoMixAdShowSuccessListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdShowSuccess", dataJson));
};
AdPopcornSSP.videoMixAdShowFailListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdShowFail", dataJson));
};
AdPopcornSSP.videoMixAdClosedListener = (placementId, campaignType) {
final dataJson = {
"placementId": placementId,
"campaignType": campaignType
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdClosed", dataJson));
};
AdPopcornSSP.videoMixAdCompletedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdPlayCompleted", dataJson));
};
AdPopcornSSP.videoMixAdClickedListener = (placementId) {
final dataJson = {
"placementId": placementId
};
_handleNativeEvent(returnMessageFormat("APSSPVideoMixAdClicked", dataJson));
};
return null;
},
);
}
}
2. 웹 Javacript API 연동
위의 기본 연동이 끝난 상태에서 실제 웹 페이지에선 아래의 API를 호출하여 광고 연동 및 이벤트 연동을 진행 합니다.
2.1 전면 광고
2.1.1 전면 광고 요청
전면 형태의 광고 요청이 필요할 때 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('loadInterstitial', APP_KEY, PLACEMENT_ID_INTERSTITIAL);
appKey : 앱키
placementId: 지면키
2.1.2 전면 광고 노출
전면 광고 노출 시 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('showInterstitial', APP_KEY, PLACEMENT_ID_INTERSTITIAL);
appKey : 앱키
placementId: 지면키
2.1.3 전면 광고 이벤트
전면 광고 관련 이벤트를 받고자 할 때 사용됩니다.
<body>
<!-- ... -->
<script>
window.addEventListener('NativeEvent', function(event) {
const eventDataString = event.detail.data;
let eventObject = null;
if (typeof eventDataString === 'string') {
try {
eventObject = JSON.parse(eventDataString);
} catch (e) {
console.error('JSON parsing failed:', e);
console.log('Failed to parse string:', eventDataString);
}
}
if (eventObject) {
console.log('EventName received:', eventObject.EventName);
logEvent('Received', eventObject);
handleAdEvent(eventObject);
}
});
</script>
</body>
지원되는 EventName
APSSPInterstitialAdLoadSuccess : 전면 광고 로드 성공
placementId
APSSPInterstitialAdLoadFail : 전면 광고 로드 실패
placementId
errorCode
APSSPInterstitialAdShowSuccess : 전면 광고 노출 성공
placementId
APSSPInterstitialAdShowFail : 전면 광고 노출 실패
placementId
APSSPInterstitialAdClosed : 전면 광고 닫기
placementId
APSSPInterstitialAdClicked : 전면 광고 클릭
placementId
2.2 전면 비디오 광고
2.2.1 전면 비디오광고 요청
전면 형태의 비디오광고 요청이 필요할 때 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('loadInterstitialVideo', APP_KEY, PLACEMENT_ID_INTERSTITIAL_VIDEO);
appKey : 앱키
placementId: 지면키
2.2.2 전면 비디오광고 노출
전면 비디오광고 노출 시 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('showInterstitialVideo', APP_KEY, PLACEMENT_ID_INTERSTITIAL_VIDEO);
appKey : 앱키
placementId: 지면키
2.2.3 전면 비디오 광고 이벤트
전면 비디오광고 관련 이벤트를 받고자 할 때 사용됩니다.
<body>
<!-- ... -->
<script>
window.addEventListener('NativeEvent', function(event) {
const eventDataString = event.detail.data;
let eventObject = null;
if (typeof eventDataString === 'string') {
try {
eventObject = JSON.parse(eventDataString);
} catch (e) {
console.error('JSON parsing failed:', e);
console.log('Failed to parse string:', eventDataString);
}
}
if (eventObject) {
console.log('EventName received:', eventObject.EventName);
logEvent('Received', eventObject);
handleAdEvent(eventObject);
}
});
</script>
</body>
지원되는 이벤트
APSSPInterstitialVideoAdLoadSuccess : 전면 비디오 광고 로드 성공
placementId
APSSPInterstitialVideoAdLoadFail : 전면 비디오 광고 로드 실패
placementId
errorCode
APSSPInterstitialVideoAdShowSuccess : 전면 비디오 광고 노출 성공
placementId
APSSPInterstitialVideoAdShowFail : 전면 비디오 광고 노출 실패
placementId
errorCode
APSSPInterstitialVideoAdClosed : 전면 비디오 광고 닫기
placementId
2.3 리워드 비디오 광고
2.3.1 리워드 비디오광고 요청
리워드 비디오광고 요청이 필요할 때 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('loadRewardVideo', APP_KEY, PLACEMENT_ID_REWARD_VIDEO);
appKey : 앱키
placementId: 지면키
2.3.2 리워드 비디오광고 노출
리워드 비디오광고 노출 시 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('showRewardVideo', APP_KEY, PLACEMENT_ID_REWARD_VIDEO);
appKey : 앱키
placementId: 지면키
2.3.3 리워드비디오 광고 이벤트
리워드비디오광고 관련 이벤트를 받고자 할 때 사용됩니다.
<body>
<!-- ... -->
<script>
window.addEventListener('NativeEvent', function(event) {
const eventDataString = event.detail.data;
let eventObject = null;
if (typeof eventDataString === 'string') {
try {
eventObject = JSON.parse(eventDataString);
} catch (e) {
console.error('JSON parsing failed:', e);
console.log('Failed to parse string:', eventDataString);
}
}
if (eventObject) {
console.log('EventName received:', eventObject.EventName);
logEvent('Received', eventObject);
handleAdEvent(eventObject);
}
});
</script>
</body>
지원되는 이벤트
APSSPRewardVideoAdLoadSuccess : 리워드비디오 광고 로드 성공
placementId
APSSPRewardVideoAdLoadFail : 리워드 비디오 광고 로드 실패
placementId
errorCode
APSSPRewardVideoAdShowSuccess : 리워드 비디오 광고 노출 성공
placementId
APSSPRewardVideoAdShowFail : 리워드 비디오 광고 노출 실패
placementId
errorCode
APSSPRewardVideoAdPlayCompleted : 리워드 비디오 광고 재생 완료
placementId
adNetworkNo
completed
APSSPRewardVideoAdClosed : 리워드 비디오 광고 닫기
placementId
2.4 비디오 믹스 광고
2.4.1 비디오 믹스광고 요청
비디오 믹스 광고 요청이 필요할 때 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('loadVideoMix', APP_KEY, PLACEMENT_ID_VIDEO_MIX);
appKey : 앱키
placementId: 지면키
2.4.2 비디오 믹스광고 노출
비디오 믹스광고 노출 시 사용되는 API 입니다.
window.flutter_inappwebview.callHandler('showVideoMix', APP_KEY, PLACEMENT_ID_VIDEO_MIX);
appKey : 앱키
placementId: 지면키
2.4.3 비디오 믹스광고 이벤트
비디오 믹스광고 관련 이벤트를 받고자 할 때 사용됩니다.
<body>
<!-- ... -->
<script>
window.addEventListener('NativeEvent', function(event) {
const eventDataString = event.detail.data;
let eventObject = null;
if (typeof eventDataString === 'string') {
try {
eventObject = JSON.parse(eventDataString);
} catch (e) {
console.error('JSON parsing failed:', e);
console.log('Failed to parse string:', eventDataString);
}
}
if (eventObject) {
console.log('EventName received:', eventObject.EventName);
logEvent('Received', eventObject);
handleAdEvent(eventObject);
}
});
</script>
</body>
지원되는 이벤트
APSSPVideoMixAdLoadSuccess : 비디오 믹스 광고 로드 성공
placementId
APSSPVideoMixAdLoadFail : 비디오 믹스광고 로드 실패
placementId
errorCode
APSSPVideoMixAdShowSuccess : 비디오 믹스광고 노출 성공
placementId
APSSPVideoMixAdShowFail : 비디오 믹스광고 노출 실패
placementId
errorCode
APSSPVideoMixAdPlayCompleted : 비디오 믹스광고 재생 완료
placementId
APSSPVideoMixAdClosed : 비디오 믹스광고 닫기
placementId
campaignType : 2(전면), 4(리워드 비디오), 6(전면 비디오)
APSSPVideoMixAdClicked : 비디오 믹스 광고 클릭
placementId
Last updated
Was this helpful?