in_house_ads 1.5.0
in_house_ads: ^1.5.0 copied to clipboard
Reusable in-house (cross-promo) native, banner, interstitial, and rewarded ads for Android Flutter apps.
in_house_ads #
Reusable Android-only Flutter package for cross-promo (in-house) native, banner, and interstitial ads.
Consuming apps supply their own apps.json asset and configure theming / analytics via InHouseAds.configure.
Setup #
1. Add the dependency #
dependencies:
in_house_ads: ^1.0.0
2. Bundle your ads JSON #
Keep an apps.json asset in the host app (schema below) and declare it in the host pubspec.yaml:
flutter:
assets:
- assets/in_house_ads/
3. Configure once at startup #
Call before using any repository / widget APIs (typically in main() before runApp):
import 'package:in_house_ads/in_house_ads.dart';
InHouseAds.configure(
InHouseAdsConfig(
assetPath: 'assets/in_house_ads/apps.json',
currentAppId: 'com.example.myapp', // filtered out of rotation
theme: const InHouseAdsTheme(
cardColor: Color(0xFFFFFFFF),
borderColor: Color(0xFFBBF7D0),
badgeBackground: Color(0xFFDCFCE7),
accentColor: Color(0xFF16A34A),
ctaTextColor: Color(0xFFFFFFFF),
textColor: Color(0xFF000000),
secondaryTextColor: Color(0xFF616161),
),
onAdClicked: ({required type, required title}) {
// Optional analytics hook
},
// Optional: remote-configurable routing (see below).
remoteUrl: 'https://your-host.example/in-app-ads-data.json',
remoteRefreshInterval: Duration(hours: 6),
// Optional: open store links in an in-app browser tab (Chrome Custom
// Tabs on Android, SFSafariViewController on iOS) instead of the
// external app/browser.
linkMode: InHouseAdLinkMode.inAppBrowser,
),
);
Usage #
Native ad #
final ad = await InHouseAdRepository.pickForSlot('home_0');
if (ad != null) {
return InHouseNativeAdView(ad: ad);
}
Banner ad #
final ad = await InHouseAdRepository.pickForSlot('banner_0');
if (ad != null) {
return InHouseBannerAdView(ad: ad);
}
Interstitial #
final ad = await InHouseAdRepository.pickNext();
if (ad != null && context.mounted) {
await InHouseInterstitial.show(
context: context,
ad: ad,
onComplete: () {},
);
}
apps.json schema #
Top-level JSON array. Each entry:
| Field | Type | Required | Notes |
|---|---|---|---|
title |
string | yes | App title |
icon |
string | yes | Icon image URL |
appId |
string | yes | Play Store package id |
summary / description |
string | no | Body copy (summary preferred) |
developer |
string | no | Developer name |
headerImage |
string | no | Hero / banner image |
screenshots |
string[] | no | Additional media URLs |
url |
string | no | Store URL (defaults to Play Store for appId) |
free |
bool | no | Default true |
priceText |
string | no | CTA when free is false |
rating |
number | no | Star rating |
installs |
string | no | Install count label |
ctaColor |
string | no | #RRGGBB, #AARRGGBB, or 0xAARRGGBB |
imageOnly |
bool | no | See Image-only ad entries below |
nativeImage / bannerImage / interstitialImage |
string or string[] | no | Static creative image(s) per placement, used when imageOnly is true. A single string or a JSON array of strings — multiple images rotate across separate impressions |
The bundled local asset (assetPath) is always treated as this bare-array shape — it never carries routing information (see below).
Remote routing (optional) #
Instead of (or alongside) the bundled local asset, you can point the package at a hosted JSON file that lets you control, remotely and without an app update, which promoted apps show in which host app:
InHouseAdsConfig(
assetPath: 'assets/in_house_ads/apps.json', // offline bootstrap / first-run fallback
remoteUrl: 'https://your-host.example/in-app-ads-data.json',
remoteRefreshInterval: Duration(hours: 6),
)
The remote URL must serve a JSON object with two keys:
{
"apps": [ /* same per-entry schema as apps.json above */ ],
"routing": {
"com.example.hostAppA": ["com.example.promotedApp1", "com.example.promotedApp2"]
}
}
appsis the full ad pool, same schema as the localapps.json.routingmaps a host app'scurrentAppIdto the list of promotedappIds it's allowed to show. A host app with no entry inroutingshows every ad except itself (opt-out default) — add an entry only for apps whose ad set you want to restrict or curate.
Fetch/cache behavior: on every launch, the package resolves ads immediately from whichever source is available (never blocking on a network call): the last successfully fetched remote payload if one has ever been persisted, otherwise the bundled assetPath asset. In the background, if the persisted payload is missing or older than remoteRefreshInterval, the package fetches remoteUrl and — only if the response is valid — persists it for use starting on the next app launch. A failed fetch is silently ignored and the previously persisted data is left untouched, so there's never a mid-session change or flicker.
Image-only ad entries #
For partner placements that only supply a static creative image with no app-store-style metadata (e.g. game-portal partners), set "imageOnly": true on that entry and supply nativeImage / bannerImage / interstitialImage (each falls back to headerImage/screenshots/icon if omitted). Native, banner, and interstitial views render just the image plus a small "Ad" disclosure badge — no title, description, rating, or CTA text. Image-only entries are excluded from rewarded rotation (InHouseRewarded/pickNextRewarded), since rewarded's detail screen needs the full metadata.
Each of nativeImage / bannerImage / interstitialImage accepts either a single URL string or a JSON array of URL strings:
{
"title": "Qureka",
"icon": "https://example.com/qureka/icon.png",
"appId": "com.qureka",
"imageOnly": true,
"nativeImage": ["https://example.com/qureka/native1.png", "https://example.com/qureka/native2.png"],
"bannerImage": ["https://example.com/qureka/banner1.png", "https://example.com/qureka/banner2.png"],
"interstitialImage": "https://example.com/qureka/interstitial1.png",
"url": "https://play.google.com/store/apps/details?id=com.qureka"
}
When more than one image is supplied for a placement, the package rotates through them one at a time across separate impressions (each pickForSlot/pickNext call) rather than showing them all at once — a single string is equivalent to a one-item list.
Public API #
InHouseAds/InHouseAdsConfig/InHouseAdsThemeInHouseAd/InHouseAdRepositoryInHouseNativeAdViewInHouseInterstitial/InHouseInterstitialView
Platform support #
Designed and tested for Android only.