Flutter货币化基础功能插件knt_base_monetized的使用
Flutter货币化基础功能插件knt_base_monetized的使用
knt_base_monetized
是一个帮助处理应用内购买和广告流的辅助库。以下是其基本使用方法。
开始使用
1. 配置Admob ID
确保你已经按照以下参考文档完成了平台设置:
2. 使用依赖注入
建议使用 get_it
和 injectable
进行依赖注入:
- 参考注册第三方类型部分来创建包中的BLoC和服务类实例。
- 这些BLoC和服务类需要是单例(使用
@singleton
注解)。
3. 理解BLoC模式
了解BLoC模式,可以参考库 flutter_bloc
。
4. 使用 flutter_bloc
库
- 在应用级别创建
BlocProvider
以提供此包的BLoC。 - 使用
BlocBuilder
和BlocListener
来处理来自这些BLoC的状态。
常见流程
1. 广告(Admob)
步骤1:创建实例
AdmobConfig config = AdmobConfig(
appId: 'YOUR_APP_ID',
bannerId: 'YOUR_BANNER_ID',
interstitialId: 'YOUR_INTERSTITIAL_ID',
);
AdmobService admobService = AdmobService(config);
FrequentlyAdsBloc frequentlyAdsBloc = FrequentlyAdsBloc(admobService);
StaticAdsBloc staticAdsBloc = StaticAdsBloc(admobService);
步骤2:初始化
在 main()
函数中初始化 MobileAd
:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await getIt<AdmobService>().init();
runApp(App());
}
步骤3:在启动页中准备广告
在 SplashPage
的 initState()
中插入以下代码:
Future.delayed(Duration.zero, () {
context.read<FrequentlyAdsBloc>().add(PrepareFrequentlyAdEvent());
});
步骤4:显示插屏广告
在需要显示插屏广告的地方调用:
context.read<FrequentlyAdsBloc>().add(ShowFrequentlyAdEvent(_adTag));
推荐为每个屏幕创建唯一的 _adTag
以便于状态管理。
2. 应用内购买
步骤1:创建订阅BLoC
创建一个继承自 BaseSubscriptionBloc
的订阅BLoC。
class SubscriptionBloc extends BaseSubscriptionBloc {
SubscriptionBloc(MonetizedRepo repo, {required String entitlementID})
: super(repo, entitlementID: entitlementID);
[@override](/user/override)
void onInit() {
super.onInit();
// 初始化逻辑
}
[@override](/user/override)
void onDispose() {
super.onDispose();
// 清理逻辑
}
}
步骤2:覆盖方法
覆盖所有需要的方法,例如从你的应用内购买库中获取相应函数。
步骤3:创建Premium页面
创建一个展示高级功能的页面,包括SKU列表、恢复购买选项、条款和隐私信息。
步骤4:处理SKU列表和购买请求
- 显示SKU列表:使用
SubscriptionBloc#FetchListSkuEvent
- 请求订阅:使用
SubscriptionBloc#RequestSubscriptionEvent
- 恢复购买:使用
SubscriptionBloc#RestoreSubscriptionEvent
步骤4(可选):处理免费使用流
创建 FreeUsageCounterBloc
实例来处理用户的免费使用流。
注意事项
- 此包包含
app_tracking_transparency
用于处理iOS上的Admob隐私问题。
示例代码
以下是完整的示例代码:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
import 'package:knt_bloc/knt_bloc.dart';
import 'bloc/subscription_bloc.dart';
import 'data/monetize_repo.dart';
import 'data/purchase_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Knt Monetized Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (BuildContext context) => SubscriptionBloc(
ArticleMonetizedRepo(),
entitlementID: Purchases.defaultEntitlementID,
),
child: const MyHomePage(title: 'Knt Monetized Demo'),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _iapTag = (MyHomePage).toString();
final _logs = <String>[];
[@override](/user/override)
void initState() {
super.initState();
Future.delayed(Duration.zero, _onFetchSku);
}
[@override](/user/override)
Widget build(BuildContext context) {
return BlocListener<SubscriptionBloc, BaseState>(
listener: (context, state) {
if (!mounted) {
return;
}
void showSnackBar(String message) {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: const Duration(milliseconds: 2811),
content: Text(message),
),
);
}
final stateTag = state.tag;
final timeStamps = DateTime.now();
final newMessageLog = '[${DateFormat.Hms().format(timeStamps)}]: '
'${state.runtimeType} with tag [$stateTag]';
showSnackBar(newMessageLog);
setState(() {
_logs.insert(0, newMessageLog);
});
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
BlocBuilder<SubscriptionBloc, BaseState>(
buildWhen: (previous, current) {
return current is FetchingOfferingsState ||
current is FetchedOfferingsState ||
current is FetchedOfferingsFailureState;
},
builder: (context, state) => switch (state) {
FetchedOfferingsFailureState() => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Error: ${state.exception.additionalInfo}',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 8),
TextButton(
onPressed: _onFetchSku,
child: const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.refresh,
size: 24,
),
SizedBox(width: 8),
Text('Retry'),
],
),
),
],
),
FetchingOfferingsState() => const SizedBox(
height: 240,
child: Center(
child: CircularProgressIndicator(),
),
),
FetchedOfferingsState(:final data) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: _SubscriptionBox(
itemList: data
..sort(
(s1, s2) => s2.price.compareTo(s1.price),
),
onItemPicked: _onItemPicked,
),
),
_ => const SizedBox(),
},
),
const SizedBox(height: 16),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
for (final (index, log) in _logs.indexed)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 20,
height: 20,
margin: const EdgeInsets.symmetric(vertical: 2),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
child: Center(
child: FittedBox(
child: Text(
'${_logs.length - index}',
style: Theme.of(context)
.textTheme
.labelSmall
?.copyWith(color: Colors.white),
),
),
),
),
const SizedBox(width: 8),
Expanded(
child: Text(log),
),
],
),
],
),
),
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _onFetchSku,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
child: Text(
'Retry',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Colors.white),
),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _onRestore,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
),
child: Text(
'Restore',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Colors.white),
),
),
),
],
),
),
const SizedBox(height: 32),
],
),
),
);
}
void _onFetchSku() {
_makeLogGap();
context.read<SubscriptionBloc>().add(FetchOfferingsEvent(tag: _iapTag));
}
void _onItemPicked(SubscriptionItem item) {
_makeLogGap();
context.read<SubscriptionBloc>().add(
RequestSubscriptionEvent(
item,
tag: _iapTag,
),
);
}
void _onRestore() {
_makeLogGap();
context
.read<SubscriptionBloc>()
.add(RestoreSubscriptionEvent(tag: _iapTag));
}
void _makeLogGap() {
setState(() {
_logs.insert(0, '---------------------');
});
}
}
class _SubscriptionBox extends StatelessWidget {
const _SubscriptionBox({
this.itemList = const [],
this.onItemPicked,
});
final List<SubscriptionItem> itemList;
final ValueSetter<SubscriptionItem>? onItemPicked;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
for (final item in itemList)
InkWell(
onTap: () => onItemPicked?.call(item),
child: Container(
margin: const EdgeInsets.only(top: 12),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: (item.period == Period.annually
? Colors.red
: Colors.grey)
.withOpacity(0.3),
),
),
child: Row(
children: [
const Icon(
Icons.shopping_cart,
size: 24,
color: Colors.orange,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.content,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 4),
Text(
'${item.sku} - ${item.localizedPrice}',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Colors.green),
),
],
),
),
],
),
),
),
const SizedBox(height: 16),
],
);
}
}
更多关于Flutter货币化基础功能插件knt_base_monetized的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter货币化基础功能插件knt_base_monetized的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
knt_base_monetized
是一个用于 Flutter 应用货币化的基础功能插件。它提供了一些常见的货币化功能,如广告展示、应用内购买等,帮助开发者更容易地集成和应用这些功能。以下是如何使用 knt_base_monetized
插件的基础指南。
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 knt_base_monetized
插件的依赖:
dependencies:
flutter:
sdk: flutter
knt_base_monetized: ^latest_version
然后运行 flutter pub get
来安装依赖。
2. 初始化插件
在你的应用启动时,需要初始化 knt_base_monetized
插件。通常可以在 main.dart
文件中进行初始化:
import 'package:flutter/material.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化插件
await KntBaseMonetized.initialize(
adMobAppId: 'your_admob_app_id',
// 其他初始化配置
);
runApp(MyApp());
}
3. 展示广告
knt_base_monetized
提供了多种广告类型的支持,如横幅广告、插页式广告、奖励视频广告等。
横幅广告
import 'package:flutter/material.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
class BannerAdExample extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Banner Ad Example'),
),
body: Column(
children: [
Expanded(
child: ListView(
children: [
// 你的应用内容
],
),
),
KntBannerAd(
adUnitId: 'your_banner_ad_unit_id',
),
],
),
);
}
}
插页式广告
import 'package:flutter/material.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
class InterstitialAdExample extends StatefulWidget {
[@override](/user/override)
_InterstitialAdExampleState createState() => _InterstitialAdExampleState();
}
class _InterstitialAdExampleState extends State<InterstitialAdExample> {
KntInterstitialAd _interstitialAd;
[@override](/user/override)
void initState() {
super.initState();
_interstitialAd = KntInterstitialAd(adUnitId: 'your_interstitial_ad_unit_id');
_interstitialAd.load();
}
void _showAd() {
_interstitialAd.show();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Interstitial Ad Example'),
),
body: Center(
child: ElevatedButton(
onPressed: _showAd,
child: Text('Show Interstitial Ad'),
),
),
);
}
}
奖励视频广告
import 'package:flutter/material.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
class RewardedAdExample extends StatefulWidget {
[@override](/user/override)
_RewardedAdExampleState createState() => _RewardedAdExampleState();
}
class _RewardedAdExampleState extends State<RewardedAdExample> {
KntRewardedAd _rewardedAd;
[@override](/user/override)
void initState() {
super.initState();
_rewardedAd = KntRewardedAd(adUnitId: 'your_rewarded_ad_unit_id');
_rewardedAd.load();
}
void _showAd() {
_rewardedAd.show(onReward: (reward) {
// 处理奖励逻辑
print('User earned reward: $reward');
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Rewarded Ad Example'),
),
body: Center(
child: ElevatedButton(
onPressed: _showAd,
child: Text('Show Rewarded Ad'),
),
),
);
}
}
4. 应用内购买
knt_base_monetized
还支持应用内购买功能。你需要配置产品 ID 并处理购买逻辑。
import 'package:flutter/material.dart';
import 'package:knt_base_monetized/knt_base_monetized.dart';
class InAppPurchaseExample extends StatefulWidget {
[@override](/user/override)
_InAppPurchaseExampleState createState() => _InAppPurchaseExampleState();
}
class _InAppPurchaseExampleState extends State<InAppPurchaseExample> {
List<ProductDetails> _products = [];
[@override](/user/override)
void initState() {
super.initState();
_loadProducts();
}
Future<void> _loadProducts() async {
final products = await KntInAppPurchase.queryProductDetails([
'your_product_id_1',
'your_product_id_2',
]);
setState(() {
_products = products;
});
}
Future<void> _purchaseProduct(ProductDetails product) async {
final purchaseDetails = await KntInAppPurchase.buyProduct(product);
// 处理购买结果
if (purchaseDetails.status == PurchaseStatus.purchased) {
print('Purchase successful: ${purchaseDetails.productID}');
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('In-App Purchase Example'),
),
body: ListView.builder(
itemCount: _products.length,
itemBuilder: (context, index) {
final product = _products[index];
return ListTile(
title: Text(product.title),
subtitle: Text(product.price),
onTap: () => _purchaseProduct(product),
);
},
),
);
}
}