Перейти к основному содержимому
Версия: 4.2.0

Руководство по интеграции

Полное руководство по интеграции BidMachine Plus Android SDK.

BidMachine Plus Android SDK

BidMachine Plus предоставляет два пути получения спроса через единый API:

ModeОписание
AdNetworkBidMachine работает как источник спроса хедер-биддинга — самостоятельно или подключённый к сторонней медиации
MediationBidMachine сам выступает платформой медиации, проводя аукцион по всему вашему спросу

Одни и те же классы рекламных юнитов — BannerAd, InterstitialAd, RewardedAd — работают в обоих режимах. Активный режим выбирается при инициализации.

На этой странице описаны установка SDK, инициализация и загрузка рекламы. Доступны два пути установки: автоматический через ИИ-агенты для кодирования или ручная настройка через Gradle.

Автоматическая интеграция с ИИ-агентами для кодирования

Бандл BidMachine Plus SDK Agents поставляет переносимый навык интеграции для Claude Code, Codex и Gemini. Установите его для вашей среды выполнения:

/plugin marketplace add bidmachine/bidmachine-sdk-agents
/plugin install bidmachine-sdk-agents@bidmachine

Затем попросите своего агента интегрировать BidMachine Plus — например:

Промпт
Integrate BidMachine Plus into my Android app with interstitial, rewarded, and banner ads.

Встроенный навык управляет интеграцией: добавляет зависимость SDK, инициализирует её в режиме AdNetwork или Mediation, подключает рекламные юниты и устанавливает флаги конфиденциальности (GDPR, CCPA), сохраняя любую уже существующую настройку рекламы.

Ручная установка

Требуется Android SDK 23+, Gradle 8.7+, Android Gradle Plugin 8.6+, Kotlin 2.1+ и совместимость source/target с Java 17.

Добавьте Maven-репозиторий BidMachine и зависимость SDK в build.gradle уровня приложения:

app/build.gradle
repositories {
maven { url "https://artifactory.bidmachine.io/bidmachine" }
}

dependencies {
implementation "io.bidmachine.plus:sdk:0.0.1" // BidMachine Plus SDK
implementation "com.google.android.gms:play-services-ads-identifier:18.2.0" // required for advertising ID
}

Конфигурация сетевой безопасности

SDK требуется доступ к сети — добавьте разрешение INTERNET и ссылку на конфигурацию сетевой безопасности в AndroidManifest.xml:

AndroidManifest.xml
<manifest>
<uses-permission android:name="android.permission.INTERNET" />
<application android:networkSecurityConfig="@xml/network_security_config" />
</manifest>

Создайте res/xml/network_security_config.xml:

res/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<debug-overrides>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>

Инициализация

Вызовите BidMachine.initialize один раз при запуске приложения. Передайте нужный режим, чтобы выбрать путь получения спроса.

BidMachine.instance возвращает экземпляр SDK — сохраните ссылку на него; вы будете передавать её в конструктор каждого рекламного юнита.

BidMachine Plus инициализируется в одном из двух режимов, выбираемом значением IntegrationType, которое вы передаёте в билдер:

Режим AdNetwork

BidMachine работает как рекламная сеть хедер-биддинга. Когда он подключается к сторонней медиации, укажите эту платформу через withMediator, чтобы он мог конкурировать в вотерфолле.

val sdk = BidMachine.instance(context, "YOUR_APP_KEY")

val config = InitializationConfigBuilder(IntegrationType.AdNetwork)
.withMediator(MediatorName.ADMOB) // the mediation BidMachine plugs into — or LEVEL_PLAY, MAX, a custom String
.withLoggingEnabled(true) // remove before release
.withTestModeEnabled(true) // remove before release
.build()

sdk.initialize(config) { status, error ->
if (error != null) Log.e("BidMachine", "init failed: ${error.message}")
}

Режим Mediation

BidMachine сам выступает платформой медиации, проводя аукцион по всему вашему спросу. Передайте IntegrationType.Mediation — стороннего медиатора объявлять не нужно:

