TP MEDIA
A comprehensive Flutter utility package providing fast AdMob ad integration, in-app purchase management via RevenueCat, network connectivity monitoring, and a rich suite of common UI utilities and widgets for rapid app development.
π― Overview
tp_media is designed to streamline common development tasks in Flutter apps, especially those requiring monetization through ads and in-app purchases. It provides production-ready components with minimal boilerplate, built on top of popular packages like Google Mobile Ads, RevenueCat, and Flutter's ecosystem tools.
β¨ Features
π¬ AdMob Integration
AdmobBannerAd: Responsive, orientation-aware banner ads with automatic reload and internet connectivity checks. Test mode support for iOS screenshots.AdmobOpenAd: App open ad display for launch and resume scenarios.InterstitialAdMixin: Mixin for seamless interstitial ad loading and display with callbacks.RewardedAdMixin: Mixin for rewarded ad integration with reward callbacks.AdmobInitializer: One-call initialization for Google Mobile Ads SDK.TrackingTransparencyDialog: iOS-native ATT (App Tracking Transparency) permission dialog.- Internet-aware loading: Ads don't load when offline, saving bandwidth.
π³ In-App Purchase (IAP) Management
Powered by RevenueCat for cross-platform purchase handling:
IapInitializer: Initialize RevenueCat SDK with custom managers.IapManager: Abstract base for managing subscriptions, listening to purchase updates, restoring transactions.- Stream-based subscription state: Real-time subscription status monitoring.
- Paywall integration: Easy-to-use RevenueCat Paywall UI display.
- Customer info caching: Efficient customer data management.
π¨ UI Widgets
Production-ready widgets for rapid development:
CommonCard: Customizable card with rounded corners and borders.CommonEmpty: Empty state widget with Lottie animation support.CommonIconButton: Styled icon button with feedback.CommonTextButton: Text button widget with consistent theming.CommonTextField: Customizable text input field.CommonSnackbar: Helper for showing snackbars.GlobalLoading: Full-screen loading indicator.TopRoundedContainer: Container with top-rounded corners.MaterialInkWell: Material ripple effect wrapper.DisableContainer: Wrapper to disable user interactions.TakeIfContainer: Conditional visibility wrapper.PremiumUser: Widget for premium content display.DialogHeader: Reusable dialog header component.ClearFocusOnTap: Dismiss keyboard on tap.InternetChecker: Network status indicator widget.HeaderSliverList: Sliver widget with header support.StickyHeaderDelegate: Custom sliver delegate for sticky headers.
π£οΈ Dialogs
CommonAlertDialog: iOS-native style alert dialog (Cupertino) with title, message, and custom actions.TrackingTransparencyDialog: iOS ATT permission request dialog.showAlertDialog(): Helper function for quick dialog creation.
π Extensions & Utilities
Context Extensions:
context.showSnackbar('Message')β Show snackbarcontext.showSuccessSnackBar('Message')β Green snackbarcontext.showErrorSnackBar('Message')β Red snackbar
String Extensions:
'hello'.capitalize()β Capitalize first letter β "Hello"'hello'.vnToEnβ Convert Vietnamese diacritics to English'12345'.isPhoneNumber()β Validate phone number (VN format)'https://example.com'.isUri()β Check if valid URI'3.14'.replaceCommaβ Replace commas with dots
Double Extensions:
3.14159.round(2)β Smart rounding with precision
ScrollController Extensions:
scrollController.scrollToBottom()β Check if scroll is at bottomscrollController.isAtTopβ Check if scroll is at top
Text Extensions:
- Utility extensions for text formatting
Iterable Extensions:
- Extra utility methods for collections
π‘ Network Management
InternetManager: Singleton for checking internet connectivity.InternetManager.instance.isOnlineβ Check current connection statusInternetManager.instance.onStatusChangeβ Stream of connection changes
ποΈ State Management
LoadingDialogState: Mixin for showing/hiding loading dialogs from state.
π¨ Theming
themepackage: Pre-built theme configurations.
β° Utilities
-
ToastUtils:ToastUtils.success('Message')ToastUtils.failed('Message')ToastUtils.updated('Message')ToastUtils.deleted('Message')
-
DateTimeUtils: Date and time formatting utilities. -
CommonUtils: General utility functions. -
InAppReviewChecker: Helper for requesting app reviews.
π¦ Dependencies
This package relies on:
google_mobile_ads: ^6.0.0 β Google AdMob SDKpurchases_flutter: ^9.8.0 β RevenueCat IAP SDKpurchases_ui_flutter: ^9.8.0 β RevenueCat Paywall UIapp_tracking_transparency: ^2.0.6+1 β iOS ATT dialoglottie: ^3.3.2 β Animationsfluttertoast: ^9.0.0 β Toast notificationsinternet_connection_checker_plus: ^2.9.0 β Connectivity detectionin_app_review: ^2.0.11 β App review requestsintl: ^0.20.2 β Internationalization
π Getting Started
Installation
Add to your pubspec.yaml:
dependencies:
tp_media: ^1.0.3
Then run:
flutter pub get
Import
import 'package:tp_media/tp_media.dart';
π Usage Guide
AdMob Setup
Initialize AdMob SDK
import 'package:tp_media/tp_media.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AdmobInitializer.init();
runApp(MyApp());
}
Display Banner Ad
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child: YourContent()),
AdmobBannerAd('ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy'), // Replace with your ad unit ID
],
);
}
Test Mode (for iOS screenshots):
AdmobBannerAd.isTestMode = true; // Set before showing
Display App Open Ad
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
AdmobOpenAd.showAdIfAvailable();
}
}
Interstitial & Rewarded Ads with Mixins
class MyPage extends StatefulWidget {
@override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> with InterstitialAdMixin, RewardedAdMixin {
@override
String get interstitialUnitId => 'ca-app-pub-xxx';
@override
String get rewardedUnitId => 'ca-app-pub-yyy';
@override
bool get isEnableAd => true;
@override
void initState() {
super.initState();
loadAd(); // Load interstitial
loadRewardedAd(); // Load rewarded
}
void showInterstitialOnButtonTap() {
loadAndShowAd(
onDismissAd: () {
print('User dismissed ad');
},
);
}
void showRewardOnButtonTap() {
loadAndShowRewardedAd(
onUserEarnedReward: (reward) {
print('User earned: ${reward.amount} ${reward.type}');
},
onDismissAd: () {
print('Rewarded ad dismissed');
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CommonTextButton(
text: 'Show Interstitial',
onPressed: showInterstitialOnButtonTap,
),
SizedBox(height: 16),
CommonTextButton(
text: 'Show Rewarded',
onPressed: showRewardOnButtonTap,
),
],
),
),
);
}
}
In-App Purchases (RevenueCat)
Create Custom IAP Manager
class MyIapManager extends IapManager {
MyIapManager._internal();
static final _instance = MyIapManager._internal();
static MyIapManager get instance => _instance;
@override
String entitlementId = 'pro_subscription'; // Your RevenueCat entitlement ID
}
Initialize IAP
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await IapInitializer.init([MyIapManager.instance]);
runApp(MyApp());
}
Check Subscription Status
class PremiumContent extends StatefulWidget {
@override
State<PremiumContent> createState() => _PremiumContentState();
}
class _PremiumContentState extends State<PremiumContent> {
@override
void initState() {
super.initState();
MyIapManager.instance.stream.listen((isSubscribed) {
print('Subscription status: $isSubscribed');
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
stream: MyIapManager.instance.stream,
builder: (context, snapshot) {
final isSubscribed = snapshot.data ?? false;
return isSubscribed
? PremiumFeatures()
: PaywallScreen();
},
);
}
}
Show Paywall
CommonTextButton(
text: 'Show Paywall',
onPressed: () async {
final result = await MyIapManager.instance.presentPaywallIfNeeded();
if (result) {
print('Purchase successful or already subscribed');
}
},
)
Dialogs
Common Alert Dialog
showAlertDialog(
context,
title: 'Confirm',
message: 'Are you sure?',
okText: 'Yes',
cancelText: 'No',
onOkButton: () {
print('User confirmed');
Navigator.pop(context);
},
);
iOS Tracking Transparency
showDialog(
context: context,
builder: (_) => buildTrackingTransparencyDialog(),
);
Common Widgets
Cards
CommonCard(
child: Padding(
padding: EdgeInsets.all(16),
child: Text('Card content'),
),
radius: BorderRadius.circular(12),
elevation: 4,
)
Empty State
CommonEmpty(
title: 'No data',
description: 'Try again later',
)
Buttons
CommonTextButton(
text: 'Click Me',
onPressed: () {},
)
CommonIconButton(
icon: Icons.add,
onPressed: () {},
)
Text Field
CommonTextField(
controller: _controller,
hintText: 'Enter text',
)
Loading
GlobalLoading.show(context); // Show loading
// ... async operation ...
GlobalLoading.hide(); // Hide loading
Extensions Usage
// Context
context.showSnackbar('Hello');
context.showSuccessSnackBar('Success!');
context.showErrorSnackBar('Error!');
// String
print('hello'.capitalize()); // Hello
print('hΓ nα»i'.vnToEn); // ha noi
// Double
print(3.14159.round(2)); // 3.14
// ScrollController
if (scrollController.scrollToBottom) {
print('Scrolled to bottom');
}
Toasts
ToastUtils.success('Operation successful');
ToastUtils.failed('Operation failed');
ToastUtils.updated('Item updated');
ToastUtils.deleted('Item deleted');
Network Connectivity
// Check current status
final isOnline = await InternetManager.instance.isOnline;
print('Online: $isOnline');
// Listen to changes
InternetManager.instance.onStatusChange.listen((status) {
print('Status: $status');
});
π§ Platform Configuration
Android
Add to android/app/build.gradle.kts:
android {
defaultConfig {
minSdkVersion 21
}
}
Add permissions to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
iOS
Add to ios/Podfile (if needed):
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
]
end
end
end
Add to ios/Runner/Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>
π Example
See the example app for a complete working implementation including:
- AdMob banner, interstitial, and rewarded ads
- RevenueCat in-app purchases
- Common widgets usage
- Extensions examples
Run it with:
cd example
flutter run
π€ Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is licensed under the MIT License β see the LICENSE file for details.
π Acknowledgments
Built with β€οΈ using:
For more information, visit the repository.
Libraries
- ads/admob_enable
- ads/admob_initializer
- ads/admob_open_ad
- ads/tracking_transparency_dialog
- common/in_app_review_checker
- common/screens
- dialog/common_alert_dialog
- extension/context_ex
- extension/double_ex
- extension/iterable_ex
- extension/scroll_controller_ex
- extension/string_ex
- extension/text_ex
- external/in_app_review
- external/lottie
- external/purchase_flutter
- iap/iap_initializer
- iap/iap_manager
- mixin/interstitial_ad_mixin
- mixin/rewarded_ad_mixin
- network/internet_manager
- state/loading_dialog_state
- theme/theme
- tp_media
- utils/date_time_utils
- utils/toast_utils
- widget/clear_focus_on_tap
- widget/common_card
- widget/common_empty
- widget/common_snackbar
- widget/common_text_field
- widget/dialog_header
- widget/disable_container
- widget/global_loading
- widget/header_sliver_list
- widget/internet_checker
- widget/material_inkwell
- widget/phone_number_text
- widget/sticky_header_delegate
- widget/take_if_container
- widget/tile_row
- widget/top_rounded_container