magic_ad_sdk
MagicAdSDK Flutter plugin for Android and iOS.
This package provides a Flutter MethodChannel bridge for MagicAdSDK, including SDK initialization, ad loading, ad display, PlatformView-based ad rendering, event streams, and object lifecycle management.
Features
- SDK initialization and logging configuration
- Splash ads
- Rewarded video ads
- Interstitial ads
- Banner ads with Flutter PlatformView embedding
- Feed ads with Flutter PlatformView embedding
- Self-render feed ads with Flutter PlatformView embedding
- Ad lifecycle events through broadcast streams
- Per-ad-object lifecycle management with
objectID
Requirements
Flutter and Dart:
- Flutter:
>=3.10.0 - Dart SDK:
>=3.0.0 <4.0.0
Android:
- minSdk:
21 - compileSdk:
34 - Java:
11 - Kotlin Gradle Plugin:
2.1.0 - Android Gradle Plugin:
8.9.1 - MagicAdSDK Android:
com.magic.ad.sdk:magicadsdk:0.0.63
iOS:
- iOS deployment target:
13.0 - Swift:
5.0 - MagicAdSDK iOS:
MagicAdSDK 0.0.63
Installation
Add the package to your Flutter app:
dependencies:
magic_ad_sdk: ^0.0.1
Then import the unified API entry:
import 'package:magic_ad_sdk/magic_index.dart';
Android Setup
MagicAdSDK is resolved from the Magic Maven repository. Add the repository to your host Android project.
For newer Flutter Android templates, configure repositories in android/settings.gradle or the root Gradle file used by your app:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven {
url "https://mv.magicacid.cn/repository/maven-public/"
allowInsecureProtocol = true
}
google()
mavenCentral()
}
}
If your app needs to load HTTP ad assets, configure Android cleartext traffic for the required asset domains in your host app. One common approach is to add a network_security_config.xml file and reference it from AndroidManifest.xml:
<application
android:networkSecurityConfig="@xml/network_security_config">
</application>
iOS Setup
The plugin podspec depends on MagicAdSDK 0.0.63, which is integrated through CocoaPods when your Flutter app installs pods.
Set the minimum deployment target to iOS 13.0 or later in your app's ios/Podfile:
platform :ios, '13.0'
Then install pods:
cd ios
pod install
If your app uses IDFA or location-based capabilities, request the required permissions in the host app and pass the resulting configuration to MagicAdSDK according to your app's privacy and compliance requirements.
Initialize SDK
Register event streams before initialization if you need to observe init status:
final initSubscription =
MagicListenerManager.initEventHandler.listen((event) {
if (event.initStatus == MagicInitStatus.initSuccess) {
debugPrint('MagicAdSDK initialized');
} else if (event.initStatus == MagicInitStatus.initFailed) {
debugPrint('MagicAdSDK init failed: ${event.errorMessage}');
}
});
await MagicInitManger.initMagicSDK(appId: 'your_app_id');
await MagicInitManger.setLogEnabled(logEnabled: true);
Ad Object Lifecycle
Each loadXxx call returns an independent ad object with its own objectID. Multiple ads can be loaded for the same placement without overwriting each other.
Always destroy ad objects when they are no longer needed:
await adObject.destroy();
Recommended lifecycle rules:
- Store the returned ad object while the page owns it.
- Filter stream events by
event.adObject?.objectID. - Use
getPrice()after the ad has loaded if you need the native bid price value. - Call
destroy()indispose, on route exit, or before reusing an ad slot. - If a page exits while
loadXxxis still awaiting, destroy the returned object immediately once the future completes. - When an ad sends a closed event, clear the reference held by your page.
Splash Ads
MagicSplashAdObject? splashAd;
final splashSubscription =
MagicListenerManager.splashEventHandler.listen((event) {
if (event.adObject?.objectID != splashAd?.objectID) return;
if (event.isClosed) {
splashAd = null;
}
});
splashAd = await MagicSplashManager.loadSplash(
placementID: 'your_placement_id',
);
if (await splashAd?.ready() == true) {
await splashAd?.show();
}
Rewarded Video Ads
MagicRewardedAdObject? rewardedAd;
final rewardedSubscription =
MagicListenerManager.rewardedVideoEventHandler.listen((event) {
if (event.adObject?.objectID != rewardedAd?.objectID) return;
if (event.rewardedVideoStatus == MagicRewardedVideoStatus.rewarded) {
debugPrint('Reward granted');
}
if (event.isClosed) {
rewardedAd = null;
}
});
rewardedAd = await MagicRewardedManager.loadRewardedVideo(
placementID: 'your_placement_id',
);
if (await rewardedAd?.ready() == true) {
await rewardedAd?.show();
}
Interstitial Ads
MagicInterstitialAdObject? interstitialAd;
final interstitialSubscription =
MagicListenerManager.interstitialEventHandler.listen((event) {
if (event.adObject?.objectID != interstitialAd?.objectID) return;
if (event.isClosed) {
interstitialAd = null;
}
});
interstitialAd = await MagicInterstitialManager.loadInterstitialAd(
placementID: 'your_placement_id',
);
if (await interstitialAd?.ready() == true) {
await interstitialAd?.show();
}
Banner Ads
Load a banner ad and embed it with MagicBannerAdView:
MagicBannerAdObject? bannerAd;
bannerAd = await MagicBannerManager.loadBannerAd(
placementID: 'your_placement_id',
width: 320,
height: 50,
);
if (bannerAd != null)
SizedBox(
width: 320,
height: 50,
child: MagicBannerAdView(adObject: bannerAd!),
)
Destroy the banner when it leaves the page:
await bannerAd?.destroy();
bannerAd = null;
Feed Ads
Load a feed ad and embed it with MagicFeedAdView:
MagicFeedAdObject? feedAd;
feedAd = await MagicFeedManager.loadFeedAd(
placementID: 'your_placement_id',
width: MediaQuery.sizeOf(context).width,
height: 0,
);
if (feedAd != null)
MagicFeedAdView(adObject: feedAd!)
You can query and control video state when supported by the native ad:
final isVideo = await feedAd?.isVideo();
final isPlaying = await feedAd?.isPlaying();
await feedAd?.pauseVideo();
await feedAd?.resumeVideo();
Self-render Feed Ads
Load a self-render feed ad and embed it with MagicSelfRenderFeedAdView:
MagicSelfRenderFeedAdObject? selfRenderFeedAd;
selfRenderFeedAd = await MagicFeedManager.loadSelfRenderFeedAd(
placementID: 'your_placement_id',
width: MediaQuery.sizeOf(context).width,
height: 0,
);
if (selfRenderFeedAd != null)
MagicSelfRenderFeedAdView(adObject: selfRenderFeedAd!)
Self-render feed video events are emitted through selfRenderFeedEventHandler.
Error Handling
Native loading failures are reported in two ways:
- The
Futurereturned byloadXxxthrows aPlatformException. - The corresponding event stream emits a
loadFailedevent.
import 'package:flutter/services.dart';
try {
final ad = await MagicSplashManager.loadSplash(
placementID: 'your_placement_id',
);
await ad?.show();
} on PlatformException catch (error) {
debugPrint('Load failed: ${error.code} ${error.message}');
}
Stream events also include fields such as errorCode, errorMessage, rawMap, and adObject.
Event Streams
Available event streams:
MagicListenerManager.initEventHandlerMagicListenerManager.splashEventHandlerMagicListenerManager.rewardedVideoEventHandlerMagicListenerManager.interstitialEventHandlerMagicListenerManager.bannerEventHandlerMagicListenerManager.feedEventHandlerMagicListenerManager.selfRenderFeedEventHandler
Because these streams are broadcast streams, multiple pages can receive the same type of event. Always filter events by the ad object's objectID when a page owns a specific ad.
final subscription =
MagicListenerManager.bannerEventHandler.listen((event) {
if (event.adObject?.objectID != bannerAd?.objectID) return;
debugPrint('Banner event: ${event.bannerStatus}');
});
Cancel stream subscriptions when the owning object or page is disposed:
await subscription.cancel();
Extra Parameters
Each ad loading API accepts an optional extraMap. Key helper methods are provided by each manager:
final ad = await MagicRewardedManager.loadRewardedVideo(
placementID: 'your_placement_id',
extraMap: {
MagicRewardedManager.videoMuteKey(): true,
MagicRewardedManager.bidFloorKey(): 10,
},
);
Common helper methods include:
MagicSplashManager.bidFloorKey()MagicSplashManager.videoMuteKey()MagicRewardedManager.bidFloorKey()MagicRewardedManager.videoMuteKey()MagicInterstitialManager.bidFloorKey()MagicInterstitialManager.videoMuteKey()MagicBannerManager.bidFloorKey()MagicBannerManager.videoMuteKey()MagicFeedManager.bidFloorKey()MagicFeedManager.autoPlayKey()MagicFeedManager.videoMuteKey()MagicCommon.getShowCustomExtKey()
API Overview
Initialization:
MagicInitManger.initMagicSDK({required appId})MagicInitManger.getSDKVersion()MagicInitManger.setLogEnabled({logEnabled})
Splash:
MagicSplashManager.loadSplash({placementID, extraMap})MagicSplashAdObject.ready()MagicSplashAdObject.getPrice()MagicSplashAdObject.show()MagicSplashAdObject.destroy()
Rewarded video:
MagicRewardedManager.loadRewardedVideo({placementID, extraMap})MagicRewardedAdObject.ready()MagicRewardedAdObject.getPrice()MagicRewardedAdObject.show()MagicRewardedAdObject.destroy()
Interstitial:
MagicInterstitialManager.loadInterstitialAd({placementID, extraMap})MagicInterstitialAdObject.ready()MagicInterstitialAdObject.getPrice()MagicInterstitialAdObject.show()MagicInterstitialAdObject.destroy()
Banner:
MagicBannerManager.loadBannerAd({placementID, width, height, extraMap})MagicBannerAdView(adObject: bannerAd)MagicBannerAdObject.realHeight()MagicBannerAdObject.getPrice()MagicBannerAdObject.destroy()
Feed:
MagicFeedManager.loadFeedAd({placementID, width, height, extraMap})MagicFeedAdView(adObject: feedAd)MagicFeedAdObject.realHeight()MagicFeedAdObject.isVideo()MagicFeedAdObject.isPlaying()MagicFeedAdObject.pauseVideo()MagicFeedAdObject.resumeVideo()MagicFeedAdObject.getPrice()MagicFeedAdObject.destroy()
Self-render feed:
MagicFeedManager.loadSelfRenderFeedAd({placementID, width, height, extraMap})MagicSelfRenderFeedAdView(adObject: selfRenderFeedAd)MagicSelfRenderFeedAdObject.realHeight()MagicSelfRenderFeedAdObject.isVideo()MagicSelfRenderFeedAdObject.isPlaying()MagicSelfRenderFeedAdObject.pauseVideo()MagicSelfRenderFeedAdObject.resumeVideo()MagicSelfRenderFeedAdObject.getPrice()MagicSelfRenderFeedAdObject.destroy()
Example App
The example/ directory contains a Flutter sample app showing SDK initialization, ad loading, PlatformView embedding, event handling, and object cleanup.
Run it with:
cd example
flutter pub get
flutter run
License
This package is released under the MIT License. See LICENSE for details.