Skip to main content

guavasure_flutter 0.2.5 copy "guavasure_flutter: ^0.2.5" to clipboard
guavasure_flutter: ^0.2.5 copied to clipboard

Embed GuavaSure pet insurance in Flutter via WebView.

guavasure_flutter #

Flutter package that embeds the hosted GuavaSure insurance flow in a WebView and implements GuavasureBridge for native Razorpay Checkout (primary), payment-link fallback (Custom Tab / Safari / external browser), opt-in native camera capture (nose photos + just-in-time permissions), native file pick, logout, mobile nav go-back, and optional partner-collected payment.

Requirements: Dart >=3.6.0, Flutter >=3.24.0 · Android & iOS

Installation #

Add from pub.dev:

flutter pub add guavasure_flutter

Or in pubspec.yaml:

dependencies:
  guavasure_flutter: ^0.2.5

Then:

flutter pub get
cd ios && pod install && cd ..

Transitive packages: webview_flutter, url_launcher, file_selector, image_picker, permission_handler, razorpay_flutter.

Platform setup #

Android #

URL fallback (Custom Tabs) on Android 11+ - inside <queries> in AndroidManifest.xml:

<queries>
  <intent>
    <action android:name="android.support.customtabs.action.CustomTabsService" />
  </intent>
</queries>

Camera (only when enableCameraCapture: true) - inside <manifest>:

<uses-permission android:name="android.permission.CAMERA" />

compileSdk 35+ - permission_handler 12.x (transitive from this package) requires compileSdkVersion 35 or higher in android/app/build.gradle (or compileSdk = 35 in build.gradle.kts). Flutter 3.24+ project templates usually already meet this.

Native Razorpay Checkout uses the official Android SDK via razorpay_flutter (Internet permission is included by the SDK).

iOS #

Run pod install after adding the package so the Razorpay iOS SDK is linked.

URL fallback uses SFSafariViewController - no additional manifest entries.

Camera (only when enableCameraCapture: true) - add to ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>GuavaSure needs camera access to capture your pet’s nose photo.</string>

Also enable the camera permission macro in ios/Podfile (required by permission_handler):

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',
        'PERMISSION_CAMERA=1',
      ]
    end
  end
end

Then re-run pod install.

Payment cascade #

When the embed posts open-payment, the plugin runs strategies in order:

open-payment
   ├─ 1. Native Razorpay SDK     key + orderId | subscriptionId
   ├─ 2. Custom Tab / Safari     url (Razorpay allowlist)
   └─ 3. External browser        url if in-app browser fails
Strategy Customer sees
Native SDK (primary) Razorpay modal inside the app
Custom Tab / Safari (fallback) Razorpay hosted page in system browser
External browser (last resort) Razorpay in Chrome / Safari app
  • Native cancel / failure does not open a URL (no double checkout).
  • Native success lets the embed keep polling and advance checkout (no reload).
  • Browser fallback does not reload on app resume - embed polling advances checkout.

The hosted embed sends key, orderId (annual) or subscriptionId (monthly), amountPaise, prefill, and url in every open-payment message - native checkout is the default on mobile when using current embed + 0.1.9+.

Partners using GuavaSureEmbed get this automatically. Custom WebView hosts can call:

final result = await launchGuavaSurePayment(request);

Native camera (nose photos) #

Native camera is opt-in via enableCameraCapture: true on GuavaSureEmbedConfig (default false, same as iOS/Android SDKs). When enabled, the plugin adds enable-camera-capture=true to the embed URL so the hosted embed uses the native camera bridge instead of file picker fallbacks.

When the embed posts camera-permission / capture-photo / open-camera-settings, GuavaSureEmbed handles them automatically only when enableCameraCapture is true:

  1. Request camera permission when the capture screen opens
  2. Open the system camera on Capture Photo
  3. Return the image to the embed (chunked base64 when large)
  4. On permanent deny, open OS Settings via Open Settings

When enableCameraCapture is false (default), nose photos use the embed file picker - no camera permission declarations are required in your app.

Faster first open (optional) #

From a logged-in screen before opening insurance:

