Руководство по интеграции
Полное руководство по интеграции плагина BidMachine Plus для Unity.
Плагин BidMachine Plus для Unity
BidMachine Plus предоставляет два источника спроса через один API:
| Mode | Описание |
|---|---|
| AdNetwork | BidMachine работает как источник спроса с хедер-биддингом — самостоятельно или подключённым к сторонней медиации |
| Mediation | BidMachine сам выступает платформой медиации, проводя аукцион по вашему спросу |
Одни и те же классы рекламных юнитов — BannerAd, InterstitialAd, RewardedAd — работают в обоих режимах. Активный режим выбирается при инициализации.
На этой странице описаны установка плагина, инициализация и загрузка рекламы. Доступны два пути установки: автоматический через ИИ-агенты для кодинга или ручная настройка через Unity Package Manager.
Автоматическая интеграция с ИИ-агентами для кодинга
Бандл BidMachine Plus SDK Agents поставляет переносимый навык интеграции для Claude Code, Codex и Gemini. Установите его для вашей среды выполнения:
- Claude Code
- Gemini CLI
- npx (any agent)
/plugin marketplace add bidmachine/bidmachine-sdk-agents
/plugin install bidmachine-sdk-agents@bidmachine
gemini extensions install https://github.com/bidmachine/bidmachine-sdk-agents
npx skills add bidmachine/bidmachine-sdk-agents
Затем попросите вашего агента добавить BidMachine Plus как First Look перед вашей существующей медиацией — например:
Add BidMachine Plus as a First Look in front of my existing ad mediation in this Unity game.
Встроенный навык управляет интеграцией: устанавливает плагин, инициализирует BidMachine в режиме Mediation и подключает BidMachine Plus как основной источник для interstitial и rewarded — запрашивается первым по таймауту — с фолбэком на вашу существующую медиацию (MAX, AdMob, LevelPlay или другую) при отсутствии заполнения, сохраняя текущую настройку.
First Look покрывает только interstitial и rewarded. Для баннеров используйте ручную настройку ниже — плагин их поддерживает, но в поток First Look они не входят.
Ручная установка
Требуется Unity 2021.3+, Android SDK 23+, iOS 13.0+ и Xcode 16.4+.
Unity Package Manager
BidMachine Plus распространяется через scoped-реестр BidMachine. Зарегистрируйте его, затем установите com.bidmachine.plus. External Dependency Manager подтягивается автоматически как зависимость пакета — отдельный импорт не нужен.
- Editor UI
- manifest.json
- Откройте Edit → Project Settings → Package Manager.
- В разделе Scoped Registries нажмите + и заполните:
- Name:
BidMachine Registry - URL:
https://npm.bidmachine.com - Scope(s):
com.bidmachine
- Name:
- Нажмите Apply.
- Откройте Window → Package Manager, переключите источник на My Registries, выберите BidMachine Plus и нажмите Install.
Добавьте scoped-реестр и зависимость в Packages/manifest.json в корне вашего проекта:
{
"scopedRegistries": [
{
"name": "BidMachine Registry",
"url": "https://npm.bidmachine.com",
"scopes": ["com.bidmachine"]
}
],
"dependencies": {
"com.bidmachine.plus": "0.0.1"
}
}
Настройка Android
В Player Settings → Publishing Settings включите Custom Main Gradle Template и Custom Gradle Settings Template.
В Assets → External Dependency Manager → Android Resolver → Settings включите Patch mainTemplate.gradle, Copy and patch settingsTemplate.gradle from 2022.2 и Use Jetifier. Затем запустите Android Resolver → Resolve.
Обязательные разрешения в AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
Необязательные разрешения:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
Настройка iOS
В Assets → External Dependency Manager → iOS Resolver → Settings отключите Link frameworks statically.
Добавьте в Info.plist экспортированного проекта Xcode:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>SKAdNetworkItems</key>
<array>
<!-- full SKAdNetwork list is published with the SDK -->
</array>
<key>NSUserTrackingUsageDescription</key>
<string>$(APP_NAME) needs your advertising identifier to deliver personalized ads.</string>
Инициализация
Вызовите BidMachine.Initialize один раз при запуске приложения. Передайте нужный режим, чтобы выбрать источник спроса.
BidMachine.GetInstance возвращает экземпляр SDK — сохраните ссылку на него; вы будете передавать его в конструктор каждого рекламного юнита.
BidMachine Plus инициализируется в одном из двух режимов, выбираемых параметром IntegrationMode, который вы передаёте билдеру:
Режим AdNetwork
BidMachine работает как рекламная сеть с хедер-биддингом. Когда он подключается к сторонней медиации, укажите эту платформу через WithMediator, чтобы он мог конкурировать в вотерфолле.
var sdk = BidMachine.GetInstance("YOUR_APP_KEY");
var config = new InitializationConfigBuilder(IntegrationMode.AdNetwork)
.WithMediator(MediationProvider.AdMob) // the mediation BidMachine plugs into — or MediationProvider.LevelPlay, MediationProvider.Max, a custom string
.WithLoggingEnabled(true) // remove before release
.WithTestModeEnabled(true) // remove before release
.Build();
sdk.Initialized += (sender, args) =>
{
if (args.Error != null) Debug.LogError($"init failed: {args.Error.Message}");
};
sdk.Initialize(config);
Режим Mediation
BidMachine сам выступает платформой медиации, проводя аукцион по вашему спросу. Передайте IntegrationMode.Mediation — сторонний медиатор объявлять не нужно:
var config = new InitializationConfigBuilder(IntegrationMode.Mediation)
.WithLoggingEnabled(true) // remove before release
.WithTestModeEnabled(true) // remove before release
.Build();
var sdk = BidMachine.GetInstance("YOUR_APP_KEY");
sdk.Initialized += (sender, args) => { /* ready */ };
sdk.Initialize(config);
В обоих режимах классы рекламных юнитов предоставляют NotifyWin() и NotifyLoss(winnerEcpm, networkName) для сообщения о результате раунда вотерфолла — см. Медиация.
Проводите аукцион на собственном сервере? См. S2S-биддинг для описания потока bid-токена и загрузки с
bidPayload.
Интеграция рекламы
Все события жизненного цикла рекламы доставляют объект AdInfo, описывающий победившую рекламу (через EventArgs.AdInfo):
| Property | Type | Описание |
|---|---|---|
PlacementId | string | ID плейсмента из панели BidMachine |
Price | double | eCPM ÷ 1000 (например, 0.005 = $5 CPM) |
Precision | RevenuePrecision | Одно из Estimated, Exact, Unknown |
RawData | IReadOnlyDictionary<string, string> | Метаданные сети. Известные ключи: networkName, dsp, ecpm |
Читайте победившую сеть через e.AdInfo.RawData["networkName"], а доход по конкретному показу — через e.AdInfo.Price.
e.AdInfo.Precision описывает, насколько надёжна эта цена:
| Value | Значение |
|---|---|
Exact | Цена аукциона в реальном времени — можно доверять для отчётности |
Estimated | Оценка по историческим данным — считайте приблизительной |
Unknown | Достоверность определить невозможно |
Все события рекламы срабатывают в основном потоке Unity, поэтому из них можно напрямую обновлять UI и вызывать API MonoBehaviour.
Реклама Interstitial
Полноэкранная реклама. Создайте один раз, загрузите, затем вызовите Show, когда она готова. Перезагружайте из Closed, чтобы держать рекламу готовой к следующему показу.
public class AdsController : MonoBehaviour
{
private InterstitialAd interstitialAd;
private void CreateInterstitialAd()
{
interstitialAd = new InterstitialAd(sdk, placementId: "YOUR_PLACEMENT_ID");
interstitialAd.Loaded += (s, e) => Debug.Log($"Interstitial loaded from {e.AdInfo.RawData["networkName"]}");
interstitialAd.LoadFailed += (s, e) => Debug.LogError($"Interstitial load failed: {e.Error.Message}");
interstitialAd.Shown += (s, e) => Debug.Log("Interstitial displayed");
interstitialAd.ShowFailed += (s, e) => Debug.LogError($"Interstitial show failed: {e.Error.Message}");
interstitialAd.Clicked += (s, e) => Debug.Log("Interstitial clicked");
interstitialAd.Closed += (s, e) => interstitialAd.Load(); // reload for next show
interstitialAd.Expired += (s, e) => Debug.LogWarning("Interstitial expired before show");
interstitialAd.RevenuePaid += (s, e) => Debug.Log($"Interstitial revenue: {e.AdInfo.Price} from {e.AdInfo.RawData["networkName"]}");
interstitialAd.Load();
}
private void ShowInterstitialAd()
{
if (interstitialAd.IsLoaded)
{
interstitialAd.Show();
}
else
{
Debug.LogWarning("Interstitial ad not ready yet");
}
}
private void OnDestroy()
{
interstitialAd?.Dispose();
}
}
| Callback | Описание |
|---|---|
Loaded | Реклама загружена и готова к показу |
LoadFailed | Не удалось загрузить рекламу |
Shown | Реклама отображается на весь экран |
ShowFailed | Не удалось отобразить рекламу |
Clicked | Пользователь нажал на рекламу |
Closed | Пользователь закрыл рекламу |
Expired | Срок действия рекламы истёк до показа |
RevenuePaid | Зафиксирован оплачиваемый показ |
Реклама Rewarded
Тот же жизненный цикл, что и у interstitial, плюс колбэк UserQualifiedForReward, когда пользователь завершает просмотр рекламы и получает вознаграждение.
public class AdsController : MonoBehaviour
{
private RewardedAd rewardedAd;
private void CreateRewardedAd()
{
rewardedAd = new RewardedAd(sdk, placementId: "YOUR_PLACEMENT_ID");
rewardedAd.Loaded += (s, e) => Debug.Log($"Rewarded loaded from {e.AdInfo.RawData["networkName"]}");
rewardedAd.UserQualifiedForReward += (s, e) =>
{
Debug.Log($"Reward earned: {e.Reward?.Amount} {e.Reward?.Label}");
// grant reward to the user
};
rewardedAd.LoadFailed += (s, e) => Debug.LogError($"Rewarded load failed: {e.Error.Message}");
rewardedAd.Shown += (s, e) => { };
rewardedAd.ShowFailed += (s, e) => { };
rewardedAd.Clicked += (s, e) => { };
rewardedAd.Closed += (s, e) => rewardedAd.Load(); // reload for next show
rewardedAd.Expired += (s, e) => { };
rewardedAd.RevenuePaid += (s, e) => Debug.Log($"Rewarded revenue: {e.AdInfo.Price} from {e.AdInfo.RawData["networkName"]}");
rewardedAd.Load();
}
private void ShowRewardedAd()
{
if (rewardedAd.IsLoaded)
{
rewardedAd.Show();
}
else
{
Debug.LogWarning("Rewarded ad not ready yet");
}
}
private void OnDestroy()
{
rewardedAd?.Dispose();
}
}
| Callback | Описание |
|---|---|
Loaded | Реклама загружена и готова к показу |
UserQualifiedForReward | Пользователь завершил просмотр, выдайте вознаграждение |
LoadFailed | Не удалось загрузить рекламу |
Shown | Реклама отображается на весь экран |
ShowFailed | Не удалось отобразить рекламу |
Clicked | Пользователь нажал на рекламу |
Expired | Срок действия рекламы истёк до показа |
RevenuePaid | Зафиксирован оплачиваемый показ |
Аргументы события UserQualifiedForReward предоставляют Reward (может быть null, если метаданные вознаграждения не заданы), которое содержит Label (string) и Amount (int).
Реклама Banner
BannerAd отображается в виде оверлея, прикреплённого к краю экрана. Загрузите его, затем вызовите Show(position) из обработчика Loaded; вызовите Hide(), чтобы убрать его. Это одноразовый показ — баннер не обновляется автоматически.
| Size | Размеры | Сценарий использования |
|---|---|---|
BannerAdSize.Banner | 320 × 50 | Стандартный баннер |
BannerAdSize.Leaderboard | 728 × 90 | Планшеты |
BannerAdSize.MRec | 300 × 250 | Средний прямоугольник |
BannerAdSize.Adaptive(width, maxHeight) | произвольные | Гибкая компоновка |
Используйте BannerAdSize.GetMaxAdaptiveHeight(width), чтобы вычислить maxHeight для адаптивных баннеров.
Вызовите Show(position) на загруженном BannerAd, чтобы прикрепить его к одной из позиций ниже. Вызовите Hide(), чтобы убрать его с экрана.
| Позиция | Constant |
|---|---|
| Сверху | BannerPosition.HorizontalTop |
| Снизу | BannerPosition.HorizontalBottom |
| Слева | BannerPosition.VerticalLeft |
| Справа | BannerPosition.VerticalRight |
var banner = new BannerAd(sdk, placementId: "YOUR_PLACEMENT_ID", size: BannerAdSize.Banner);
banner.Loaded += (s, e) => banner.Show(BannerPosition.HorizontalBottom); // default position
banner.LoadFailed += (s, e) => Debug.LogError($"Banner load failed: {e.Error.Message}");
banner.Shown += (s, e) => { };
banner.ShowFailed += (s, e) => { };
banner.Clicked += (s, e) => { };
banner.Expired += (s, e) => { };
banner.RevenuePaid += (s, e) => { };
banner.Load();
// Later:
banner.Hide(); // remove the overlay; Show(position) can re-display it
banner.Dispose();
| Event | Описание |
|---|---|
Loaded | Реклама загружена и готова к показу |
LoadFailed | Не удалось загрузить рекламу |
Shown | Баннер виден на экране, показ зафиксирован |
ShowFailed | Не удалось отобразить рекламу |
Clicked | Пользователь нажал на рекламу |
Expired | Срок действия рекламы истёк до показа |
RevenuePaid | Зафиксирован оплачиваемый показ |
Дополнительные данные паблишера
Прикрепляйте произвольные пары ключ → значение, передаваемые с bid-запросом как дополнительные данные паблишера. API существует на двух уровнях с одинаковой формой — выбирайте тот, что соответствует нужной области применения.
| Область | Где вызывать | Применяется к |
|---|---|---|
| Для всего SDK | BidMachine.AddExtra | Каждый аукцион этого экземпляра |
| Для рекламного юнита | <AdUnit>.AddExtra | Только аукционы этого плейсмента |
Передача null в качестве значения удаляет ключ. Дополнительные данные на уровне рекламного юнита переопределяют значения уровня SDK для того же ключа в этом плейсменте.
Для всего SDK
var sdk = BidMachine.GetInstance("YOUR_APP_KEY");
sdk.AddExtra("user_segment", "whale");
sdk.AddExtra("ab_bucket", "control");
IReadOnlyDictionary<string, string> all = sdk.GetExtras();
sdk.AddExtra("ab_bucket", null); // remove
Для рекламного юнита
Доступно на BannerAd, InterstitialAd и RewardedAd:
interstitialAd.AddExtra("placement_context", "level_complete");
bannerAd.AddExtra("screen", "main_menu");
IReadOnlyDictionary<string, string> extras = interstitialAd.GetExtras();