# MonetizeD7 — Partner Integration Guide

**SDK:** `1.1.1` • **Date:** 2026-05-14

This guide covers everything a partner needs to integrate the MonetizeD7 SDK: project setup, ad unit IDs, UI customization, and release checklist.

> All ad display logic, waterfall, fallback, and cadence are controlled by Apero via Firebase Remote Config. Partners only provide ad unit IDs and UI assets.

---

## Table of Contents

1. [Project Setup](#1-project-setup)
2. [FirstOpen Ad Config (by position)](#2-firstopen-ad-config-by-position)
3. [InApp Ad Config (by touchpoint)](#3-inapp-ad-config-by-touchpoint)
4. [Full Application Code](#4-full-application-code)
5. [UI Customization](#5-ui-customization)
6. [Release Checklist](#6-release-checklist)
7. [Troubleshooting](#7-troubleshooting)

---

## 1. Project Setup

### 1.1 Add Apero Repository

File: **`settings.gradle.kts`**

```kotlin
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://artifactory.apero.vn/artifactory/gradle-release/")
            credentials {
                username = "<provided by Apero>"
                password = "<provided by Apero>"
            }
        }
    }
}
```

### 1.2 Add Dependency

File: **`app/build.gradle.kts`**

```kotlin
dependencies {
    implementation("apero-inhouse:monetize-d7:1.1.1")
}
```

### 1.3 Android Manifest

File: **`AndroidManifest.xml`**

```xml
<manifest>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application
        android:name=".MyApplication"
        android:theme="@style/Theme.MyApp">

        <!-- AdMob app ID -->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-XXXXXXXX~YYYYYYYY" />

        <!-- Production: false -->
        <meta-data
            android:name="com.apero.ads.IS_DEVELOPMENT"
            android:value="false" />

        <!-- Splash = launcher -->
        <activity
            android:name=".SplashActivity"
            android:exported="true"
            android:theme="@style/Theme.FOSplash">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity" />
    </application>
</manifest>
```

### 1.4 SplashActivity — one line

```kotlin
class SplashActivity : FOSplashActivity()
```

The SDK handles: consent, remote config fetch, billing, ad load/show, and navigation.

### 1.5 NextActionListener — navigate to Main

```kotlin
class MyNextActionListener : FONextActionListener() {
    override fun onNextScreenListener(activity: ComponentActivity, intent: Intent) {
        activity.startActivity(
            Intent(activity, MainActivity::class.java).putExtras(intent)
        )
        activity.finish()
    }
}
```

---

## 2. FirstOpen Ad Config (by position)

Flow: **Launcher → Splash → Onboarding → Main**. Each ad position lists the IDs you need + the config code.

> **Convention:** No ID for a tier? Pass `""` — SDK skips it automatically.

---

### 2.1 Splash (required)

**Ad unit IDs needed:**

| # | Position | Tier | Format | ID | BuildConfig field |
|---|---|---|---|---|---|
| 1 | Splash Native | 2ID | Native | `ca-app-pub-___/___` | `NATIVE_SPLASH_HF` |
| 2 | Splash Native | Normal | Native | `ca-app-pub-___/___` | `NATIVE_SPLASH` |
| 3 | Splash Inter | 2ID | Interstitial | `ca-app-pub-___/___` | `INTER_SPLASH_HF` |
| 4 | Splash Inter | Normal | Interstitial | `ca-app-pub-___/___` | `INTER_SPLASH` |
| 5 | Splash Banner | 2ID | Banner | `ca-app-pub-___/___` | `BANNER_SPLASH_HF` |
| 6 | Splash Banner | Normal | Banner | `ca-app-pub-___/___` | `BANNER_SPLASH` |

**build.gradle.kts:**

```kotlin
// debug — Google test IDs
buildConfigField("String", "NATIVE_SPLASH_HF", "\"ca-app-pub-3940256099942544/2247696110\"")
buildConfigField("String", "NATIVE_SPLASH",    "\"ca-app-pub-3940256099942544/2247696110\"")
buildConfigField("String", "INTER_SPLASH_HF",  "\"ca-app-pub-3940256099942544/1033173712\"")
buildConfigField("String", "INTER_SPLASH",     "\"ca-app-pub-3940256099942544/1033173712\"")
buildConfigField("String", "BANNER_SPLASH_HF", "\"ca-app-pub-3940256099942544/6300978111\"")
buildConfigField("String", "BANNER_SPLASH",    "\"ca-app-pub-3940256099942544/6300978111\"")

// release — replace with production IDs from AdMob console
buildConfigField("String", "NATIVE_SPLASH_HF", "\"ca-app-pub-XXXX/YYYY\"")
// ... same pattern for all
```

**Config code:**

```kotlin
.setSplashAdConfig(
    FirstOpenConfig.SplashAdConfig(
        nativeSplash2ID = NativeAd2Id(BuildConfig.NATIVE_SPLASH_HF),
        nativeSplash    = NativeAdId(BuildConfig.NATIVE_SPLASH),
        interSplash2ID  = InterAd2Id(BuildConfig.INTER_SPLASH_HF),
        interSplash     = InterAdId(BuildConfig.INTER_SPLASH),
        bannerSplash    = BannerAdDouble(
            highFloor = BannerAd2Id(BuildConfig.BANNER_SPLASH_HF),
            standard  = BannerAdId(BuildConfig.BANNER_SPLASH),
        ),
    )
)
```

---

### 2.2 Onboarding (optional)

**Ad unit IDs needed:**

| # | Position | Tier | Format | ID | BuildConfig field |
|---|---|---|---|---|---|
| 1 | Onboarding Native | 2ID | Native | `ca-app-pub-___/___` | `NATIVE_OB_HF` |
| 2 | Onboarding Native | Normal | Native | `ca-app-pub-___/___` | `NATIVE_OB` |

**Config code:**

```kotlin
.setOnboardingAdConfig(
    FirstOpenConfig.OnboardingAdConfig(
        nativeOnboarding = NativeAdDouble(
            highFloor = NativeAd2Id(BuildConfig.NATIVE_OB_HF),
            standard  = NativeAdId(BuildConfig.NATIVE_OB),
        ),
    )
)
```

> Omit `.setOnboardingAdConfig(...)` entirely if you don't need onboarding ads.

---

### 2.3 Resume — when user returns to app (optional)

**Ad unit IDs needed:**

| # | Position | Tier | Format | ID | BuildConfig field |
|---|---|---|---|---|---|
| 1 | Resume | Normal | App Open | `ca-app-pub-___/___` | `APP_OPEN_RESUME` |
| 2 | Resume | Normal | Native | `ca-app-pub-___/___` | `NATIVE_RESUME` |

**Config code:**

```kotlin
.setResumeAdConfig(
    FirstOpenConfig.ResumeAdConfig(
        appOpenResume = AppOpenAdId(BuildConfig.APP_OPEN_RESUME),
        nativeResume  = NativeAdId(BuildConfig.NATIVE_RESUME),
    )
)
```

> Omit `.setResumeAdConfig(...)` entirely if you don't need resume ads.

---

## 3. InApp Ad Config (by touchpoint)

InApp Ad = ads shown at **trigger points inside your app** (after the first-open flow). Each point is called a **touchpoint (tp)**.

> **Touchpoint names are defined by BA.** Partners **MUST use the exact name** BA has specified — wrong name (including casing) means the SDK cannot match it, ads won't show, and Remote Config won't take effect.
>
> BA: fill in / edit each touchpoint section below before sending to partner.

---

### 3.1 Touchpoint: `home`

| Info | Value |
|---|---|
| **Touchpoint name (`tp`)** | `home` |
| **Description** | Home screen → user taps "next" button → show ad → proceed |
| **Preload where** | `HomeActivity` — use `bindActivity` (SDK auto-preloads on every `onStart`) |
| **Show where** | `HomeActivity` — when user taps the forward button |

**Ad unit IDs needed:**

| # | Tier | Format | ID |
|---|---|---|---|
| 1 | 2ID | Native | `ca-app-pub-___/___` |
| 2 | Normal | Native | `ca-app-pub-___/___` |
| 3 | — | Interstitial | `ca-app-pub-___/___` |

**Register (in Application):**

```kotlin
.register(
    tp = "home",                                           // ← exact name from BA
    nativeAd2Id  = NativeAd2Id(BuildConfig.NATIVE_HOME_HF),
    nativeAdId   = NativeAdId(BuildConfig.NATIVE_HOME),
    inter        = InterAdId(BuildConfig.INTER_HOME),
    bindActivity = HomeActivity::class.java,               // SDK auto-preloads
)
```

**Show (in HomeActivity):**

```kotlin
// bindActivity handles preload — no manual call needed
InAppAdManager.show(this, "home") {
    startActivity(Intent(this, ResultActivity::class.java))
}
```

---

### 3.2 Touchpoint: `share`

| Info | Value |
|---|---|
| **Touchpoint name (`tp`)** | `share` |
| **Description** | Share screen → user taps share → show ad → execute share |
| **Preload where** | `ShareActivity` — use `bindActivity` (SDK auto-preloads on every `onStart`) |
| **Show where** | `ShareActivity` — when user taps share button |

**Ad unit IDs needed:**

| # | Tier | Format | ID |
|---|---|---|---|
| 1 | 2ID | Native | `ca-app-pub-___/___` |
| 2 | Normal | Native | `ca-app-pub-___/___` |
| 3 | — | Interstitial | _(not used)_ |

**Register:**

```kotlin
.register(
    tp = "share",                                           // ← exact name from BA
    nativeAd2Id = NativeAd2Id(BuildConfig.NATIVE_SHARE_HF),
    nativeAdId  = NativeAdId(BuildConfig.NATIVE_SHARE),
    inter       = InterAdId(""),                            // skip inter
    bindActivity = ShareActivity::class.java,
)
```

**Show (in ShareActivity):**

```kotlin
InAppAdManager.show(this, "share") {
    proceedShare()
}
```

---

### 3.N Touchpoint: `___` _(BA adds more following the pattern above)_

| Info | Value |
|---|---|
| **Touchpoint name (`tp`)** | `___` |
| **Description** | _describe position + behavior_ |
| **Preload where** | _which Activity, use `bindActivity` or `bindPreload()`_ |
| **Show where** | _which Activity/Fragment, when to trigger_ |

**Ad unit IDs needed:**

| # | Tier | Format | ID |
|---|---|---|---|
| 1 | 2ID | Native | `ca-app-pub-___/___` |
| 2 | Normal | Native | `ca-app-pub-___/___` |
| 3 | — | Interstitial | `ca-app-pub-___/___` |

---

### Preload — 3 options, pick one

| Option | Where | Code | When to use |
|---|---|---|---|
| `bindActivity` | `register()` call | `bindActivity = XxxActivity::class.java` | Simplest — SDK auto-preloads on every `onStart` |
| `bindPreload()` | Activity/Fragment | `InAppAdManager.bindPreload(this, "tp")` | Need lifecycle control (Fragment, ViewPager) |
| `preload()` | Anywhere | `InAppAdManager.preload("tp")` | Fire-and-forget, no retry |

> If using `bindActivity`, do **NOT** call `bindPreload()` for that touchpoint. If both are set, `bindPreload()` takes priority.

### `show()` contract

- `onNextAction` is **always called exactly once** — whether ad shows, is skipped, or fails.
- `tp` must **match exactly** (case-sensitive) with the value from `register()`.
- Must be called from the **Main thread**.

---

## 4. Full Application Code

File: **`MyApplication.kt`** — init order: Firebase → apero-ads → MonetizeD7.

```kotlin
class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        // ① Firebase
        FirebaseApp.initializeApp(this)

        // ② apero-ads
        val adsConfig = AperoAdConfig(
            this,
            AperoAdConfig.PROVIDER_ADMOB,
            if (BuildConfig.DEBUG) AperoAdConfig.ENVIRONMENT_DEVELOP
            else AperoAdConfig.ENVIRONMENT_PRODUCTION,
        ).apply {
            apiKey = "<APERO_API_KEY>"   // provided by Apero
        }
        AperoAd.getInstance().init(this, adsConfig, false)
        AppOpenManager.getInstance().init(this)
        AppOpenManager.getInstance().disableAppResumeWithActivity(AdActivity::class.java)
        Admob.getInstance().setOpenActivityAfterShowInterAds(true)

        // ③ MonetizeD7
        FirstOpenSDK.configure(
            FirstOpenConfig.Builder(MyNextActionListener())
                .setDevelopment(BuildConfig.DEBUG)

                // ── §2.1 Splash (required) ──
                .setSplashAdConfig(
                    FirstOpenConfig.SplashAdConfig(
                        nativeSplash2ID = NativeAd2Id(BuildConfig.NATIVE_SPLASH_HF),
                        nativeSplash    = NativeAdId(BuildConfig.NATIVE_SPLASH),
                        interSplash2ID  = InterAd2Id(BuildConfig.INTER_SPLASH_HF),
                        interSplash     = InterAdId(BuildConfig.INTER_SPLASH),
                        bannerSplash    = BannerAdDouble(
                            highFloor = BannerAd2Id(BuildConfig.BANNER_SPLASH_HF),
                            standard  = BannerAdId(BuildConfig.BANNER_SPLASH),
                        ),
                    )
                )

                // ── §2.2 Onboarding (optional) ──
                .setOnboardingAdConfig(
                    FirstOpenConfig.OnboardingAdConfig(
                        nativeOnboarding = NativeAdDouble(
                            highFloor = NativeAd2Id(BuildConfig.NATIVE_OB_HF),
                            standard  = NativeAdId(BuildConfig.NATIVE_OB),
                        ),
                    )
                )

                // ── §2.3 Resume (optional) ──
                .setResumeAdConfig(
                    FirstOpenConfig.ResumeAdConfig(
                        appOpenResume = AppOpenAdId(BuildConfig.APP_OPEN_RESUME),
                        nativeResume  = NativeAdId(BuildConfig.NATIVE_RESUME),
                    )
                )

                // ── §3.x InApp (optional) ──
                .setInAppAd(
                    InAppAdConfig.Builder()
                        .register(   // §3.1 home
                            tp = "home",
                            nativeAd2Id  = NativeAd2Id(BuildConfig.NATIVE_HOME_HF),
                            nativeAdId   = NativeAdId(BuildConfig.NATIVE_HOME),
                            inter        = InterAdId(BuildConfig.INTER_HOME),
                            bindActivity = HomeActivity::class.java,
                        )
                        .register(   // §3.2 share
                            tp = "share",
                            nativeAd2Id = NativeAd2Id(BuildConfig.NATIVE_SHARE_HF),
                            nativeAdId  = NativeAdId(BuildConfig.NATIVE_SHARE),
                            inter       = InterAdId(""),
                            bindActivity = ShareActivity::class.java,
                        )
                        .build()
                )
                .build()
        )
    }
}
```

> `tp` names must match exactly with the touchpoint table in §3 as defined by BA.

---

## 5. UI Customization

Place these files in `app/src/main/res/`. The SDK looks them up by **exact resource name** — typo → SDK uses default.

### 5.1 Colors — `res/values/colors.xml`

Override these 4 tokens — the entire SDK UI derives from them:

```xml
<resources>
    <color name="fo_color_primary">#3B86FF</color>
    <color name="fo_color_background">#FFFFFF</color>
    <color name="fo_color_text_title">#202020</color>
    <color name="fo_color_text_sub_title">#494656</color>
</resources>
```

| Token | Default | Applies to |
|---|---|---|
| `fo_color_primary` | `#C90202` | Buttons, dots, active indicators |
| `fo_color_background` | `#FFFFFF` | Screen backgrounds |
| `fo_color_text_title` | `#333333` | Title text |
| `fo_color_text_sub_title` | `#1B232E` | Subtitle text |

### 5.2 Strings — `res/values/strings.xml`

```xml
<resources>
    <!-- Splash -->
    <string name="fo_splash_title">App Name</string>
    <string name="fo_splash_subtitle">Your tagline here</string>

    <!-- Onboarding (required — 3 pairs of title + description) -->
    <string name="fo_onboarding_title_1">Welcome</string>
    <string name="fo_onboarding_description_1">Discover amazing features</string>
    <string name="fo_onboarding_title_2">Powerful Tools</string>
    <string name="fo_onboarding_description_2">Do more with less</string>
    <string name="fo_onboarding_title_3">Ready?</string>
    <string name="fo_onboarding_description_3">Let's get started!</string>
</resources>
```

| Resource | Default | Required? |
|---|---|---|
| `fo_splash_title` | `@string/app_name` | optional |
| `fo_splash_subtitle` | _(empty)_ | optional |
| `fo_onboarding_title_{1,2,3}` | _(empty)_ | **yes** |
| `fo_onboarding_description_{1,2,3}` | _(empty)_ | **yes** |
| `fo_onboarding_button_next` | `Next` | optional |
| `fo_onboarding_button_start` | `Get Started` | optional |

### 5.3 Images — `res/drawable/` and `res/raw/`

| File | Required | Directory | Purpose |
|---|---|---|---|
| `fo_ic_logo_app.webp` | **Yes** | `drawable/` | Splash logo |
| `fo_img_onboarding_1.webp` | **Yes** | `drawable/` | Onboarding page 1 image |
| `fo_img_onboarding_2.webp` | **Yes** | `drawable/` | Onboarding page 2 image |
| `fo_img_onboarding_3.webp` | **Yes** | `drawable/` | Onboarding page 3 image |
| `fo_img_splash_bg.webp` | No | `drawable/` | Splash background |
| `fo_anim_logo_app.json` | No | `raw/` | Lottie animated logo (overrides drawable) |
| `fo_anim_onboarding_{1,2,3}.json` | No | `raw/` | Lottie onboarding (overrides drawable) |

Accepted extensions: `webp`, `png`, `jpg`. Lottie files must be `.json` in `res/raw/`.

Minimum required assets: **`fo_ic_logo_app`** + **`fo_img_onboarding_{1,2,3}`**.

---

## 6. Release Checklist

- [ ] `google-services.json` belongs to the partner's Firebase project
- [ ] `APPLICATION_ID` in manifest matches the partner's AdMob app ID
- [ ] `IS_DEVELOPMENT` in manifest = `false`
- [ ] `APERO_API_KEY` is the production key (provided by Apero)
- [ ] All `ca-app-pub-...` are **production** ad unit IDs (not test IDs)
- [ ] `setDevelopment(BuildConfig.DEBUG)` — not hard-coded to `true`
- [ ] Required assets present: `fo_ic_logo_app` + `fo_img_onboarding_{1,2,3}`
- [ ] Onboarding text set: `fo_onboarding_title_{1,2,3}` + `fo_onboarding_description_{1,2,3}`
- [ ] 4 color tokens overridden to match brand
- [ ] Every `tp` used in `show()` has been `register()`-ed in `Application.onCreate`
- [ ] Tested on real device: launcher → splash → onboarding → main → InApp ad at every touchpoint

---

## 7. Troubleshooting

**Ads don't show?**
1. Ask Apero to set `fo_allow_log_tester = true` on Firebase
2. Filter Logcat: `adb logcat | grep FOR_TESTER_FO`
3. Check registration log:
```
[InAppAd] ═══════ Registered 2 touchpoint(s) ═══════
[InAppAd] ✓ tp=home         native=[hf=ca-app-pub-xxx, std=ca-app-pub-xxx]  inter=[ca-app-pub-xxx]
[InAppAd] ✓ tp=share        native=[hf=ca-app-pub-xxx, std=ca-app-pub-xxx]  inter=✗
[InAppAd] ═══════ End registration ═══════
```

**Splash never ends?**
- Check `google-services.json` is present and Firebase is reachable
- Check Logcat `ForTester` — likely stuck on consent or remote config fetch

**Wrong layout / no UI override applied?**
- Resource names are **case-sensitive** — check exact spelling
- Lottie in `res/raw/` takes precedence over drawable

**Don't have a 2ID (high-floor) ad unit?**
- Pass `NativeAd2Id("")` — SDK skips that tier, uses normal/inter fallback

**Does the partner need to set up Firebase Remote Config?**
- **No.** Remote Config is managed by Apero (BA/Ad Ops). Partner only needs a Firebase project + `google-services.json`.