- Unlike other ad formats where the mediation SDK implements the ad view, native ads provide ad components for you to build the ad view directly.
- The key advantage is minimizing disruption by implementing layouts based on your UI/UX. However, you must include ad markers to prevent users from confusing ads with content.
4 Required Native Ad ElementsNative ads can be freely designed to match your app’s UI, but the following 4 elements are mandatory:
- Ad Label: Add “AD” or similar text so users clearly recognize it as an advertisement.
- AdChoices Icon: Automatically inserted by the DARO SDK. Ensure it’s not obscured by other UI elements.
- Ad Title: Display the ad’s headline.
- CTA (Call to Action): Include a CTA button such as “Install”, “Open”, “Download”. The size and format are flexible.
Registering Native Factory
To use native ads in Flutter, you must register a native ad factory on the native platform (iOS/Android). The factoryId is the identifier of the factory registered on the native platform.
Create Ad Layout XML
Create a native ad layout file in android/app/src/main/res/layout/.<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="400dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:cardBackgroundColor="#1E1E1E">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="12dp">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="56dp"
android:layout_height="56dp"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="12dp"
android:orientation="vertical">
<TextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
android:maxLines="2"
android:ellipsize="end" />
<TextView
android:id="@+id/ad_advertiser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="13sp"
android:layout_marginTop="4dp" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/ad_media"
android:layout_width="match_parent"
android:layout_height="180dp" />
<TextView
android:id="@+id/ad_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:textSize="14sp"
android:maxLines="2"
android:ellipsize="end" />
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginTop="12dp"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
Implement DaroNativeAdFactory
Create a class that implements the DaroNativeAdFactory interface.import android.content.Context
import android.view.LayoutInflater
import android.view.View
import so.daro.flutter.native.DaroNativeAdFactory
import droom.daro.core.model.DaroNativeAdBinder
class SampleNativeAdFactory(private val context: Context) : DaroNativeAdFactory {
override fun createNativeAdView(): View {
return LayoutInflater.from(context).inflate(R.layout.sample_native_ad, null)
}
override fun createAdBinder(view: View): DaroNativeAdBinder {
return DaroNativeAdBinder.Builder(view)
.setTitleViewId(R.id.ad_headline)
.setBodyTextViewId(R.id.ad_body)
.setIconViewId(R.id.ad_app_icon)
.setMediaViewGroupId(R.id.ad_media)
.setCallToActionViewId(R.id.ad_call_to_action)
.build()
}
}
Register Factory in MainActivity
Register the factory in configureFlutterEngine of your MainActivity.import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import so.daro.flutter.DaroFlutterPlugin
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
DaroFlutterPlugin.registerNativeAdFactory(
SampleNativeAdFactory(this),
"sample_native_ad"
)
}
}
Implement DaroNativeAdFactory
Create a factory class that implements the DaroNativeAdFactory protocol and a custom view that inherits from DaroAdNativeView.SampleNativeAdFactory.swift
import UIKit
import daro_flutter
import Daro
class SampleNativeAdFactory: NSObject, DaroNativeAdFactory {
func createNativeAdView(unit: DaroAdUnit) -> DaroAdNativeView {
return SampleNativeAdContentView(unit: unit)
}
}
final class SampleNativeAdContentView: DaroAdNativeView {
init(unit: DaroAdUnit) {
super.init(unit: unit)
setupUI()
}
@available(*, unavailable)
public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Define UI elements
let iconImageView: UIImageView = {
let view = UIImageView()
view.contentMode = .scaleAspectFill
view.layer.cornerRadius = 8
view.clipsToBounds = true
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16, weight: .bold)
label.numberOfLines = 2
return label
}()
let advertiserLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 13)
label.numberOfLines = 1
return label
}()
let bodyLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14)
label.numberOfLines = 2
return label
}()
let mediaContentView = UIView()
let callToActionButton: UIButton = {
let button = UIButton()
button.titleLabel?.font = .systemFont(ofSize: 16, weight: .bold)
button.backgroundColor = .systemBlue
button.layer.cornerRadius = 8
return button
}()
private func setupUI() {
// Configure layout (AutoLayout, etc.)
// ...
// Bind views to Daro SDK
bindViews(
titleLabel: titleLabel,
advertiserLabel: advertiserLabel,
bodyLabel: bodyLabel,
iconImageView: iconImageView,
mediaContentView: mediaContentView,
callToActionButton: callToActionButton
)
}
}
Register Factory in AppDelegate
Register the factory in application(_:didFinishLaunchingWithOptions:) of your AppDelegate.import Flutter
import UIKit
import daro_flutter
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
DaroFlutterPlugin.registerNativeAdFactory(
SampleNativeAdFactory(),
factoryId: "sample_native_ad"
)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
The factoryId passed to Flutter’s DaroNativeAdWidget must exactly match the factory ID registered on the native platform.
import 'package:daro_flutter/daro_flutter.dart';
DaroNativeAdWidget(
adUnitId: '{YOUR_AD_UNIT_ID}',
factoryId: '{YOUR_FACTORY_ID}',
onAdLoaded: (adInfo) {
print('Native ad loaded: ${adInfo.adUnitId}');
},
onAdFailedToLoad: (error) {
print('Native ad failed to load: ${error.message}');
},
onAdClicked: (adInfo) {
print('Native ad clicked');
},
onAdImpression: (adInfo) {
print('Native ad impression');
},
)
Callback Reference
| Callback | Description |
|---|
onAdLoaded | Called when the ad is successfully loaded |
onAdFailedToLoad | Called when ad loading fails |
onAdClicked | Called when the user clicks the ad |
onAdImpression | Called when an ad impression is recorded |
LINE Native Ads
- LINE native ads are compact native ad formats designed to be naturally inserted into feeds or lists.
- They are more compact than standard native ads, ideal for embedding between list items.
- The ad height is fixed at 36dp (Android) / 36pt (iOS).
- Styles can be customized to match your app’s UI.
DaroLineNativeAdWidget(
adUnitId: '{YOUR_AD_UNIT_ID}',
onAdLoaded: (adInfo) {
print('Line native ad loaded: ${adInfo.adUnitId}');
},
onAdFailedToLoad: (error) {
print('Line native ad failed to load: ${error.message}');
},
onAdClicked: (adInfo) {
print('Line native ad clicked');
},
onAdImpression: (adInfo) {
print('Line native ad impression');
},
)
Callback Reference
| Callback | Description |
|---|
onAdLoaded | Called when the ad is successfully loaded |
onAdFailedToLoad | Called when ad loading fails |
onAdClicked | Called when the user clicks the ad |
onAdImpression | Called when an ad impression is recorded |
Style Customization
Use DaroLineNativeAdStyle to customize the colors of LINE native ads.
DaroLineNativeAdWidget(
adUnitId: '{YOUR_AD_UNIT_ID}',
style: DaroLineNativeAdStyle(
backgroundColor: '#FFFFFF',
contentColor: '#000000',
adMarkLabelTextColor: '#FFFFFF',
adMarkLabelBackgroundColor: '#888888',
),
onAdLoaded: (adInfo) {
print('Line native ad loaded');
},
onAdFailedToLoad: (error) {
print('Line native ad failed: ${error.message}');
},
)
Style Properties
| Property | Description |
|---|
backgroundColor | Overall ad background color |
contentColor | Ad content text color |
adMarkLabelTextColor | Ad mark label text color |
adMarkLabelBackgroundColor | Ad mark label background color |