adseye_ad_plugin 1.0.1-dev.1
adseye_ad_plugin: ^1.0.1-dev.1 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/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 平台
print('开始初始化 adseye 平台');
await AdseyeAdPlugin.initialize(
listener: AdseyeInitListener(
onInitSuccess: () {
print('adseye 平台初始化完成');
},
onInitFailed: (error) {
print('adseye 平台初始化失败: $error');
},
),
);
runApp(const AdseyeDemoApp());
}
// class AdseyeAdHelper {
// static String get appOpenAdUnitId =>
// Platform.isAndroid ? '9020591' : 'IOS_APP_OPEN_AD_UNIT_ID';
// static String get interstitialAdUnitId =>
// Platform.isAndroid ? '9020594' : 'IOS_INTERSTITIAL_AD_UNIT_ID';
// static String get rewardedAdUnitId =>
// Platform.isAndroid ? '9020595' : 'IOS_REWARDED_AD_UNIT_ID';
// static String get nativeAdUnitId_01 =>
// Platform.isAndroid ? '9020596' : 'IOS_NATIVE_AD_UNIT_ID';
// static String get nativeAdUnitId_02 =>
// Platform.isAndroid ? '9020592' : 'IOS_NATIVE_AD_UNIT_ID';
// }
class AdseyeAdHelper {
static String get appOpenAdUnitId =>
Platform.isAndroid ? '9020588' : 'IOS_APP_OPEN_AD_UNIT_ID';
static String get interstitialAdUnitId =>
Platform.isAndroid ? '9020265' : 'IOS_INTERSTITIAL_AD_UNIT_ID';
static String get rewardedAdUnitId =>
Platform.isAndroid ? '9020589' : 'IOS_REWARDED_AD_UNIT_ID';
static String get nativeAdUnitId_01 =>
Platform.isAndroid ? '9020266' : 'IOS_NATIVE_AD_UNIT_ID';
static String get nativeAdUnitId_02 =>
Platform.isAndroid ? '9020264' : 'IOS_NATIVE_AD_UNIT_ID';
}
/// 长按事件处理工具类
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()),
),
),
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 = true;
SplashAd? _splashAd;
@override
void initState() {
super.initState();
_loadAndShow();
}
void _loadAndShow() {
print('开始加载开屏广告: ${AdseyeAdHelper.appOpenAdUnitId}');
// 1. 创建 SplashAd 实例
_splashAd = SplashAd.create(AdseyeAdHelper.appOpenAdUnitId);
_splashAd?.watchAdRevenue(
listener: AdRevenueListener(
onAdRevenue: (AdRevenueData data) {
print('🎉 Ad Revenue: source=${data.adSourceName}, revenue=\$${data.revenue}, currency=${data.currency}, precision=${data.precision}');
},
),
);
// 2. 加载广告
_splashAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
print('[SplashAd] onAdLoaded');
// 加载成功后展示
_splashAd?.show(
listener: SplashDisplayListener(
onAdShow: () {
print('[SplashAd] onAdShow');
setState(() => _isLoading = false);
},
onAdClicked: () {
print('[SplashAd] onAdClicked');
Navigator.pop(context);
},
onAdDismiss: () {
print('[SplashAd] onAdDismiss');
Navigator.pop(context);
},
onAdDisplayFailed: () {
print('[SplashAd] onAdDisplayFailed');
Navigator.pop(context);
},
),
);
},
onAdLoadFailed: (String error) {
print('[SplashAd] onAdLoadFailed $error');
Navigator.pop(context);
// 给用户一个小弹窗提示加载失败
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('开屏广告加载失败: $error')));
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _isLoading
? const CircularProgressIndicator()
: 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 = true;
InterstitialAd? _interstitialAd;
@override
void initState() {
super.initState();
_loadAndShow();
}
void _loadAndShow() {
print('=== 开始加载插屏广告: ${AdseyeAdHelper.interstitialAdUnitId} ===');
// 1. 创建 InterstitialAd 实例
_interstitialAd = InterstitialAd.create(
AdseyeAdHelper.interstitialAdUnitId,
);
// 2. 加载广告
_interstitialAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
print('=== 插屏广告加载成功 ===');
setState(() => _isLoading = false);
// 加载成功后展示
_interstitialAd?.show(
listener: InterstitialDisplayListener(
onAdDisplayed: () {
print('=== 插屏广告展示成功 ===');
},
onAdClicked: () {
print('=== 插屏广告被点击 ===');
},
onAdDismissed: () {
print('=== 插屏广告被关闭 ===');
Navigator.pop(context);
},
onAdDisplayFailed: () {
print('=== 插屏广告展示失败 ===');
Navigator.pop(context);
},
),
);
},
onAdLoadFailed: (String error) {
Navigator.pop(context);
print('=== 插屏广告加载失败: $error ===');
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('插屏广告加载失败: $error')));
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('插屏广告')),
body: Center(
child: _isLoading
? const CircularProgressIndicator()
: const Text('广告已展示'),
),
);
}
}
/// 激励视频页面(使用 adseye_ad_plugin 的 RewardedAd)
class RewardedPage extends StatefulWidget {
const RewardedPage({super.key});
@override
// ignore: library_private_types_in_public_api
_RewardedPageState createState() => _RewardedPageState();
}
class _RewardedPageState extends State<RewardedPage> {
bool _isLoading = true;
int _totalReward = 0;
RewardedAd? _rewardedAd;
@override
void initState() {
super.initState();
_loadAndShow();
}
void _loadAndShow() {
print('=== 开始加载激励视频: ${AdseyeAdHelper.rewardedAdUnitId} ===');
// 1. 创建 RewardedAd 实例
_rewardedAd = RewardedAd.create(AdseyeAdHelper.rewardedAdUnitId);
// 2. 加载广告
_rewardedAd?.load(
listener: AdseyeLoadListener(
onAdLoaded: () {
print('=== 激励视频加载成功 ===');
setState(() => _isLoading = false);
// 加载成功后展示
_rewardedAd?.show(
listener: RewardedDisplayListener(
onAdDisplayed: () {
print('=== 激励视频展示成功 ===');
},
onAdClicked: () {
print('=== 激励视频被点击 ===');
},
onAdDismissed: () {
print('=== 激励视频被关闭 ===');
Navigator.pop(context);
},
onAdVideoCompleted: () {
print('=== 激励视频播放完成 ===');
},
onAdVideoStart: () {
print('=== 激励视频播放开始 ===');
},
onAdDisplayFailed: () {
print('=== 激励视频展示失败 ===');
Navigator.pop(context);
},
onAdRewarded: () {
print('=== 激励视频获得奖励 ===');
setState(() => _totalReward += 1);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('获得奖励:1 金币')));
},
),
);
},
onAdLoadFailed: (String error) {
print('=== 激励视频加载失败: $error ===');
Navigator.pop(context);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('激励视频广告加载失败: $error')));
},
),
);
}
@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),
_isLoading
? const CircularProgressIndicator()
: const Text('广告已展示'),
],
),
),
);
}
}
class FeedScreen extends StatefulWidget {
const FeedScreen({super.key});
@override
State<FeedScreen> createState() => _FeedScreenState();
}
class _FeedScreenState extends State<FeedScreen> {
// 这个列表将持有我们所有的内容和广告数据
final List<ListItem> _items = [];
@override
void initState() {
super.initState();
_generateMockData();
}
// 生成一个混合了内容和广告的模拟数据列表
void _generateMockData() {
// 假设你有3个不同的广告位ID
final adUnitIdStyle1 = AdseyeAdHelper.nativeAdUnitId_01;
final adUnitIdStyle2 = AdseyeAdHelper.nativeAdUnitId_02;
for (int i = 0; i < 30; i++) {
// 使用取余运算在固定的间隔插入广告
if (i > 0 && i % 11 == 2) {
_items.add(
AdItem(templateId: 'left_icon_style', adUnitId: adUnitIdStyle1),
);
} else if (i > 0 && i % 11 == 7) {
_items.add(
AdItem(templateId: 'reboot_head_stle', adUnitId: adUnitIdStyle2),
);
} else if (i > 0 && i % 11 == 10) {
_items.add(
AdItem(templateId: 'big_media_style', adUnitId: adUnitIdStyle1),
);
} else {
// 其他位置都是普通内容
_items.add(
ContentItem(
'Article Title #$i',
'This is the body of the article, showing some interesting content. Flutter makes building lists like this very easy and performant.',
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter Native Ads Feed')),
body: ListView.builder(
// 列表的总长度就是我们数据列表的长度
itemCount: _items.length,
// itemBuilder 会为列表中的每一项构建一个 Widget
itemBuilder: (context, index) {
final item = _items[index];
// 关键逻辑:检查当前项的类型
if (item is AdItem) {
// 我们把 templateId 和 adUnitId 传递进去
return NativeAdCard(
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();
},
),
);
}
}
/// 原生广告页面
class NativeAdPage extends StatefulWidget {
const NativeAdPage({super.key});
@override
State<NativeAdPage> createState() => _NativeAdPageState();
}
class _NativeAdPageState extends State<NativeAdPage> {
late AdseyeNativeAdController _controller;
// 添加状态变量用于管理UI
bool _isLoading = true; // 初始为 true,一进入页面就显示 loading
String? _loadError; // 用于存储加载失败时的错误信息
@override
void initState() {
super.initState();
_controller = AdseyeNativeAdController();
// 设置回调
_controller.onAdLoaded = _onAdLoaded;
_controller.onAdFailed = _onAdFailed;
_controller.onAdImpression = () {
print("[NativeAdPage] 广告成功渲染展示!");
// 可以在这里隐藏一个覆盖在 AdViewContainer 上的占位图
};
_controller.onAdClick = () {
print("[NativeAdPage] 广告被点击。");
};
}
void _onAdLoaded() {
print("[NativeAdPage] 广告加载成功!");
// 更新状态,隐藏 loading
setState(() {
_isLoading = false;
_loadError = null;
});
}
void _onAdFailed(String error) {
print("[NativeAdPage] 广告加载失败: $error");
// 更新状态,隐藏 loading,并记录错误信息
setState(() {
_isLoading = false;
_loadError = error;
});
}
@override
void dispose() {
// 确保在页面销毁时调用 controller 的 destroy
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('上图下文原生广告')),
// 使用 Stack 布局,让 loading 指示器可以覆盖在广告视图之上
body: Stack(
alignment: Alignment.center, // 让 Stack 中的子项居中
children: [
// 广告视图容器,它一直在底层
AdseyeNativeAdViewContainer(
adUnitId: AdseyeAdHelper.nativeAdUnitId_01,
controller: _controller,
// 广告的具体布局 - 完全根据您的描述实现
child: Padding(
padding: const EdgeInsets.all(12.0),
// 整体是“上下”结构,所以使用 Column
child: Column(
mainAxisSize: MainAxisSize.min, // 让广告容器高度自适应内容
crossAxisAlignment: CrossAxisAlignment.stretch, // 让子项横向填满
children: [
// --- 上半部分: Media View ---
AspectRatio(
aspectRatio: 16 / 9,
child: AdseyeNativeMediaView(),
),
const SizedBox(height: 12), // MediaView 和下方信息行的间距
// --- 下半部分: 信息行 (图标 - 文字 - 按钮) ---
// 这是一个“左右”结构,所以使用 Row
Row(
crossAxisAlignment:
CrossAxisAlignment.center, // 垂直居中对齐图标、文字、按钮
children: [
// --- 最左边: Icon ---
AdseyeNativeIconView(width: 50, height: 50),
const SizedBox(width: 8), // 图标和文字之间的间距
// --- 中间: Title 和 Body ---
// 使用 Expanded,让文字部分占据所有剩余的横向空间
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start, // 文字内容左对齐
children: [
// 上: Title, 粗体
AdseyeNativeTitleView(
height: 22.0,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold, // 实现“title粗体”
color: Colors.black,
),
),
const SizedBox(height: 4), // 标题和描述之间的垂直间距
// 下: Body, 两行
AdseyeNativeBodyView(
height: 38.0,
style: const TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
],
),
),
const SizedBox(width: 6), // 文字和CTA按钮之间的间距
// --- 右边: CTA Button ---
Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(6),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5,
vertical: 12,
),
child: AdseyeNativeCTAView(
width: 90.0,
height: 55.0,
style: const TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
),
),
// --- 覆盖层:根据状态显示 Loading 或 Error ---
// 1. 加载指示器
Visibility(
visible: _isLoading,
child: Container(
// 给一个半透明的背景,提升用户体验
color: Colors.white.withOpacity(0.8),
child: const Center(child: CircularProgressIndicator()),
),
),
// 2. 错误信息
Visibility(
// 只有在不加载且有错误信息时显示
visible: !_isLoading && _loadError != null,
child: Container(
color: Colors.white, // 使用纯白背景覆盖广告视图
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'广告加载失败:\n$_loadError',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red),
),
),
),
),
),
],
),
);
}
}