val config = InitializationConfigBuilder(IntegrationType.Mediation)
.withLoggingEnabled(true) // remove before release
.withTestModeEnabled(true) // remove before release
.build()

BidMachine.instance(context, "YOUR_APP_KEY").initialize(config) { status, error -> }

В обоих режимах классы рекламных юнитов предоставляют notifyWin() и notifyLoss(winnerEcpm, networkName) для сообщения результата раунда вотерфолла — см. Медиация.

Проводите аукцион на собственном сервере? См. S2S биддинг для описания потока bid-токена и загрузки с bidPayload.

Интеграция рекламы

Все колбэки жизненного цикла рекламы доставляют AdInfo, описывающий рекламу-победителя:

PropertyTypeОписание
placementIdStringИдентификатор плейсмента из панели BidMachine
priceDoubleeCPM ÷ 1000 (например, 0.005 = $5 CPM)
precisionRevenuePrecisionОдно из Estimated, Exact, Unknown
infoMap<String, String>Метаданные сети. Известные ключи: networkName, dsp, ecpm

Читайте сеть-победителя через adInfo.info["networkName"], а доход по каждому показу — через adInfo.price.

adInfo.precision описывает, насколько надёжна эта цена:

ValueЗначение
ExactЦена аукциона в реальном времени — можно доверять для отчётности
EstimatedОценка по историческим данным — считайте приблизительной
UnknownДостоверность не может быть определена

Все колбэки срабатывают в главном потоке, поэтому из них можно напрямую обновлять UI.

Реклама Interstitial

Полноэкранная реклама. Создайте её один раз, загрузите, затем вызовите show, когда она будет готова. Перезагружайте из onAdClosed, чтобы держать рекламу готовой к следующему показу.

MainActivity.kt
class MainActivity : AppCompatActivity(), InterstitialListener {
private lateinit var interstitialAd: InterstitialAd

private fun createInterstitialAd() {
interstitialAd = InterstitialAd(sdk, placementId = "YOUR_PLACEMENT_ID")
interstitialAd.listener = this
interstitialAd.load(this)
}

private fun showInterstitialAd() {
if (interstitialAd.isLoaded) {
interstitialAd.show(this)
} else {
Log.w("BidMachine", "Interstitial ad not ready yet")
}
}

override fun onDestroy() {
super.onDestroy()
interstitialAd.destroy()
}

// InterstitialListener callbacks
override fun onAdLoaded(adInfo: AdInfo) {
Log.d("BidMachine", "Interstitial loaded from ${adInfo.info["networkName"]}")
}

override fun onAdLoadFailed(adInfo: AdInfo?, error: BidMachineError) {
Log.e("BidMachine", "Interstitial load failed: ${error.message}")
}

override fun onAdShown(adInfo: AdInfo) {
Log.d("BidMachine", "Interstitial displayed")
}

override fun onAdShowFailed(adInfo: AdInfo?, error: BidMachineError) {
Log.e("BidMachine", "Interstitial show failed: ${error.message}")
}

override fun onAdClicked(adInfo: AdInfo) {
Log.d("BidMachine", "Interstitial clicked")
}

override fun onAdClosed(adInfo: AdInfo) {
Log.d("BidMachine", "Interstitial closed")
interstitialAd.load(this) // reload for next show
}

override fun onAdExpired(adInfo: AdInfo) {
Log.w("BidMachine", "Interstitial expired before show")
}

override fun onAdRevenuePaid(adInfo: AdInfo) {
Log.d("BidMachine", "Interstitial revenue: ${adInfo.price} from ${adInfo.info["networkName"]}")
}
}
CallbackОписание
onAdLoadedРеклама загружена и готова к показу
onAdLoadFailedНе удалось загрузить рекламу
onAdShownРеклама отображается на весь экран
onAdShowFailedНе удалось отобразить рекламу
onAdClickedПользователь нажал на рекламу
onAdClosedПользователь закрыл рекламу
onAdExpiredСрок действия рекламы истёк до показа
onAdRevenuePaidЗафиксирован оплачиваемый показ

