232 lines
7.9 KiB
Markdown
232 lines
7.9 KiB
Markdown
# Mediation Patterns
|
|
|
|
How ad mediation works in decompiled Android code — identifying the primary mediator, adapter chains, waterfall vs bidding, and configuration extraction.
|
|
|
|
## What is Mediation
|
|
|
|
Ad mediation allows an app to use multiple ad networks through a single SDK. A **mediator** (e.g., AdMob, IronSource, AppLovin MAX) orchestrates which ad network serves each impression via:
|
|
|
|
- **Waterfall**: Networks are tried in priority order; first to fill wins
|
|
- **Bidding (header bidding)**: Networks bid simultaneously; highest bid wins
|
|
- **Hybrid**: Some networks bid, others fill via waterfall
|
|
|
|
## Identifying the Primary Mediator
|
|
|
|
The mediator is the SDK that controls ad loading. Look for:
|
|
|
|
### Google AdMob Mediation
|
|
```java
|
|
// AdMob is the mediator when you see mediation adapters:
|
|
com.google.ads.mediation.*
|
|
// Adapter classes follow the pattern:
|
|
com.google.ads.mediation.unity.UnityAdapter
|
|
com.google.ads.mediation.ironsource.IronSourceMediationAdapter
|
|
com.google.ads.mediation.applovin.AppLovinMediationAdapter
|
|
com.google.ads.mediation.facebook.FacebookMediationAdapter
|
|
com.google.ads.mediation.vungle.VungleMediationAdapter
|
|
```
|
|
|
|
**Grep**:
|
|
```bash
|
|
grep -rn 'com\.google\.ads\.mediation\.' "$SOURCE_DIR"
|
|
```
|
|
|
|
### IronSource / LevelPlay Mediation
|
|
```java
|
|
// IronSource is the mediator when you see adapter packages:
|
|
com.ironsource.adapters.*
|
|
// Adapter naming:
|
|
com.ironsource.adapters.admob.*
|
|
com.ironsource.adapters.unityads.*
|
|
com.ironsource.adapters.applovin.*
|
|
com.ironsource.adapters.facebook.*
|
|
com.ironsource.adapters.vungle.*
|
|
```
|
|
|
|
**Grep**:
|
|
```bash
|
|
grep -rn 'com\.ironsource\.adapters\.' "$SOURCE_DIR"
|
|
```
|
|
|
|
### AppLovin MAX Mediation
|
|
```java
|
|
// MAX is the mediator when you see MAX adapter packages:
|
|
com.applovin.mediation.adapters.*
|
|
// Adapter classes extend MediationAdapterBase:
|
|
com.applovin.mediation.adapters.GoogleMediationAdapter
|
|
com.applovin.mediation.adapters.UnityAdsMediationAdapter
|
|
com.applovin.mediation.adapters.IronSourceMediationAdapter
|
|
com.applovin.mediation.adapters.FacebookMediationAdapter
|
|
```
|
|
|
|
**Grep**:
|
|
```bash
|
|
grep -rn 'com\.applovin\.mediation\.adapters\.' "$SOURCE_DIR"
|
|
```
|
|
|
|
## Waterfall vs Bidding
|
|
|
|
### Waterfall indicators
|
|
```bash
|
|
# Priority/floor price configuration
|
|
grep -rn 'waterfall\|floorPrice\|ecpm\|eCPM\|setPriority\|adNetworkOrder' "$SOURCE_DIR"
|
|
|
|
# Manual network ordering
|
|
grep -rn 'setNetworkOrder\|setAdapterOrder\|setWaterfallConfiguration' "$SOURCE_DIR"
|
|
```
|
|
|
|
### Bidding indicators
|
|
```bash
|
|
# Real-time bidding signals
|
|
grep -rn 'bidding\|headerBidding\|bidToken\|collectSignal\|getBiddingToken' "$SOURCE_DIR"
|
|
|
|
# Bidding adapter classes (often have "Bidding" in the name)
|
|
grep -rn 'BiddingAdapter\|BiddingProvider\|RTBAdapter' "$SOURCE_DIR"
|
|
|
|
# MAX bidding
|
|
grep -rn 'MaxMediatedNetworkInfo\|isBidding\|bidFloor' "$SOURCE_DIR"
|
|
```
|
|
|
|
## Adapter Discovery
|
|
|
|
### List all mediation adapters present
|
|
```bash
|
|
# Find all adapter class files
|
|
find "$SOURCE_DIR" -path "*/mediation/adapters/*.java" -o -path "*/adapters/*Adapter*.java" | head -50
|
|
|
|
# Find adapter registration/initialization
|
|
grep -rn 'registerAdapter\|initializeAdapter\|setAdapterState\|MediationAdapter' "$SOURCE_DIR"
|
|
```
|
|
|
|
### Extract adapter configuration
|
|
```bash
|
|
# Network IDs and app keys passed to adapters
|
|
grep -rn 'setAppKey\|setAppId\|setGameId\|setSdkKey\|setNetworkKey' "$SOURCE_DIR"
|
|
|
|
# Ad unit/placement mapping (mediator → network)
|
|
grep -rn 'placementMap\|adUnitMap\|networkPlacementId\|customEventExtras' "$SOURCE_DIR"
|
|
```
|
|
|
|
## Common Mediation Setups
|
|
|
|
### Setup 1: AdMob as Mediator
|
|
```
|
|
AdMob (primary) → loads via:
|
|
├── Google Ads (direct)
|
|
├── UnityAdapter → Unity Ads SDK
|
|
├── IronSourceMediationAdapter → IronSource SDK
|
|
├── AppLovinMediationAdapter → AppLovin SDK
|
|
└── FacebookMediationAdapter → Meta AN SDK
|
|
```
|
|
|
|
### Setup 2: IronSource/LevelPlay as Mediator
|
|
```
|
|
IronSource (primary) → loads via:
|
|
├── IronSource Network (direct)
|
|
├── AdMob adapter → Google Mobile Ads SDK
|
|
├── Unity adapter → Unity Ads SDK
|
|
├── AppLovin adapter → AppLovin SDK
|
|
└── Vungle adapter → Vungle SDK
|
|
```
|
|
|
|
### Setup 3: AppLovin MAX as Mediator
|
|
```
|
|
AppLovin MAX (primary) → loads via:
|
|
├── AppLovin Network (direct, always bidding)
|
|
├── GoogleMediationAdapter → AdMob SDK
|
|
├── IronSourceMediationAdapter → IronSource SDK
|
|
├── UnityAdsMediationAdapter → Unity Ads SDK
|
|
└── FacebookMediationAdapter → Meta AN SDK
|
|
```
|
|
|
|
## Active vs Passive SDKs
|
|
|
|
When mediation is present, most ad SDKs in the APK are **passive dependencies** — they are only invoked internally by the mediator's adapter classes, never by the app's own code.
|
|
|
|
### The Entry Point Graph
|
|
|
|
```
|
|
App code (com.example.myapp.*)
|
|
│
|
|
▼
|
|
Mediator SDK (e.g., AdMob) ← ACTIVE: called by app code
|
|
│
|
|
├──→ Adapter (com.google.ads.mediation.unity.*)
|
|
│ └──→ Unity Ads SDK ← PASSIVE: called only by adapter
|
|
│
|
|
├──→ Adapter (com.google.ads.mediation.ironsource.*)
|
|
│ └──→ IronSource SDK ← PASSIVE: called only by adapter
|
|
│
|
|
└──→ Adapter (com.google.ads.mediation.applovin.*)
|
|
└──→ AppLovin SDK ← PASSIVE: called only by adapter
|
|
```
|
|
|
|
### How to Distinguish
|
|
|
|
An SDK is **active** if its init/load/show calls appear in app code. An SDK is **passive** if its code is present only inside library packages.
|
|
|
|
**Key principle**: Search for SDK calls only in non-library directories. Known library packages to exclude:
|
|
|
|
| Package prefix | SDK |
|
|
|---|---|
|
|
| `com/google` | Google/AdMob |
|
|
| `com/unity3d` | Unity Ads |
|
|
| `com/ironsource` | IronSource/LevelPlay |
|
|
| `com/applovin` | AppLovin/MAX |
|
|
| `com/facebook` | Meta Audience Network |
|
|
| `com/vungle`, `io/vungle` | Vungle/Liftoff |
|
|
| `com/inmobi` | InMobi |
|
|
| `com/chartboost` | Chartboost |
|
|
| `com/bytedance`, `com/pgl` | Pangle/TikTok |
|
|
| `com/mbridge`, `com/mintegral` | Mintegral |
|
|
|
|
### Grep Examples
|
|
|
|
```bash
|
|
# Search for ad SDK calls ONLY in app code (exclude all library packages)
|
|
grep -rn --include="*.java" --include="*.kt" \
|
|
--exclude-dir="com/google" --exclude-dir="com/unity3d" \
|
|
--exclude-dir="com/ironsource" --exclude-dir="com/applovin" \
|
|
--exclude-dir="com/facebook" --exclude-dir="com/vungle" \
|
|
--exclude-dir="com/inmobi" --exclude-dir="com/chartboost" \
|
|
--exclude-dir="com/bytedance" --exclude-dir="com/pgl" \
|
|
--exclude-dir="com/mbridge" \
|
|
-E '(MobileAds\.initialize|UnityAds\.initialize|IronSource\.init|AppLovinSdk\.getInstance)' \
|
|
"$SOURCE_DIR"
|
|
```
|
|
|
|
**Interpreting results**:
|
|
- If `MobileAds.initialize` appears in `com/example/myapp/AdManager.java` → AdMob is **active**
|
|
- If `UnityAds.initialize` appears only in `com/google/ads/mediation/unity/UnityAdapter.java` → Unity Ads is **passive** (but this file is excluded, so it won't show up)
|
|
- If `UnityAds.initialize` appears in `com/example/myapp/AdsHelper.java` → Unity Ads is also **active** (direct integration alongside mediation)
|
|
|
|
### Architecture Classification
|
|
|
|
| Architecture | Meaning | Example |
|
|
|---|---|---|
|
|
| **Single mediator** | App calls 1 SDK; all others are passive adapter deps | AdMob init + 5 mediated networks |
|
|
| **Multiple direct** | App calls 2+ SDKs directly; no mediation | AdMob banners + Unity interstitials |
|
|
| **Hybrid** | App calls a mediator + some SDKs directly | AdMob mediation + direct IronSource rewarded |
|
|
|
|
### Automated Detection
|
|
|
|
Use the `--entrypoints` flag of `find-ads.sh`:
|
|
|
|
```bash
|
|
bash find-ads.sh <source-dir> --entrypoints
|
|
```
|
|
|
|
This runs the exclusion-based grep automatically and shows only app-initiated SDK calls.
|
|
|
|
## Extracting Mediation Configuration
|
|
|
|
Look for server-side configuration that controls the mediation waterfall:
|
|
|
|
```bash
|
|
# JSON config responses from mediation servers
|
|
grep -rn 'mediationConfig\|auctionResponse\|waterfallConfig\|adNetworkConfig' "$SOURCE_DIR"
|
|
|
|
# Remote config / A/B test for ad setup
|
|
grep -rn 'RemoteConfig.*ad\|firebase.*ad_config\|ad_waterfall\|ad_network_ids' "$SOURCE_DIR"
|
|
```
|