guavasure_flutter 0.2.5
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:
- Request camera permission when the capture screen opens
- Open the system camera on Capture Photo
- Return the image to the embed (chunked base64 when large)
- 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
partnerAuthTokenProviderwith short-lived JWTs.partnerAuthTokenis 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-paymentpayload.
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.