adseye_ad_plugin 1.0.9-beta.2
adseye_ad_plugin: ^1.0.9-beta.2 copied to clipboard
Adseye Flutter Plugin Project.
example/lib/main.dart
import 'dart:io';
import 'package:adseye_ad_plugin/adseye_ad_plugin.dart';
import 'package:adseye_ad_plugin_example/native_stage/ad_view_provider.dart';
import 'package:adseye_ad_plugin/src/logger.dart';
import 'package:adseye_ad_plugin_example/native_stage/base_item.dart';
import 'package:adseye_ad_plugin_example/native_stage/hiwaifu_style.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 adseye 平台
AdseyeLogger.info('开始初始化 adseye 平台');
runApp(const AdseyeDemoApp());
await AdseyeAdPlugin.initialize(
pangleAppId: '8571079',
tradPlusAppId: 'F143609D85E02070A6F84543438AF82A',
listener: AdseyeInitListener(
onPreInitSuccess: () {
print('adseye 平台提前初始化完成');
},
onInitSuccess: () {
print('adseye 平台全部初始化完成');
AdseyeLogger.info('adseye 平台初始化完成');
},
onInitFailed: (error) {
AdseyeLogger.info('adseye 平台初始化失败: $error');
},
),
);
}
class AdseyeAdHelper {
static String get appOpenAdUnitId =>
Platform.isAndroid ? '9020588' : '9020631';
static String get interstitialAdUnitId =>
Platform.isAndroid ? '9020265' : '9020643';
static String get rewardedAdUnitId =>
Platform.isAndroid ? '9020589' : '9020642';
static String get nativeAdUnitId_01 =>
Platform.isAndroid ? '9020266' : '9020648';
static String get nativeAdUnitId_02 =>
Platform.isAndroid ? '9020264' : '9020648';
}
/// 长按事件处理工具类
class LongPressHelper {
/// 创建带长按事件的按钮
static Widget createLongPressButton({
required Widget child,
required VoidCallback onPressed,
required VoidCallback onLongPress,
String? longPressMessage,
BuildContext? context,
}) {
return GestureDetector(
onLongPress: () {
onLongPress();
if (longPressMessage != null && context != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(longPressMessage),
duration: const Duration(seconds: 2),
),
);
}
},
child: ElevatedButton(onPressed: onPressed, child: child),
);
}
/// 创建带长按事件的通用容器
static Widget createLongPressContainer({
required Widget child,
required VoidCallback onLongPress,
String? longPressMessage,
BuildContext? context,
}) {
return GestureDetector(
onLongPress: () {
onLongPress();
if (longPressMessage != null && context != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(longPressMessage),
duration: const Duration(seconds: 2),
),
);
}
},
child: child,
);
}
}
class AdseyeDemoApp extends StatelessWidget {
const AdseyeDemoApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Adseye Demo App',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
// 长按开屏广告按钮时,启用 的调试模式
void showDebugger() {
AdseyeAdPlugin.openDebugger();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Adseye 广告插件演示')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
GestureDetector(
onLongPress: () {
// 长按开屏广告按钮时,启用 的调试模式
showDebugger();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('已打开 调试器'),
duration: Duration(seconds: 2),
),
);
},
child: ElevatedButton(
child: const Text('App Open Ad (开屏)'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AppOpenAdPage()),
),
),
),
const SizedBox(height: 8),
GestureDetector(
onLongPress: () {
// 长按插屏广告按钮时的响应
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('长按插屏按钮 - 可以添加调试功能'),
duration: Duration(seconds: 2),
),
);
},
child: ElevatedButton(
child: const Text('Interstitial (插屏)'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const InterstitialPage()),
),
),
),
const SizedBox(height: 8),
ElevatedButton(
child: const Text('Rewarded (激励视频)'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const RewardedPage()),
),
),
if (true) ...[
const SizedBox(height: 8),
ElevatedButton(
child: const Text('Native Ad (原生广告List)'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const FeedScreen()),
),
),
const SizedBox(height: 8),
ElevatedButton(
child: const Text('Native Ad (原生广告)'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const NativeAdPage()),
),
)
],
],
),
);
}
}
/// 开屏广告页面(使用 adseye_ad_plugin 的 SplashAd)
class AppOpenAdPage extends StatefulWidget {
const AppOpenAdPage({super.key});
@override
// ignore: library_private_types_in_public_api
_AppOpenAdPageState createState() => _AppOpenAdPageState();
}
class _AppOpenAdPageState extends State<AppOpenAdPage> {
bool _isLoading = false;
bool _isLoaded = false;
SplashAd? _splashAd;
@override
void initState() {
super.initState();
// _initAd();
}
@override
void dispose() {
super.dispose();
_splashAd?.destroy();
}
void _initAd() {
_splashAd?.destroy();
_splashAd = SplashAd.create(AdseyeAdHelper.appOpenAdUnitId);
_splashAd?.watchAdRevenue(
listener: AdRevenueListener(
onAdRevenue: (AdRevenueData data) {
print(
'🎉 Ad Revenue: slotId=${data.adSlotId}, source=${data.adSourceName}, revenue=\$${data.revenue}, currency=${data.currency}, precision=${data.precision}',
);
},
),
);
}
void _loadAd() {
if (_isLoading) return;
setState(() {
_isLoading = true;
_isLoaded = false;
});
AdseyeLogger.info('开始加载开屏广告: ${AdseyeAdHelper.appOpenAdUnitId}');
_initAd();
_splashAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
AdseyeLogger.info('[SplashAd] onAdLoaded');
setState(() {
_isLoading = false;
_isLoaded = true;
});
},
onAdLoadFailed: (String error) {
AdseyeLogger.info('[SplashAd] onAdLoadFailed $error');
setState(() {
_isLoading = false;
_isLoaded = false;
});
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('开屏广告加载失败: $error')));
},
),
);
}
void _showAd() async {
if (!_isLoaded) return;
final bool suggestShow = await _splashAd?.checkAdShowSuggestion() ?? false;
if (!suggestShow) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('不建议展示广告,已中止。'),
backgroundColor: Colors.orange,
),
);
return;
}
_splashAd?.show(
listener: SplashDisplayListener(
onAdShow: () {
AdseyeLogger.info('[SplashAd] onAdShow');
setState(() {
_isLoaded = false;
});
},
onAdClicked: () {
AdseyeLogger.info('[SplashAd] onAdClicked');
},
onAdDismiss: () {
AdseyeLogger.info('[SplashAd] onAdDismiss');
},
onAdDisplayFailed: () {
AdseyeLogger.info('[SplashAd] onAdDisplayFailed');
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('开屏广告')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 加载广告按钮
ElevatedButton(
onPressed: _isLoading ? null : _loadAd,
child: _isLoading
? Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 8),
Text('加载中...'),
],
)
: const Text('加载开屏广告'),
),
const SizedBox(height: 16),
// 展示广告按钮
ElevatedButton(
onPressed: _isLoaded ? _showAd : null,
child: const Text('展示开屏广告'),
),
],
),
),
);
}
}
/// 插屏页面(使用 adseye_ad_plugin 的 InterstitialAd)
class InterstitialPage extends StatefulWidget {
const InterstitialPage({super.key});
@override
// ignore: library_private_types_in_public_api
_InterstitialPageState createState() => _InterstitialPageState();
}
class _InterstitialPageState extends State<InterstitialPage> {
bool _isLoading = false;
bool _isLoaded = false;
InterstitialAd? _interstitialAd;
@override
void initState() {
super.initState();
// _initAd();
}
@override
void dispose() {
super.dispose();
_interstitialAd?.destroy();
}
void _initAd() {
_interstitialAd?.destroy();
_interstitialAd = InterstitialAd.create(
AdseyeAdHelper.interstitialAdUnitId,
);
_interstitialAd?.watchAdRevenue(
listener: AdRevenueListener(
onAdRevenue: (AdRevenueData data) {
print(
'🎉 Ad Revenue: slotId=${data.adSlotId}, source=${data.adSourceName}, revenue=\$${data.revenue}, currency=${data.currency}, precision=${data.precision}',
);
},
),
);
}
void _loadAd() {
if (_isLoading) return;
setState(() {
_isLoading = true;
_isLoaded = false;
});
AdseyeLogger.info('=== 开始加载插屏广告: ${AdseyeAdHelper.interstitialAdUnitId} ===');
_initAd();
// 2. 加载广告
_interstitialAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
AdseyeLogger.info('=== 插屏广告加载成功 ===');
setState(() {
_isLoading = false;
_isLoaded = true;
});
},
onAdLoadFailed: (String error) {
AdseyeLogger.info('=== 插屏广告加载失败: $error ===');
setState(() {
_isLoading = false;
_isLoaded = false;
});
// 不返回主页,只提示
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('插屏广告加载失败: $error')));
},
),
);
}
void _showAd() async {
if (_interstitialAd == null) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('请先加载广告')));
return;
}
final ready = await _interstitialAd?.isReady() ?? false;
if (!ready) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('广告尚未准备好')));
return;
}
_interstitialAd?.show(
listener: InterstitialDisplayListener(
onAdDisplayed: () {
AdseyeLogger.info('=== 插屏广告展示成功 ===');
},
onAdClicked: () {
AdseyeLogger.info('=== 插屏广告被点击 ===');
},
onAdDismissed: () {
AdseyeLogger.info('=== 插屏广告被关闭 ===');
},
onAdDisplayFailed: () {
AdseyeLogger.info('=== 插屏广告展示失败 ===');
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('插屏广告')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 加载广告按钮
ElevatedButton(
onPressed: _isLoading ? null : _loadAd,
child: _isLoading
? Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 8),
Text('加载中...'),
],
)
: const Text('加载插屏广告'),
),
const SizedBox(height: 16),
// 展示广告按钮
ElevatedButton(
onPressed: _isLoaded ? _showAd : null,
child: const Text('展示插屏广告'),
),
],
),
),
);
}
}
/// 激励视频页面(使用 adseye_ad_plugin 的 RewardedAd)
class RewardedPage extends StatefulWidget {
const RewardedPage({super.key});
@override
_RewardedPageState createState() => _RewardedPageState();
}
class _RewardedPageState extends State<RewardedPage> {
bool _isLoading = false;
bool _isLoaded = false;
int _totalReward = 0;
RewardedAd? _rewardedAd;
@override
void initState() {
super.initState();
// _initAd();
}
@override
void dispose() {
super.dispose();
_rewardedAd?.destroy();
}
void _initAd() {
_rewardedAd?.destroy();
_rewardedAd = RewardedAd.create(AdseyeAdHelper.rewardedAdUnitId);
_rewardedAd?.watchAdRevenue(
listener: AdRevenueListener(
onAdRevenue: (AdRevenueData data) {
AdseyeLogger.info(
'🎉 Ad Revenue: slotId=${data.adSlotId}, source=${data.adSourceName}, revenue=\$${data.revenue}, currency=${data.currency}, precision=${data.precision}',
);
},
),
);
}
void _loadAd() {
if (_isLoading) return;
setState(() {
_isLoading = true;
_isLoaded = false;
});
print('=== 开始加载激励视频: ${AdseyeAdHelper.rewardedAdUnitId} ===');
_initAd();
_rewardedAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
AdseyeLogger.info('=== 激励视频加载成功 ===');
setState(() {
_isLoading = false;
_isLoaded = true;
});
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('激励视频加载成功,可点击展示')));
},
onAdLoadFailed: (String error) {
AdseyeLogger.info('=== 激励视频加载失败: $error ===');
setState(() {
_isLoading = false;
_isLoaded = false;
});
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('激励视频广告加载失败: $error')));
},
),
);
}
void _showAd() async {
if (!_isLoaded || _rewardedAd == null) return;
final ready = await _rewardedAd!.isReady();
if (!ready) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('激励视频未准备好,无法展示')));
return;
}
_rewardedAd?.show(
listener: RewardedDisplayListener(
onAdDisplayed: () {
AdseyeLogger.info('=== 激励视频展示成功 ===');
},
onAdClicked: () {
AdseyeLogger.info('=== 激励视频被点击 ===');
},
onAdDismissed: () {
AdseyeLogger.info('=== 激励视频被关闭 ===');
},
onAdVideoCompleted: () {
AdseyeLogger.info('=== 激励视频播放完成 ===');
},
onAdVideoStart: () {
AdseyeLogger.info('=== 激励视频播放开始 ===');
},
onAdDisplayFailed: () {
AdseyeLogger.info('=== 激励视频展示失败 ===');
},
onAdRewarded: () {
AdseyeLogger.info('=== 激励视频获得奖励 ===');
setState(() => _totalReward += 1);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('获得奖励:1 金币')));
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('激励视频广告')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('累计奖励:$_totalReward'),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoading ? null : _loadAd,
child: _isLoading
? Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 8),
Text('加载中...'),
],
)
: const Text('加载激励视频'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoaded ? _showAd : null,
child: const Text('展示激励视频'),
),
],
),
),
);
}
}
class FeedScreen extends StatefulWidget {
const FeedScreen({super.key});
@override
State<FeedScreen> createState() => _FeedScreenState();
}
class _FeedScreenState extends State<FeedScreen> {
// 这个列表将持有我们所有的内容和广告数据
final List<ListItem> _items = [];
late final AdViewProvider _adViewProvider;
@override
void initState() {
super.initState();
_adViewProvider = AdViewProvider(maxPoolSize: 3);
_generateMockData();
}
// 生成一个混合了内容和广告的模拟数据列表
void _generateMockData() {
// 假设你有3个不同的广告位ID
final adUnitIdStyle1 = AdseyeAdHelper.nativeAdUnitId_01;
final adUnitIdStyle2 = AdseyeAdHelper.nativeAdUnitId_02;
final List<Map<String, String>> adTemplates = [
{'templateId': 'retrain_dialog_style', 'adUnitId': adUnitIdStyle1},
{'templateId': 'reboot_head_stle', 'adUnitId': adUnitIdStyle2},
{'templateId': 'big_media_style', 'adUnitId': adUnitIdStyle1},
];
int adCounter = 0;
for (int i = 0; i < 300; i++) {
// 1. 先添加内容项
_items.add(
ContentItem(
'Article Title #${i + 1}', // 标题从1开始
'This is the body of the article, showing some interesting content.',
),
);
if (i % 10 == 0) {
final adInfo = adTemplates[adCounter % adTemplates.length];
_items.add(
AdItem(
templateId: adInfo['templateId']!,
adUnitId: adInfo['adUnitId']!,
),
);
adCounter++; // 广告计数器增加
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter Native Ads Feed')),
body: ListView.builder(
cacheExtent: MediaQuery.of(context).size.height * 1.3,
// 列表的总长度就是我们数据列表的长度
itemCount: _items.length,
// itemBuilder 会为列表中的每一项构建一个 Widget
itemBuilder: (context, index) {
final item = _items[index];
// 关键逻辑:检查当前项的类型
if (item is AdItem) {
// 我们把 templateId 和 adUnitId 传递进去
return NativeAdCard(
key: ValueKey('ad_${item.adUnitId}_$index'),
templateId: item.templateId,
nativeAdUnitId: item.adUnitId,
);
} else if (item is ContentItem) {
// 如果是内容项,就创建一个简单的 Card + ListTile
return Card(
margin: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 12.0,
),
child: ListTile(
title: Text(
item.title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(item.body),
isThreeLine: true,
),
);
}
// 理论上不会走到这里,但作为安全措施返回一个空容器
return const SizedBox.shrink();
},
),
);
}
@override
void dispose() {
super.dispose();
}
}
/// 原生广告页面
class NativeAdPage extends StatefulWidget {
const NativeAdPage({super.key});
@override
State<NativeAdPage> createState() => _NativeAdPageState();
}
class _NativeAdPageState extends State<NativeAdPage> {
NativeAd? _nativeAd;
bool _isLoading = false;
String? _loadError;
bool _adLoaded = false;
bool _adShown = false;
@override
void initState() {
super.initState();
}
void _loadAd() {
setState(() {
_isLoading = true;
_loadError = null;
_adLoaded = false;
_adShown = false;
_nativeAd?.destroy();
_nativeAd = null;
});
final ad = NativeAd.create(AdseyeAdHelper.nativeAdUnitId_01);
ad.setDisplayListener(MainNativeAdDisplayListener());
ad.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
AdseyeLogger.info("[NativeAdPage] 广告数据加载成功!");
if (mounted) {
setState(() {
_nativeAd = ad;
_isLoading = false;
_loadError = null;
_adLoaded = true;
});
}
},
onAdLoadFailed: (error) {
AdseyeLogger.info("[NativeAdPage] 广告数据加载失败: $error");
if (mounted) {
setState(() {
_isLoading = false;
_loadError = error;
_adLoaded = false;
_adShown = false;
});
ad.destroy();
}
},
),
);
}
void _showAd() {
setState(() {
_adShown = true;
});
}
@override
void dispose() {
_nativeAd?.destroy();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('上图下文原生广告')),
body: Center(child: _buildBody()),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: 'load',
onPressed: _loadAd,
tooltip: '加载广告',
child: const Icon(Icons.download),
),
const SizedBox(width: 16),
FloatingActionButton(
heroTag: 'show',
onPressed: _adLoaded && !_adShown ? _showAd : null,
tooltip: '展示广告',
child: const Icon(Icons.visibility),
),
],
),
);
}
Widget _buildBody() {
print(
"[_buildBody] Called. isLoading: $_isLoading, loadError: $_loadError, nativeAd is null: [38;5;208m${_nativeAd == null} [0m, adLoaded: $_adLoaded, adShown: $_adShown",
);
if (_isLoading) {
return const CircularProgressIndicator();
}
if (_loadError != null) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'广告加载失败:\n$_loadError',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red),
),
);
}
if (_adShown && _nativeAd != null) {
return AdseyeNativeAdViewContainer(
ad: _nativeAd!,
onLayoutFailed: () => {AdseyeLogger.info("on Layout Failed")},
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AspectRatio(aspectRatio: 16 / 9, child: AdseyeNativeMediaView()),
const SizedBox(height: 12),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AdseyeNativeIconView(
width: 50,
height: 50,
borderRadius: BorderRadius.circular(8),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AdseyeNativeTitleView(
height: 22.0,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
const SizedBox(height: 4),
AdseyeNativeBodyView(
height: 38.0,
style: const TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
],
),
),
const SizedBox(width: 6),
AdseyeNativeCTAView(
width: 90.0,
height: 55.0,
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 12,
),
backgroundColor: Colors.blue,
borderRadius: BorderRadius.circular(6),
style: const TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
),
);
}
if (_adLoaded && !_adShown) {
return const Text('广告已加载,请点击“展示广告”按钮显示广告');
}
return const Text("请点击右下角按钮加载广告");
}
}
// *** 5. 创建一个独立的监听器类,处理展示相关的回调 ***
class MainNativeAdDisplayListener implements NativeAdDisplayListener {
@override
void onAdClicked() {
AdseyeLogger.info("[MyNativeAdDisplayListener] 广告被点击。");
}
@override
void onAdDisplayFailed(String errorMsg) {
AdseyeLogger.info("[MyNativeAdDisplayListener] 广告展示失败: $errorMsg");
}
@override
void onAdShow() {
AdseyeLogger.info("[MyNativeAdDisplayListener] 广告成功渲染展示!");
}
}