diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2644d3..41170cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,58 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [7.7.2](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.7.1...v7.7.2) (2026-09-23) + +### Improvements + +* update Android Gateway SDK to 6.1.4 and Loans SDK to 5.4.0 +* update iOS Gateway SDK to 7.2.2 and Loans SDK to 7.5.0 + +### [7.7.1](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.7.0...v7.7.1) (2026-09-20) + + +### Features + +* expose webview-as-a-service ([648f235](https://github.com/smallcase/react-native-smallcase-gateway/commit/648f2359715094ce88f680e3ba18fc2c7cfbae4c)) + +## [7.7.0](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.6.2...v7.7.0) (2026-08-27) + + +### Features + +* add Loans KYC permission usage descriptions ([e384009](https://github.com/smallcase/react-native-smallcase-gateway/commit/e384009584353f89528e07bbf7ee28ce7e2eba2d)) + +### [7.6.2](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.6.1...v7.6.2) (2026-09-02) + +### [7.6.1](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.6.0...v7.6.1) (2026-08-17) + +### Improvements + +* **android:** update Loans SDK to 5.3.1 + +## [7.6.0](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.5.0...v7.6.0) (2026-07-31) + + +### Improvements + +* **android:** update Loans SDK to 5.3.0 + +### Bug Fixes + +* **android:** keep SCGateway classes for R8 ([e99d428](https://github.com/smallcase/react-native-smallcase-gateway/commit/e99d4284368827051a46a68f12e2dba75852ac3e)) + +## [7.5.0](https://npmjs.com/package/react-native-smallcase-gateway/v/7.5.0?activeTab=versions) (2026-07-10) + +Dev Improvements + +* Bumped Loans native SDK to the dark-theme internal release (Android 5.1.4-92, iOS 7.1.2-44) and dropped a stale ProGuard workaround while keeping R8 full mode on. + +Features + +* Added a `colorScheme` (`dark` / `light` / `system`) option to `ScLoanInfo`, letting partner apps control the LAS web UI theme instead of always defaulting to light. + +### [7.4.4](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.4.3...v7.4.4) (2026-06-11) + ### [7.4.3](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.4.0...v7.4.3) (2026-06-09) ### [7.4.2](https://github.com/smallcase/react-native-smallcase-gateway/compare/v7.4.0...v7.4.2) (2026-05-25) diff --git a/README.md b/README.md index 80a9d484..72c2b6bb 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,17 @@ platform :ios, '11.0' then run `cd ios; pod update` +Apps using Loans KYC must also add these usage descriptions to the iOS app's `Info.plist`: + +```xml +NSCameraUsageDescription +Camera access is required to capture your selfie during KYC. +NSMicrophoneUsageDescription +Microphone access is required for audio during video KYC. +NSLocationWhenInUseUsageDescription +Location access is required to verify your location during KYC. +``` + ## android setup Add these lines to your project level `build.gradle` @@ -37,12 +48,8 @@ allprojects { repositories { // .. you other repositories maven { - url "http://artifactory.smallcase.com/artifactory/gradle-dev-local" - credentials { - username "react_native_user" - password "reactNativeUser123" - } - } + url "https://artifactory.smallcase.com/artifactory/SCGateway" + } } } ``` @@ -100,8 +107,22 @@ 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"); ``` +## Native SDK debug mode + +The native Gateway and Loans SDK versions this package depends on are pinned in `native-sdk.json`, once for `release` (default) and once for `debug`. Debug builds of the native SDKs enable WebView inspection and debug logging, and are published to smallcase's internal registries only. + +To consume the debug builds: + +- Android: add `SmallcaseGateway_sdkMode=debug` to the host app's `android/gradle.properties`, then sync. Artifactory access to `SCGateway-internal` is required. +- iOS: add `source 'git@github.com:smallcase/cocoapodspec-internal.git'` and `source 'https://cdn.cocoapods.org/'` to the host app's `Podfile`, then run `SMALLCASE_SDK_MODE=debug pod install`. Run a plain `pod install` to switch back. + +The build fails with an explicit error if debug mode is selected but `native-sdk.json` has no debug pin for an SDK. + ## Debug / Contribution Make sure you have react native dev environment set up diff --git a/android/build.gradle b/android/build.gradle index 68bb5f72..4e34b7ee 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -146,11 +146,25 @@ repositories { def kotlin_version = getExtOrDefault('kotlinVersion') +// Native SDK pins live in native-sdk.json. Set SmallcaseGateway_sdkMode=debug in the +// host app's gradle.properties to consume debug builds of the native SDKs. +def sdkMode = getExtOrDefault('sdkMode') ?: 'release' +def nativeSdks = new groovy.json.JsonSlurper().parse(file("$projectDir/../native-sdk.json")) +if (!nativeSdks.containsKey(sdkMode)) { + throw new GradleException("${project.name}: unknown SmallcaseGateway_sdkMode '${sdkMode}', expected one of ${nativeSdks.keySet()}") +} +def androidSdks = nativeSdks[sdkMode].android +androidSdks.each { sdk, coordinate -> + if (!coordinate) { + throw new GradleException("${project.name}: no ${sdk} SDK pinned for mode '${sdkMode}' in native-sdk.json") + } +} + dependencies { //noinspection GradleDynamicVersion implementation 'com.facebook.react:react-native:+' // From node_modules - implementation 'com.smallcase.gateway:sdk:6.1.1' - implementation 'com.smallcase.loans:sdk-sourav-native-dark-theme-cb54bf9:5.1.4-92-release' + implementation androidSdks.gateway + implementation androidSdks.loans implementation "androidx.core:core-ktx:1.3.1" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } 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/native-sdk.json b/native-sdk.json new file mode 100644 index 00000000..03f441c9 --- /dev/null +++ b/native-sdk.json @@ -0,0 +1,22 @@ +{ + "release": { + "android": { + "gateway": "com.smallcase.gateway:sdk:6.1.4", + "loans": "com.smallcase.loans:sdk:5.4.0" + }, + "ios": { + "gateway": { "name": "SCGateway", "version": "7.2.2" }, + "loans": { "name": "SCLoans", "version": "7.5.0" } + } + }, + "debug": { + "android": { + "gateway": null, + "loans": null + }, + "ios": { + "gateway": null, + "loans": null + } + } +} diff --git a/package.json b/package.json index 26045bb4..069a09ff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-native-smallcase-gateway", "title": "React Native Smallcase Gateway", - "version": "7.4.3", + "version": "7.7.2", "description": "smallcase gateway bindings for react native", "main": "src/index.js", "files": [ @@ -12,6 +12,7 @@ "cpp", "types", "react-native-smallcase-gateway.podspec", + "native-sdk.json", "!lib/typescript/example", "!lib/typescript/smart_investing_react_native", "!android/build", diff --git a/react-native-smallcase-gateway.podspec b/react-native-smallcase-gateway.podspec index 686d423d..1a61ec5c 100644 --- a/react-native-smallcase-gateway.podspec +++ b/react-native-smallcase-gateway.podspec @@ -1,6 +1,18 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +# Native SDK pins live in native-sdk.json. Run `SMALLCASE_SDK_MODE=debug pod install` +# in the host app to consume debug builds of the native SDKs. +native_sdks = JSON.parse(File.read(File.join(__dir__, "native-sdk.json"))) +sdk_mode = ENV.fetch("SMALLCASE_SDK_MODE", "release") +unless native_sdks.key?(sdk_mode) + raise "react-native-smallcase-gateway: unknown SMALLCASE_SDK_MODE '#{sdk_mode}', expected one of #{native_sdks.keys}" +end +ios_sdks = native_sdks[sdk_mode]["ios"] +ios_sdks.each do |sdk, pod| + raise "react-native-smallcase-gateway: no #{sdk} SDK pinned for mode '#{sdk_mode}' in native-sdk.json" if pod.nil? +end folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' Pod::Spec.new do |s| @@ -34,8 +46,6 @@ Pod::Spec.new do |s| s.dependency "ReactCommon/turbomodule/core" end - s.dependency 'SCGateway', '7.2.0' - # INTERNAL TEST PIN: dark-theme branch build (mirrors the android/build.gradle pin). - # Revert to: s.dependency 'SCLoans', '7.2.0' - s.dependency 'SCLoans-sourav-native-dark-theme-37c97d9', '7.1.2-45-release' + s.dependency ios_sdks["gateway"]["name"], ios_sdks["gateway"]["version"] + s.dependency ios_sdks["loans"]["name"], ios_sdks["loans"]["version"] end diff --git a/smart_investing_react_native/android/app/proguard-rules.pro b/smart_investing_react_native/android/app/proguard-rules.pro index 5dccbcd3..5924e582 100644 --- a/smart_investing_react_native/android/app/proguard-rules.pro +++ b/smart_investing_react_native/android/app/proguard-rules.pro @@ -12,6 +12,8 @@ # SCGateway proguard rules — keeping it here, same as loans. -keep class com.smallcase.gateway.** { *; } +-keep class com.example.** { *; } + # Retrofit + R8 full mode (AGP 8 default): generic signatures are stripped for # any type that is not kept, so ConfigService.getBrokerConfigs(): Call # degrades to a raw Call and Retrofit rejects it diff --git a/smart_investing_react_native/android/gradle.properties b/smart_investing_react_native/android/gradle.properties index 9767fbf1..6657b545 100644 --- a/smart_investing_react_native/android/gradle.properties +++ b/smart_investing_react_native/android/gradle.properties @@ -42,6 +42,3 @@ hermesEnabled=true artifactory_contextUrl=https\://artifactory.smallcase.com/artifactory artifactory_password=reactNativeUser123 artifactory_user=react_native_user - -# R8 full mode enabled — verified safe against loans SDK consumer-rules.pro -android.enableR8.fullMode=true \ No newline at end of file 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" /> - + +