The stash-native package makes it simple to add Stash in-app purchases (IAPs) and webshops to your game or app. It delivers seamless, native-like payment flows and selection dialogs, which appear as system dialogs on Android and iOS through lightweight embedded webviews, while providing direct callbacks to your application.
| Platform | Description |
|---|---|
| Android | Android library (AAR). |
| iOS | iOS framework (XCFramework). |
If you're using one of the game engines listed below, we offer dedicated wrappers for this library. These wrappers provide ready-to-use interfaces for integrating Stash features into your project, along with added development tools—such as full flow testing directly in the Unity Editor.
| Engine | Repository | Compatibility | |
|---|---|---|---|
![]() |
Unity | stash-unity | Unity 2019.4+ (LTS recommended) |
![]() |
Unreal Engine 5 | stash-unreal (main) | Unreal Engine 5.0+ |
![]() |
Unreal Engine 4 | stash-unreal (4.27-plus) | Unreal Engine 4.27-plus |
Latest pre-built binaries are always available on Releases Page:
- Android:
stashnative-release.aar(orStashNative-<tag>.aarfrom releases) - iOS:
StashNative.xcframework.zip
Both platforms contain up-to-date sample apps that demonstrate the library usage and functions. You can run them from source
- Android:
./Android/sample/- Run with./gradlew :sample:installDebug - iOS:
./iOS/Sample/- OpenStashNativeSample.xcodeprojin Xcode
or try them instantly in your browser using the Appetize online emulator:
- Download
StashNative-<tag>.aarfrom GitHub Releases and add it to your project (e.g.libs/). - In your app's
build.gradle:
dependencies {
implementation files('libs/StashNative-<tag>.aar')
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.browser:browser:1.7.0'
}To build the AAR locally: cd Android && ./gradlew :stashnative:assembleRelease (output in stashnative/build/outputs/aar/).
XCFramework (recommended): Download StashNative.xcframework.zip from GitHub Releases, unzip it, add StashNative.xcframework to your Xcode project, and under Frameworks, Libraries, and Embedded Content set it to Embed & Sign.
Swift Package Manager: In Xcode choose File → Add Packages... and add https://github.com/stashgg/stash-native.git, then select the StashNative package for your target.
Manual integration: Copy all files from StashNative/Sources/StashNative/ into your project, add them to your target, and link SafariServices.framework and WebKit.framework.
The library provides three distinct ways to present Stash URLs within your app or game: openCard, openModal, and openBrowser. Each method lets you present different types of Stash experiences—such as Stash Pay checkout, Stash Web Shop, or Stash Opt-in—in a style that best fits your user flow. Details for each option are provided below.
Drawer-style card: slides up from the bottom on phones, centered on tablets. Suited for Stash Pay payment links or channel selection. Integrating Stash Pay
Android
StashNativeCard.CardConfig config = new StashNativeCard.CardConfig(); // or null for defaults
StashNativeCard.getInstance().openCard("https://testcard.stashpreview.com", config);iOS (Swift)
let config = StashNativeCardConfig() // or nil for defaults
StashNativeCard.sharedInstance().openCard(withURL: "https://testcard.stashpreview.com", config: config)iOS (Objective-C)
StashNativeCardConfig *config = [[StashNativeCardConfig alloc] init]; // or nil for defaults
[[StashNativeCard sharedInstance] openCardWithURL:@"https://testcard.stashpreview.com" config:config];Pass a CardConfig (or nil/null) to control orientation and sizing. Pass nil/null for defaults.
| Aspect | Description |
|---|---|
| forcePortrait | true: card opens portrait-locked (separate activity on Android, portrait-only on iOS). false (default): card appears in current orientation as an overlay. |
| Phone | cardHeightRatioPortrait, cardWidthRatioLandscape, cardHeightRatioLandscape (0.1–1.0). |
| Tablet | tabletWidthRatioPortrait, tabletHeightRatioPortrait, tabletWidthRatioLandscape, tabletHeightRatioLandscape (0.1–1.0). |
Warning: If using
forcePortrait, ensure your app supports portrait or can unlock to portrait while the card is shown.
Android
StashNativeCard.CardConfig config = new StashNativeCard.CardConfig();
config.forcePortrait = false;
config.cardHeightRatioPortrait = 0.68f;
// ... tabletWidthRatioPortrait, tabletHeightRatioPortrait, etc. (see table above)
stashNative.openCard(url, config);iOS (Swift)
let config = StashNativeCardConfig()
config.forcePortrait = false
config.cardHeightRatioPortrait = 0.68
// ... tabletWidthRatioPortrait, tabletHeightRatioPortrait, etc. (see table above)
stashNative.openCard(withURL: url, config: config)| Event | Description |
|---|---|
| Payment Success | Called when the payment completes successfully. |
| Payment Failure | Called when the payment fails. |
| Dialog Dismissed | Called when the user dismisses the dialog. |
| Opt-In Response | Called when a channel selection response is received. |
| Page Loaded | Called when the page finishes loading (with load time). |
| Network Error | Called when the page load fails (no connection, HTTP error, timeout). |
Set a listener (Android) or delegate (iOS) before calling openCard or openModal. Same callback interface is used for both.
Android — implement StashNativeCardListener (or extend StashNativeCardListenerAdapter to override only the callbacks you need):
StashNativeCard.getInstance().setActivity(this);
StashNativeCard.getInstance().setListener(new StashNativeCard.StashNativeCardListener() {
@Override
public void onPaymentSuccess() {
// Handle successful payment
}
@Override
public void onPaymentFailure() {
// Handle failed payment
}
@Override
public void onDialogDismissed() {
// User closed the card/modal
}
@Override
public void onOptInResponse(String optinType) {
// Channel selection response (e.g. "email", "sms")
}
@Override
public void onPageLoaded(long loadTimeMs) {
// Page finished loading
}
@Override
public void onNetworkError() {
// Load failed (no connection, HTTP error, or timeout)
}
});iOS (Swift) — set the delegate and implement StashNativeCardDelegate (all methods are optional):
StashNativeCard.sharedInstance().delegate = self
// In your class (e.g. ViewController):
extension YourViewController: StashNativeCardDelegate {
func stashNativeCardDidCompletePayment() {
// Handle successful payment
}
func stashNativeCardDidFailPayment() {
// Handle failed payment
}
func stashNativeCardDidDismiss() {
// User closed the card/modal
}
func stashNativeCardDidReceiveOpt(in optinType: String) {
// Channel selection response
}
func stashNativeCardDidLoadPage(_ loadTimeMs: Double) {}
func stashNativeCardDidEncounterNetworkError() {
// Load failed (no connection, HTTP error, or timeout)
}
}iOS (Objective-C) — set the delegate and implement the optional protocol methods:
[StashNativeCard sharedInstance].delegate = self;
// In your class:
- (void)stashNativeCardDidCompletePayment {
// Handle successful payment
}
- (void)stashNativeCardDidFailPayment {
// Handle failed payment
}
- (void)stashNativeCardDidDismiss {
// User closed the card/modal
}
- (void)stashNativeCardDidReceiveOptIn:(NSString *)optinType {
// Channel selection response
}
- (void)stashNativeCardDidLoadPage:(double)loadTimeMs {}
- (void)stashNativeCardDidEncounterNetworkError {
// Load failed
}Centered modal on all devices. Same layout on phone and tablet; resizes on rotation. Suited for channel selection or an alternative checkout style. Stash Pay Opt-In
Android
StashNativeCard.ModalConfig config = new StashNativeCard.ModalConfig(); // or null for defaults
StashNativeCard.getInstance().openModal("https://testcard.stashpreview.com", config);iOS (Swift)
let config = StashNativeModalConfig() // or nil for defaults
StashNativeCard.sharedInstance().openModal(withURL: "https://testcard.stashpreview.com", config: config)iOS (Objective-C)
StashNativeModalConfig *config = [[StashNativeModalConfig alloc] init]; // or nil for defaults
[[StashNativeCard sharedInstance] openModalWithURL:@"https://testcard.stashpreview.com" config:config];Pass a ModalConfig (or nil/null) to control drag bar, dismiss behavior, and sizing. Pass nil/null for defaults.
| Aspect | Description |
|---|---|
| Behavior | showDragBar (default true), allowDismiss (default true). |
| Phone | phoneWidthRatioPortrait, phoneHeightRatioPortrait, phoneWidthRatioLandscape, phoneHeightRatioLandscape (0.1–1.0). |
| Tablet | tabletWidthRatioPortrait, tabletHeightRatioPortrait, tabletWidthRatioLandscape, tabletHeightRatioLandscape (0.1–1.0). |
Android
StashNativeCard.ModalConfig config = new StashNativeCard.ModalConfig();
config.showDragBar = true;
config.allowDismiss = true;
// ... phoneWidthRatioPortrait, phoneHeightRatioPortrait, tablet ratios, etc. (see table above)
stashNative.openModal(url, config);iOS (Swift)
let config = StashNativeModalConfig()
config.showDragBar = true
config.allowDismiss = true
// ... phoneWidthRatioPortrait, phoneHeightRatioPortrait, tablet ratios, etc. (see table above)
stashNative.openModal(withURL: url, config: config)Same as openCard: same events and the same listener/delegate. Set it once as shown in the Callbacks section under openCard; it receives events for both card and modal.
Opens the URL in the platform browser (Chrome Custom Tabs on Android, SFSafariViewController on iOS). No in-app UI, no config, no callbacks. Use when you only need a simple browser view.
Android
StashNativeCard.getInstance().openBrowser("https://testcard.stashpreview.com");iOS (Swift)
StashNativeCard.sharedInstance().openBrowser(withURL: "https://testcard.stashpreview.com")
// Optionally dismiss when handling a deeplink:
StashNativeCard.sharedInstance().closeBrowser()iOS (Objective-C)
[[StashNativeCard sharedInstance] openBrowserWithURL:@"https://testcard.stashpreview.com"];
// Optionally dismiss when handling a deeplink:
[[StashNativeCard sharedInstance] closeBrowser];On iOS, closeBrowser() dismisses the Safari view. On Android, closeBrowser() is a no-op (Chrome Custom Tabs cannot be closed by the app).
This package follows Semantic Versioning (major.minor.patch):
- Major: Breaking changes
- Minor: New features (backward compatible)
- Patch: Bug fixes
- Documentation: https://docs.stash.gg
- Email: developers@stash.gg


