Inappify Flutter SDK

Flutter SDK for Inappify sessions, offerings, entitlements and purchases. The 0.2.7 API follows the current Kotlin SDK. Android delegates to Kotlin through MethodChannel; Kotlin owns purchase, cache and automatic recovery. iOS keeps its Dart Direct-payment backend; Web uses the separately loaded JavaScript SDK. Store purchases and native delivery callbacks are Android-only. Flutter Web requires @inappifylabs/web-sdk 0.2.0+. It supports combined attributes/offerings sync and all four CustomerInfo policies, defaulting explicitly to cachedOrFetched. See the Web setup and cache contract.

Android store packaging for the 0.2.7 release is described in store-specific builds. Set inappifyStore=myket or inappifyStore=bazaar at build time; API keys alone do not remove permissions.

Configure and identify the customer

import 'package:inappify_sdk/inappify_sdk.dart';

await InappifySdk.configure(apiKey: 'public_app_key');
// Or, on mobile:
await InappifySdk.configure(apiKey: 'public_app_key', appUserIdentifier: 'customer_123');
await InappifySdk.logIn('customer_123');
await InappifySdk.logOut();
await InappifySdk.setAttributes({'plan': 'gold', 'removed': null});
await InappifySdk.setEmail('person@example.com');

The verified server configuration supplies market and RSA key. Android reads app metadata itself. Configure on startup; automatic prefetch/recovery belongs to the native SDK. Web identity uses an Identity Ticket or OTP; see Web.

Offerings, customer info and purchase

final offerings = await InappifySdk.getOfferings();
final offering = await InappifySdk.getCurrentOffering();
final placed = await InappifySdk.getCurrentOffering(placementIdentifier: 'home');
final special = await InappifySdk.getOffering('special_offer');
await InappifySdk.syncAttributesAndOfferingsIfNeeded();

final info = await InappifySdk.getCustomerInfo(); // cachedOrFetched
final current = await InappifySdk.getCustomerInfo(
  fetchPolicy: InappifyCacheFetchPolicy.fetchCurrent,
);
final hasPremium = current?.entitlements.active.containsKey('premium') == true;

if (offering?.packages?.isNotEmpty == true) {
  final result = await InappifySdk.purchaseResult(InappifyPurchaseParams(
    packageToPurchase: offering!.packages!.first,
  ));
  // Inspect result.data / result.failure. A Direct payment URL is host-owned.
}

The package supplies product/offering/package identifiers and product type; Android supplies its Activity. Keep an explicit idempotency key only when retrying the same logical purchase. Consumables require a durable grant; see delivery and recovery.

Convenience operations retain nullable/bool results. Their *Result companions preserve typed failures and snapshots. See the complete reference. The Android 0.2.7 release uses the coordinated native v0.2.7 dependency; Android development setup supports the current local checkout.

Documentation

Install the official integration skill into your consuming app's coding agent:

npx skills add InappifyLabs/flutter-sdk --skill inappify-sdk

Choose the target agent when prompted; see the installation guide for Codex, Claude Code, Cursor and manual installation.

The repository includes automated contract tests and compile/build checks. Real store purchases, subscription renewals and backend deployment still require integration testing against your own app and store accounts.

License

The Flutter SDK is licensed under Apache-2.0. The Android dependency includes its own Apache-2.0 license and third-party notices in the Kotlin repository.

SDK logging

Configure logging before Configure:

await InappifySdk.setLogLevel(InappifyLogLevel.debug);
await InappifySdk.setLogHandler((level, message) {
  // Route the filtered message to your application's logging system.
});
// Restore default console output:
await InappifySdk.setLogHandler(null);

Levels are verbose, debug, info, warn and error. Defaults are debug in development and info in release/profile builds. Custom handlers replace default console output; Android forwards Kotlin messages once and iOS uses the Dart logger. Logging and consumable-delivery callbacks share a dispatcher without replacing one another. No logs are uploaded automatically. HTTP trace listeners remain separate and opt-in. On Web, this controls Flutter-wrapper messages, not the host-owned JavaScript provider's logger.

Libraries

helpers/localization_helper
helpers/paywall_assets_downloader
helpers/paywall_assets_helper
helpers/paywall_image_loader
helpers/paywall_theme_manager
helpers/paywall_widget_parser
helpers/responsive_font_helper
helpers/validate_helper
inappify_sdk
inappify_sdk_method_channel
inappify_sdk_platform_interface
inappify_sdk_web
local/local_storage
models/api_response_model
models/attribute
models/authentication_result
models/background
models/buttons
models/captcha_challenge
models/checkout_result
models/condition
models/customer_info
models/entitlement_infos
models/entitlement_model
models/enums/market
models/enums/purchase_status
models/feature
models/general_color
models/inappify_configuration
models/log_level
models/mobile_v2
models/offering_model
models/offering_packages
models/offering_packages_product
models/offerings_model
models/otp_challenge
models/package_model
models/packages_color
models/paywall
models/paywall_action
models/paywall_asset
models/paywall_badge_style
models/paywall_connector
models/paywall_content_layout
models/paywall_divider
models/paywall_element
models/paywall_element_states
models/paywall_image_file
models/paywall_item_tree_state
models/paywall_localization
models/paywall_text
models/paywall_text_style
models/paywall_top_button
models/pivot
models/placement
models/placement_offering
models/price_model
models/purchase_attempt
models/purchase_params
models/purchase_result
models/rule
models/store_product_model
models/template
models/text_model
models/transaction_model
models/validate_discount_code_data
offering_evaluation_context
request_cancellation
session_state
ui/first_template
ui/paywall_modal
ui/paywall_pacakges
ui/second_template
ui/third_template