@hotfyllc/wrapper-sdk-rn
v0.7.0
Published
Hotfy Wrapper SDK for React Native — remote-controlled ad orchestration (interstitial, app open, rewarded, banner, native) for AdMob and GAM, configured via the Hotfy App Console.
Downloads
1,287
Readme
@hotfyllc/wrapper-sdk-rn
Wrapper SDK da Hotfy para React Native — orquestração remota de anúncios (interstitial, app open, rewarded, banner, native) com AdMob e GAM, configurada via Hotfy App Console.
O que esse SDK te dá
- Config remota: ad units por tela por segmento, decididos no console — mude no dashboard, sem rebuild do app
- Pool embutido: interstitials são pré-carregados por ad unit, em paralelo, com re-preload automático após cada exibição
- Boot ad: app open ou interstitial no slot do splash, com timeout e fallback
- Rewarded ads: API
Promise<boolean> - Banner & Native components:
<WrapperBanner>euseNativeAdhook - Logs padronizados:
Ad [TYPE] ACTION key=value...pra grep / dashboards - API de eventos: pluga em qualquer analytics (Hotfy CDP, Mixpanel, Amplitude, Sentry...) — o SDK é zero-dep de analytics
- Guards de test ad: bloqueia builds de produção de servir ad units de teste por engano
Instalação
npm install @hotfyllc/wrapper-sdk-rn react-native-google-mobile-adsVocê também precisa configurar o react-native-google-mobile-ads no app
(AdMob app ID em app.json/Info.plist/AndroidManifest.xml,
SKAdNetwork IDs no iOS). Ver os
docs oficiais.
Peer dependencies
| Pacote | Versão |
|---|---|
| react-native | >=0.70.0 |
| react-native-google-mobile-ads | >=14.0.0 |
| react | * |
Quick start
1. Inicializa uma vez no boot do app
import AsyncStorage from '@react-native-async-storage/async-storage'
import { HotfyWrapper, startAdPreload } from '@hotfyllc/wrapper-sdk-rn'
await HotfyWrapper.init({
appId: 'uuid-do-seu-app-no-console',
baseUrl: 'https://api.console.hotfy.com',
storage: AsyncStorage,
// O SDK classifica a origem do user (google_ads, meta_ads, organic, ...)
// a partir desses campos crus — passe o que tiver do install referrer.
utmSource,
utmMedium,
utmCampaign,
utmContent, // ← necessário pra detectar Meta Install Referrer
// encriptado (blob começa com `{"app":`)
gclid, // ← se veio de Google Ads
daysSinceInstall, // calculado do seu first-open timestamp
useTestAds: __DEV__, // opcional — default já é __DEV__
debug: __DEV__,
})
startAdPreload() // pré-carrega todos os interstitials configurados pro segmento resolvidoO backend resolve o segmento (d0_meta, d0_google, d0_organic, etc.)
a partir desses campos. Passa o que tiver — o SDK escolhe a heurística
certa internamente (sem precisar você classificar no app).
2. Mostra um interstitial
import { showInterstitial } from '@hotfyllc/wrapper-sdk-rn'
const handleProceed = async () => {
await showInterstitial('cart_proceed')
router.push('/checkout')
}A screenKey é o único contrato entre o app e o console. O console decide
qual ad unit (ou fallback) servir pra essa tela no segmento do user. Se
nenhum unit tá configurado, a chamada resolve silenciosamente (no-op).
3. Mostra boot ad durante o splash
import { loadAndShowBootAd } from '@hotfyllc/wrapper-sdk-rn'
// antes de SplashScreen.hideAsync() / router.replace
await loadAndShowBootAd({ timeoutMs: 4000 })Suporta tanto app_open quanto interstitial no slot do boot, com
fallback automático se o primário não preencher dentro do orçamento de tempo.
4. Mostra um rewarded ad
import { showRewarded } from '@hotfyllc/wrapper-sdk-rn'
const earned = await showRewarded({ screenKey: 'chat' })
if (earned) unlockTurn()5. Banner
import { WrapperBanner } from '@hotfyllc/wrapper-sdk-rn'
<WrapperBanner screenKey="home" size="adaptive" />
<WrapperBanner screenKey="feed" size="medium_rectangle" />Tamanhos: adaptive (anchored adaptive — recomendado), inline_adaptive,
banner (320×50), large_banner (320×100), medium_rectangle (300×250),
full_banner (468×60), leaderboard (728×90).
O componente renderiza null se ads estiverem desativados ou não tiver
unit configurado pra essa tela. Cai pra screens[X].banner_fallback se o
primário falhar ao carregar.
6. Native ad (hook)
Native ads no react-native-google-mobile-ads v14+ exigem compor
<NativeAdView> + <NativeAsset> da própria lib. O wrapper fornece um
hook useNativeAd que cuida do load, fallback e emissão de eventos; você
compõe o layout:
import {
useNativeAd,
NativeAdView,
NativeAsset,
NativeAssetType,
} from '@hotfyllc/wrapper-sdk-rn'
function FeedNativeAd() {
const { ad } = useNativeAd('feed')
if (!ad) return null
return (
<NativeAdView nativeAd={ad} style={{ height: 90 }}>
<NativeAsset assetType={NativeAssetType.ICON}>
<View style={styles.icon} />
</NativeAsset>
<NativeAsset assetType={NativeAssetType.HEADLINE}>
<Text style={styles.headline} numberOfLines={1} />
</NativeAsset>
<NativeAsset assetType={NativeAssetType.BODY}>
<Text style={styles.body} numberOfLines={2} />
</NativeAsset>
<NativeAsset assetType={NativeAssetType.CALL_TO_ACTION}>
<View style={styles.cta}>
<Text style={styles.ctaText} />
</View>
</NativeAsset>
</NativeAdView>
)
}Os componentes <NativeAsset> auto-populam seus <Text>/<View> filhos
com o asset correspondente — não precisa passar valores manualmente.
Nota: RN-GMA v14+ só expõe um evento
IMPRESSIONsem payload pra native ads — não temPAIDcom dados de receita. O wrapper emite'impression'pra native ads comrevenueMicros,value,currencyeprecisionindefinidos. Chequeif (e.revenueMicros !== undefined)antes de usar campos de receita no listener de impression.
Eventos — pluga em qualquer analytics
O SDK emite eventos tipados. Pluga eles em qualquer stack de analytics — o próprio SDK não tem dependência de analytics.
import { HotfyWrapper } from '@hotfyllc/wrapper-sdk-rn'
import { HotfyCdp } from '@hotfyllc/hotfy-sdk-rn'
HotfyWrapper.on('impression', (e) => {
HotfyCdp.trackAdImpression({
revenueMicros: e.revenueMicros ?? 0,
currency: e.currency,
precision: e.precision,
adUnitId: e.adUnitId,
adSource: e.network,
adFormat: e.format,
})
})
HotfyWrapper.on('error', (e) => {
Sentry.captureMessage(`Ad ${e.format} ${e.reason}: ${e.message}`)
})Eventos disponíveis
| Evento | Quando dispara |
|---|---|
| load | Ad começou a carregar |
| show | Ad foi mostrado pro user |
| close | User fechou o ad |
| impression | Evento PAID do GMA — receita confirmada (use pra revenue tracking) |
| error | Falha no load ou show |
| skip | Ad pulado (sem unit configurado, slot vazio, ads desativados, etc.) |
A função on() retorna uma função de unsubscribe:
const off = HotfyWrapper.on('impression', listener)
// depois, se quiser parar de escutar:
off()Como funciona
O pool é indexado por unitId, não por screenKey. Cada ad unit único
ganha seu próprio slot, pré-carregado em paralelo no startup. Chamar
showInterstitial(screenKey) faz lookup do unit configurado pra essa
tela e mostra do slot dele — garantindo que o unit correto sempre
apareça na tela correta.
Pra detalhes mais profundos da arquitetura — modelo do pool, inventário
por unit, semântica do SKIP, decisões de design — ver
about.md.
Contribuindo
PRs contra main passam por um pipeline de checks automáticos:
tsc --noEmit— type checkvitest run— testes unitários (emsrc/lib/*.test.ts)eslint .— lint (comno-unused-varscomo error, escape hatch_)prettier --check .— formato canônico
O husky/lint-staged já cobre o pre-commit local — npm run lint antes
de commitar resolve 99% dos casos. Detalhes completos do pipeline +
convenção do prefixo _ em docs/pipeline.md.
Releases
O publish no npm é automático via GitHub Actions + OIDC Trusted Publishing — sem token armazenado, sem rotação manual. Fluxo:
- Abre PR bumpando
versionempackage.json(semver — patch/minor/major) - Merge na
main - Workflow
release.ymldetecta versão nova →npm publish+ cria tag gitv<version>
Versão não mudou? Workflow roda mas não publica (silêncio limpo —
"nada a fazer"). Detalhes em docs/pipeline.md.
Licença
UNLICENSED — proprietário. Copyright (c) 2026 Hotfy LLC. Todos os direitos reservados. Ver LICENSE pros termos. Sem uso, modificação ou distribuição sem permissão escrita prévia da Hotfy LLC.