Реклама Rewarded

Тот же жизненный цикл, что и у interstitial, плюс колбэк onAdRewarded, когда пользователь досматривает рекламу и получает вознаграждение.

MainActivity.kt
class MainActivity : AppCompatActivity(), RewardedListener {
private lateinit var rewardedAd: RewardedAd

private fun createRewardedAd() {
rewardedAd = RewardedAd(sdk, placementId = "YOUR_PLACEMENT_ID")
rewardedAd.listener = this
rewardedAd.load(this)
}

private fun showRewardedAd() {
if (rewardedAd.isLoaded) {
rewardedAd.show(this)
} else {
Log.w("BidMachine", "Rewarded ad not ready yet")
}
}

override fun onDestroy() {
super.onDestroy()
rewardedAd.destroy()
}

// RewardedListener callbacks
override fun onAdLoaded(adInfo: AdInfo) {
Log.d("BidMachine", "Rewarded loaded from ${adInfo.info["networkName"]}")
}

override fun onAdRewarded(adInfo: AdInfo, reward: Reward?) {
Log.d("BidMachine", "Reward earned")
// grant reward to the user
}

override fun onAdLoadFailed(adInfo: AdInfo?, error: BidMachineError) {
Log.e("BidMachine", "Rewarded load failed: ${error.message}")
}

override fun onAdShown(adInfo: AdInfo) {}
override fun onAdShowFailed(adInfo: AdInfo?, error: BidMachineError) {}
override fun onAdClicked(adInfo: AdInfo) {}

override fun onAdClosed(adInfo: AdInfo) {
rewardedAd.load(this) // reload for next show
}

override fun onAdExpired(adInfo: AdInfo) {}

override fun onAdRevenuePaid(adInfo: AdInfo) {
Log.d("BidMachine", "Rewarded revenue: ${adInfo.price} from ${adInfo.info["networkName"]}")
}
}
CallbackОписание
onAdLoadedРеклама загружена и готова к показу
onAdRewardedПользователь досмотрел рекламу, выдайте вознаграждение
onAdLoadFailedНе удалось загрузить рекламу
onAdShownРеклама отображается на весь экран
onAdShowFailedНе удалось отобразить рекламу
onAdClickedПользователь нажал на рекламу
onAdClosedПользователь закрыл рекламу
onAdExpiredСрок действия рекламы истёк до показа
onAdRevenuePaidЗафиксирован оплачиваемый показ

Объект Reward, передаваемый в onAdRewarded, предоставляет label: String и amount: Int.

Реклама Banner

BannerAd наследует ViewGroup. Прикрепите его к собственному макету или вызовите show(position), чтобы отобразить его в фиксированной позиции на экране.

SizeРазмерыСценарий использования
Banner320 × 50Стандартный баннер
Leaderboard728 × 90Планшеты
MREC300 × 250Средний прямоугольник
BannerAdSize.adaptive(width, maxHeight)произвольныйАдаптивный макет
подсказка

Используйте BannerAdSize.getMaxAdaptiveHeight(width), чтобы вычислить maxHeight для адаптивных баннеров.

Ручной баннер

Разместите в своём макете контейнер, который будет содержать представление баннера:

res/layout/activity_main.xml
<FrameLayout
android:id="@+id/ad_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />

Получите его один раз в onCreate, затем прикрепите загруженный BannerAd к нему внутри onAdLoaded:

MainActivity.kt
class MainActivity : AppCompatActivity(), BannerListener {
private lateinit var bannerAd: BannerAd
private lateinit var adContainer: FrameLayout

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
adContainer = findViewById(R.id.ad_container)
}

private fun createBannerAd() {
bannerAd = BannerAd(this, sdk, placementId = "YOUR_PLACEMENT_ID", size = BannerAdSize.Banner)
bannerAd.listener = this
bannerAd.load(this)
}