await GuavaSureEmbed.warmup(context, embedConfig);
// Later - same GuavaSureEmbedConfig
GuavaSureEmbed(config: embedConfig);

Call GuavaSureEmbed.cancelWarmup() on partner logout. Skip warmup if you do not need it.

Alternate theme config #

Set themeConfigId on GuavaSureEmbedConfig to add theme-config-id to the embed URL. The hosted embed then loads the matching Theme config from the partner dashboard instead of the default customization. Omit it (or pass an unknown ID) to use the default.

Claims mode #

Set claimMode: true on GuavaSureEmbedConfig to add claim-mode=true to the embed URL. Home becomes a claims-focused Policy Details screen (membership card, cover/premium, claim history, sticky file-claim CTA) instead of the full portal dashboard. Omit it or leave false for the normal dashboard. Home-screen back still posts { "type": "go-back" } to GuavasureBridge.

Mobile nav go-back #

When partner customization enables uiStyle.mobileNav, the embed shows a sticky mobile top bar. Tapping back on the home screen posts { "type": "go-back" } to GuavasureBridge. Handle it with onGoBack on GuavaSureEmbed:

GuavaSureEmbed(
  config: config,
  onGoBack: () => Navigator.of(context).maybePop(),
)

On form steps, back navigates within the embed (no bridge message). When in-flow back is blocked (disableBack, e.g. post-payment) or Home is hidden, the chevron still shows and returns the customer to portal home - it does not post go-back.

Quick start #

import 'package:guavasure_flutter/guavasure_flutter.dart';

GuavaSureEmbed(
  config: GuavaSureEmbedConfig(
    partnerId: 'YOUR_PARTNER_ID',
    environment: GuavaSureEnvironment.sandbox,
    partnerAuthTokenProvider: () => myBackend.fetchCustomerAuthToken(),
    // Optional: opt in to native nose photo capture (requires camera permissions)
    // enableCameraCapture: true,
    // Optional: same externalId as customer-auth-token pet upserts
    // partnerExternalId: 'pet-001',
    // Optional: alternate Embed → Theme configs customization
    // themeConfigId: 'app',
    // Optional: claims-focused Policy Details home
    // claimMode: true,
  ),
  // Optional: customize the WebView or run JavaScript after load
  // onWebViewCreated: (controller) async {
  //   await controller.runJavaScript("document.body.style.background='white'");
  // },
  // Only when GuavaSure enables partner-collected payment on your account:
  partnerPaymentHandler: (request) async {
    // Charge your PSP, confirm server-side, return confirmed or cancelled
    return PartnerPaymentResult.confirmed;
  },
)

Verify native checkout (debug) #

After tapping Pay, debug logs should include:

GuavaSureEmbed payment native=true quote=… order=order_…
GuavaSure native Razorpay open order=order_… amount=…

If you see I/chromium / api.razorpay.com/v1/checkout/public instead, the app is on URL fallback - upgrade to 0.1.9+, run pod install, and cold-start the app (avoid hot restart with an active WebView).

Two payment paths #

Path Bridge message Use when
Standard (default) open-payment GuavaSure-managed Razorpay - native SDK first
Partner-collected COLLECT_PAYMENT GuavaSure enabled enablePartnerCollectedPayment; you charge your PSP

Standard checkout does not require partnerPaymentHandler. Partner-collected is annual-only and separate from the Razorpay cascade above.

Security #

  • Bridge messages are only handled on the configured embed origin.
  • Razorpay payment URLs are allowlisted (rzp.io, *.rzp.io, razorpay.me, *.razorpay.me, *.razorpay.com).
  • Use partnerAuthTokenProvider with short-lived JWTs. partnerAuthToken is deprecated and will not mint a fresh token on warmup or reload.
  • Never put Razorpay Key Secret in the app - only the public Key ID from the embed open-payment payload.

Docs #

Guide Audience
Flutter Plugin Partner apps - native + URL fallback
Mobile WebView protocol Bridge message reference
Flutter Plugin Example Flutter + Node/TypeScript sample

License #

Licensed under GPL-3.0. Intended for authorized GuavaSure integration partners.