From 648f2359715094ce88f680e3ba18fc2c7cfbae4c Mon Sep 17 00:00:00 2001 From: "Sourav Ganguly (isouravganguly)" Date: Thu, 10 Sep 2026 00:49:29 +0530 Subject: [PATCH 1/3] feat: expose webview-as-a-service --- README.md | 3 ++ .../SmallcaseGatewayModule.kt | 24 ++++++++++++++- ios/SmallcaseGateway.m | 22 +++++++++++++- .../app/screens/SmtScreen.tsx | 30 ++++++++++++++++--- src/SmallcaseGateway.js | 17 +++++++++++ src/__mocks__/react-native.ts | 1 + src/__tests__/launchScWebView.test.js | 20 +++++++++++++ types/SmallcaseGateway.d.ts | 6 ++++ types/index.d.ts | 1 + 9 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/__tests__/launchScWebView.test.js diff --git a/README.md b/README.md index 80a9d484..1e7341ff 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,9 @@ const res = await SmallcaseGateway.triggerTransaction(transactionId); // start lead generation flow SmallcaseGateway.triggerLeadGen({ email: "test@gmail.com" }); + +// launch a standalone WebView; setup/init are not required +await SmallcaseGateway.launchScWebView("https://www.smallcase.com"); ``` ## Debug / Contribution diff --git a/android/src/main/java/com/reactnativesmallcasegateway/SmallcaseGatewayModule.kt b/android/src/main/java/com/reactnativesmallcasegateway/SmallcaseGatewayModule.kt index c36f9a6e..d9629576 100644 --- a/android/src/main/java/com/reactnativesmallcasegateway/SmallcaseGatewayModule.kt +++ b/android/src/main/java/com/reactnativesmallcasegateway/SmallcaseGatewayModule.kt @@ -1,5 +1,6 @@ package com.reactnativesmallcasegateway +import android.net.Uri import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.facebook.react.bridge.* @@ -163,6 +164,28 @@ class SmallcaseGatewayModule(reactContext: ReactApplicationContext) : ReactConte } } + @ReactMethod + fun launchScWebView(url: String, promise: Promise) { + val activity = reactApplicationContext.currentActivity ?: run { + promise.reject("no_activity", "No active Android activity") + return + } + val uri = Uri.parse(url) + if (uri.scheme?.lowercase() !in setOf("http", "https") || uri.host.isNullOrBlank()) { + promise.reject("invalid_url", "A valid absolute HTTP(S) URL is required") + return + } + + activity.runOnUiThread { + try { + SmallcaseGatewaySdk.launchScWebView(activity, url) + promise.resolve(true) + } catch (error: Exception) { + promise.reject("launch_failed", error) + } + } + } + @ReactMethod fun launchSmallplug(targetEndpoint: String, params: String, promise: Promise) { @@ -562,4 +585,3 @@ class SmallcaseGatewayModule(reactContext: ReactApplicationContext) : ReactConte } } - diff --git a/ios/SmallcaseGateway.m b/ios/SmallcaseGateway.m index fa04027c..46c60e4e 100644 --- a/ios/SmallcaseGateway.m +++ b/ios/SmallcaseGateway.m @@ -360,6 +360,27 @@ @interface RCT_EXTERN_MODULE(SmallcaseGateway, NSObject) } //MARK: smallplug +RCT_REMAP_METHOD(launchScWebView, + urlString:(NSString *)urlString + launchScWebViewWithResolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSURL *url = [NSURL URLWithString:urlString]; + NSString *scheme = url.scheme.lowercaseString; + if (url == nil || url.host.length == 0 || + !([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])) { + reject(@"invalid_url", @"A valid absolute HTTP(S) URL is required", nil); + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [SCGateway.shared + launchScWebViewWithPresentingController:[[[UIApplication sharedApplication] keyWindow] rootViewController] + url:url + completion:^(__unused id response, __unused NSError *error) {}]; + resolve(@(YES)); + }); +} + RCT_REMAP_METHOD(launchSmallplug, targetEndpoint:(NSString *)targetEndpoint params:(NSString *)params @@ -809,4 +830,3 @@ - (NSError *)scLoanErrorToDict:(ScLoanError *)error { } @end - diff --git a/smart_investing_react_native/app/screens/SmtScreen.tsx b/smart_investing_react_native/app/screens/SmtScreen.tsx index f2998d68..87d17507 100644 --- a/smart_investing_react_native/app/screens/SmtScreen.tsx +++ b/smart_investing_react_native/app/screens/SmtScreen.tsx @@ -1,9 +1,14 @@ import React from 'react'; -import {Button, TextInput, View} from 'react-native'; +import {Button, ScrollView, TextInput} from 'react-native'; import {launchSmallPlug} from '../apis/Functions'; -import {SCGatewayEventManager} from 'react-native-smallcase-gateway'; +import SmallcaseGateway, { + SCGatewayEventManager, +} from 'react-native-smallcase-gateway'; const SmtScreen = () => { + const [webViewUrl, onChangeWebViewUrl] = React.useState( + 'https://www.smallcase.com', + ); const [targetEndpoint, onChangeTargetEndpoint] = React.useState< string | null >(null); @@ -21,7 +26,7 @@ const SmtScreen = () => { string | null >(null); return ( - + { @@ -99,7 +104,24 @@ const SmtScreen = () => { title={'SmallPlug'} accessibilityLabel="Learn more about this purple button" /> - + +