#Cross platform implementation
In case you are using a cross platform solution—like Flutter, React Native, Ionic—for your Android and iOS apps, you can refer to the code snippets provided below. The integration process remains the same, but changes as per the language you use.
The code snippets provided below deal specifically with how the web view is loaded and dismissed within your Android/iOS app. Usage of the Create Link API will remain unaffected.
#Flutter
Switch control from your app to Setu
The link returned by the Create link API should be loaded within a webview. Our sample below uses the flutter_inappwebview plugin for webviews. Feel free to use a plugin as per your requirements.
The webview controller
will need to implement one JavaScript handler -
unload
- Used by the parent app to dismiss the webview
Special use case: This unload
function can also be used for dismissing the webview and redirecting a user back to your native app once a bill payment journey is completed (i.e. payment is successful) via a CTA from the Setu webview. Please let our team know if you would like to enable this use case for your app.
Make sure you are handling these functionalities in your webview for a seamless user experience:
If you are integrating with our default UPI payment option, the webview needs to handle UPI app specific intents using a
shouldOverrideUrlLoading
(or a similar function as per your webview plugin). This function is used to handle UPI app specific schemes and open the UPI app.For downloading and saving transaction receipts from the webview, the webview will need to handle a
onDownloadStartRequest
(or a similar function as per your webview plugin). Our sample below uses the flutter_downloader and path_provider plugins for downloading and saving transaction receipts. Please follow the plugin specific documentation for implementation. Make sure you have added necessary permissions in yourAndroidManifest.xml
andInfo.plist
files for downloading and saving files.
import 'dart:io';import 'dart:isolate';import 'dart:ui';import 'package:flutter/material.dart';import 'package:url_launcher/url_launcher.dart';import 'package:flutter_inappwebview/flutter_inappwebview.dart';import 'package:flutter_downloader/flutter_downloader.dart';import 'package:path_provider/path_provider.dart';Future main() async {WidgetsFlutterBinding.ensureInitialized();await FlutterDownloader.initialize(debug: true, // optional: set false to disable printing logs to console);runApp(new MyApp());}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(home: RpWebPage(link: 'https://billpay.setu.co/1234',), // Replace with the actual URL);}}class RpWebPage extends StatefulWidget {const RpWebPage({super.key, required this.link});final String link;@overrideState<RpWebPage> createState() => _RpWebPageState();}class _RpWebPageState extends State<RpWebPage> {late InAppWebViewController webView;bool isButtonClicked = false;@overridevoid initState() {super.initState();}void _loadUrl() {setState(() {isButtonClicked = true;});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Bill Payments'),),body: Column(children: [if (!isButtonClicked)ElevatedButton(onPressed: _loadUrl,child: Text('Load webview'),),Expanded(child: isButtonClicked? InAppWebView(initialSettings: InAppWebViewSettings(allowFileAccess: true,allowFileAccessFromFileURLs: true),initialUrlRequest: URLRequest(url: WebUri.uri(Uri.parse(widget.link))),onWebViewCreated: (InAppWebViewController controller) {webView = controller;},onLoadStop: (controller, url) async {controller.addJavaScriptHandler(handlerName: 'unload',callback: (args) async {// logic to close webview and return to app},);},// Handle opening UPI apps from UPI app specific intentsshouldOverrideUrlLoading: (controller, navigationAction) async {final uri = navigationAction.request.url!;if (["phonepe", "upi"].contains(uri.scheme) ||uri.toString().contains("upi")) {if (await canLaunchUrl(uri)) {// Launch the Appawait launchUrl(uri,);// and cancel the requestreturn NavigationActionPolicy.CANCEL;}}return NavigationActionPolicy.ALLOW;},// Handle downloading the receiptonDownloadStartRequest: (controller, request) async {print("onDownloadStart $request");final dir = Platform.isAndroid? (await getExternalStorageDirectory())?.path: (await getApplicationDocumentsDirectory()).uri.path;print("saving in $dir");final taskId = await FlutterDownloader.enqueue(url: request.url.toString(),savedDir: dir!,showNotification: true, // show download progress in status bar (for Android)openFileFromNotification: true, // click on notification to open downloaded file (for Android)saveInPublicStorage: true,allowCellular: true);// Open the downloaded fileawait FlutterDownloader.open(taskId: taskId!);},): Container(),),],),);}}
#React Native
Below are the steps to embed the pre-built screens into React Native app,
Implement a web view. We recommend to use the WebView component from react-native-webview library. You’re free to choose any other library for implementing this.
Pass the webview URL into the
uri
parameter on the WebView component. Ideally, this URL can be sent as a parameter from the previous screen to the WebView screen.WebView component exposes a function
onNavigationStateChange
which is called every time there is a change in the navigation of web view.
import React, { useRef, useEffect } from "react";import { SafeAreaView, ActivityIndicator, StyleSheet } from "react-native";import WebView from "react-native-webview"; // Load WebView from "react-native-webview"export default function WebView({ navigation }) {const webviewRef = useRef(null);// Check if webview URI contain .setu.couseEffect(() => {if(!webViewUri.includes('.setu.co')){console.log('Blocking navigation');navigation.navigate("Start");}});// Function to check the navigation state inside webviewconst onNavigation = (navState) => {let url = navState.url;};return (<SafeAreaView style={styles.flexContainer}><WebViewsource={{ uri: 'https://billpay.setu.co/1234' }} // Replace with the actual URLstartInLoadingState={true}renderLoading={() => (<ActivityIndicator color="black" size="large" style={styles.flexContainer} />)}ref={webviewRef}onNavigationStateChange={onNavigation}style={styles.margin}// Whitelist UPI app specific schemes for handling app specific intentsoriginWhitelist={['*.setu.co','*://upi/*','phonepe://*']}mixedContentMode="always"allowFileAccessallowFileAccessFromFileURLsallowUniversalAccessFromFileURLsjavaScriptEnablednestedScrollEnabled // optional: in case you are loading WebView inside a ScrollViewscrollEnabledonFileDownload={(event) => {// Handle downloading the receipt (iOS only)}}/></SafeAreaView>);}// Stylesconst styles = StyleSheet.create({flexContainer: {flex: 1,},margin: {marginTop: 50,},});
Was this page helpful?