override fun onDestroy() {
super.onDestroy()
bannerAd.destroy()
}

// BannerListener callbacks
override fun onAdLoaded(adInfo: AdInfo) {
Log.d("BidMachine", "Banner loaded from ${adInfo.info["networkName"]}")
adContainer.addView(bannerAd)
}

override fun onAdLoadFailed(adInfo: AdInfo?, error: BidMachineError) {
Log.e("BidMachine", "Banner load failed: ${error.message}")
}

override fun onAdShown(adInfo: AdInfo) {}
override fun onAdShowFailed(adInfo: AdInfo?, error: BidMachineError) {}
override fun onAdClicked(adInfo: AdInfo) {}
override fun onAdExpired(adInfo: AdInfo) {}

override fun onAdRevenuePaid(adInfo: AdInfo) {
Log.d("BidMachine", "Banner revenue: ${adInfo.price} from ${adInfo.info["networkName"]}")
}
}
CallbackОписание
onAdLoadedРеклама загружена и готова к прикреплению в контейнер
onAdLoadFailedНе удалось загрузить рекламу
onAdShownРеклама видна на экране, показ зафиксирован
onAdShowFailedНе удалось отобразить рекламу
onAdClickedПользователь нажал на рекламу
onAdExpiredСрок действия рекламы истёк до показа
onAdRevenuePaidЗафиксирован оплачиваемый показ

Позиционированный баннер

Вызовите show(position) на загруженном BannerAd, чтобы отобразить его в одной из позиций ниже. Вызовите hide(), чтобы убрать его с экрана.

PositionConstant
СверхуBannerPosition.HorizontalTop
СнизуBannerPosition.HorizontalBottom
СлеваBannerPosition.VerticalLeft
СправаBannerPosition.VerticalRight
val bannerAd = BannerAd(this, sdk, placementId = "YOUR_PLACEMENT_ID", size = BannerAdSize.Banner)
bannerAd.listener = object : BannerListener {
override fun onAdLoaded(adInfo: AdInfo) {
bannerAd.show(BannerPosition.HorizontalBottom) // default position
}
override fun onAdLoadFailed(adInfo: AdInfo?, error: BidMachineError) {}
override fun onAdShown(adInfo: AdInfo) {}
override fun onAdShowFailed(adInfo: AdInfo?, error: BidMachineError) {}
override fun onAdClicked(adInfo: AdInfo) {}
override fun onAdExpired(adInfo: AdInfo) {}
override fun onAdRevenuePaid(adInfo: AdInfo) {}
}
bannerAd.load(this)

// Later:
bannerAd.hide() // remove the overlay; show(position) can re-display it
bannerAd.destroy()

Дополнительные данные паблишера

Прикрепляйте произвольные пары key → value, передаваемые вместе с bid-запросом как дополнительные данные паблишера. API существует на двух уровнях с одинаковой формой — выберите тот, что соответствует нужной вам области применения.

ScopeГде вызыватьПрименяется к
SDK-widesdk.addExtraКаждому аукциону этого экземпляра
Per ad unit<AdUnit>.addExtraТолько к аукционам этого плейсмента

Передача null в качестве значения удаляет ключ. Дополнительные данные на уровне рекламного юнита переопределяют значения уровня SDK для того же ключа на этом плейсменте.

На уровне SDK

val sdk = BidMachine.instance(context, "YOUR_APP_KEY")

sdk.addExtra("user_segment", "whale")
sdk.addExtra("ab_bucket", "control")

val all: Map<String, String> = sdk.extras
sdk.addExtra("ab_bucket", null) // remove

На уровне рекламного юнита

Доступно на BannerAd, InterstitialAd и RewardedAd:

interstitialAd.addExtra("placement_context", "level_complete")
bannerAd.addExtra("screen", "main_menu")

val extras: Map<String, String> = interstitialAd.extras