npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-adpopcorn

v1.4.2

Published

AdPopcorn Offerwall SDK module for Expo

Readme

expo-adpopcorn

AdPopcorn Offerwall SDK module for Expo.

Two ways to serve ads:

  1. Offerwall — the SDK's full-screen campaign list page.
  2. 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-adpopcorn

This 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 / AdPopcornHashKey to Info.plist. The iOS SDK requires a runtime setAppKey call, so the module reads these keys and calls setAppKey automatically before any other SDK call — no app code needed.
  • Android — writes adpopcorn_app_key / adpopcorn_hash_key <meta-data> entries to AndroidManifest.xml (read directly by the SDK), sets adpopcorn_reward_server_type to server (server-to-server reward postbacks — override with the androidRewardServerType prop), and adds the INTERNET / ACCESS_NETWORK_STATE permissions.

Then regenerate the native projects:

npx expo prebuild

Usage

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 === 0

3. 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 android

License

MIT