expo-adpopcorn
v1.4.2
Published
AdPopcorn Offerwall SDK module for Expo
Maintainers
Readme
expo-adpopcorn
AdPopcorn Offerwall SDK module for Expo.
- iOS: AdPopcornOfferwall 5.2.3 (CocoaPods)
- Android: com.igaworks.offerwall:AdPopcornOfferwall 9.2.7 (Maven Central)
Two ways to serve ads:
- Offerwall — the SDK's full-screen campaign list page.
- Self-rendered campaigns — native placement campaign lists exposed as plain
data (or the ready-made
<CampaignList />), rendered directly in React Native.
The public API is aligned with expo-tnk:
setUserId / openOfferwall(options?) / addOfferwallClosedListener /
loadPlacements / participateCampaign(campaign) / openCampaignDetail(campaign) /
getTotalReward / <CampaignList /> share the same names and shapes.
Installation
npx expo install expo-adpopcornThis module requires a development build — it does not work in Expo Go.
Configuration
Add the config plugin to your app.json and set the app key (media key) and hash key
issued from the AdPopcorn console for each platform:
{
"expo": {
"plugins": [
[
"expo-adpopcorn",
{
"iosAppKey": "YOUR_IOS_APP_KEY",
"iosHashKey": "YOUR_IOS_HASH_KEY",
"androidAppKey": "YOUR_ANDROID_APP_KEY",
"androidHashKey": "YOUR_ANDROID_HASH_KEY"
}
]
]
}
}The plugin:
- iOS — writes
AdPopcornAppKey/AdPopcornHashKeytoInfo.plist. The iOS SDK requires a runtimesetAppKeycall, so the module reads these keys and callssetAppKeyautomatically before any other SDK call — no app code needed. - Android — writes
adpopcorn_app_key/adpopcorn_hash_key<meta-data>entries toAndroidManifest.xml(read directly by the SDK), setsadpopcorn_reward_server_typetoserver(server-to-server reward postbacks — override with theandroidRewardServerTypeprop), and adds theINTERNET/ACCESS_NETWORK_STATEpermissions.
Then regenerate the native projects:
npx expo prebuildUsage
1. Set the user id (required)
import { setUserId } from "expo-adpopcorn";
// The value is delivered back to your server in reward postbacks.
await setUserId("user-1234");2. Offerwall
import {
addCampaignCompletedListener,
addOfferwallClosedListener,
getTotalReward,
openOfferwall,
} from "expo-adpopcorn";
// Open the offerwall. `title` / `color` customize the page and persist.
await openOfferwall({ title: "Rewards", color: "#FF6B00" });
// Events
const closed = addOfferwallClosedListener(() => console.log("offerwall closed"));
const completed = addCampaignCompletedListener(() => console.log("campaign completed"));
closed.remove();
completed.remove();openCSPage() opens the customer support page.
Offerwall entry button:
const { count, total } = await getTotalReward();
// e.g. hide the entry button when count === 03. Self-rendered campaigns
Placements are issued from the AdPopcorn console. The library loads them headlessly and hands you plain data — no native view is shown, so everything is rendered 100% in React Native. The current 9.x/5.x SDKs no longer support the legacy style-table customization — this data-level API is the way to build a branded offerwall.
The flow is: loadPlacements (list data, which also carries everything a detail
screen needs) → participateCampaign (the CTA action) — with openCampaignDetail
as the SDK fallback. <CampaignList /> bundles the flow into one component.
<CampaignList />
import { CampaignList } from "expo-adpopcorn";
<CampaignList
placementIds={["placement-a", "placement-b"]}
scrollEnabled={false} // when embedded in an outer ScrollView
onLoad={(campaigns) => console.log(campaigns.length)}
onError={(error) => console.warn(error)}
/>;| Prop | Default | Description |
| --- | --- | --- |
| placementIds | (required) | Native placement ids from the AdPopcorn console. Several placements are merged into one list (deduped by campaignKey, in the given order). Reloads when it changes. |
| rewardUnit | "원" | Reward unit label appended to the reward amount. |
| renderItem | built-in item | (campaign: AdpopcornCampaign) => ReactElement \| null. Replaces the default item UI. |
| onItemPress | participateCampaign | (campaign: AdpopcornCampaign) => void. Replaces the default press behavior — e.g. navigate to your own detail screen. |
| onLoad | — | Called with the merged AdpopcornCampaign[]. |
| onError | — | Called when loading or the default press action fails. |
| scrollEnabled | FlatList default | Pass false inside another scroll view. |
| style / contentContainerStyle | — | Forwarded to the underlying FlatList. |
The default item UI is a light-themed row (icon / title / participation text / reward
button), and the default press participates directly. Note: with a custom
renderItem you own the press handling — wrap your row in a Pressable and either
pass onItemPress or call participateCampaign(campaign) yourself.
Headless
import { loadPlacements, participateCampaign } from "expo-adpopcorn";
const campaigns = await loadPlacements(["placement-a", "placement-b"]);
// campaigns: AdpopcornCampaign[] — the placements merged into one deduped list
// ({ campaignKey, placementId, title, description, reward, iconUrl, imageUrl, cta }).
// Placements that fail to load are skipped; rejects only when every one fails.Render the list — and a detail screen, if you want one — from the campaign data, then run the CTA action when the user taps join:
try {
await participateCampaign(campaign);
} catch (error) {
// campaign ended / already completed / not joinable
}participateCampaign registers the participation without any SDK UI and opens the
advertiser landing URL in the browser. Campaign completion fires the
addCampaignCompletedListener event.
SDK fallback
openCampaignDetail(campaign) hands the campaign over to the SDK instead. The
AdPopcorn SDK has no detail page for placement campaigns, so it registers the join
and opens the advertiser landing itself — same outcome as participateCampaign,
but the SDK drives the flow (kept for API parity with expo-tnk, where it opens the
SDK's detail page).
API
| Function | Description |
| --- | --- |
| setUserId(userId) | Sets the user id used for reward postbacks. |
| setLogEnable(enable) | Enables SDK logging (iOS only). |
| openOfferwall(options?) | Opens the offerwall page. { title?, color? } customize it. |
| openCSPage() | Opens the customer support page. |
| getTotalReward() | Resolves { count, total } — earnable campaigns and reward sum. |
| loadPlacements(placementIds) | Loads placement campaigns as one merged AdpopcornCampaign[]. |
| participateCampaign(campaign) | Headless CTA action — registers the join and opens the landing URL. |
| openCampaignDetail(campaign) | Hands the campaign to the SDK (join + landing, no SDK detail page). |
| <CampaignList /> | Ready-made list: load + render + participate on press. |
| addOfferwallClosedListener(listener) | Fired when the offerwall page is closed. |
| addCampaignCompletedListener(listener) | Fired when a campaign is completed. |
All promise-returning APIs reject with a coded error whose message includes the SDK
error detail. Everything is a no-op or throws UnavailabilityError on web.
Example
See example. Fill in your keys in example/app.json and PLACEMENT_ID
in App.tsx, then:
cd example
pnpm install
pnpm ios # or pnpm androidLicense
MIT
