@zencemarketing/zence-react-native-sdk
v0.1.1
Published
Reusable React Native SDK to wrap any web app URL in a native WebView shell.
Readme
Zence React Native SDK — Client Integration Guide
Overview
The Zence React Native SDK lets you embed your existing reward portal (web app) inside native Android and iOS apps using a secure WebView container and a small native ↔ web bridge.
Component name: ZenceRewardPortal
Supported platforms: Android, iOS
Capabilities:
- Secure SSO login (form POST or URL-based)
- Dynamic WebView rendering
- Web ↔ Native messaging
- Pull to refresh
- Android hardware back navigation
- Offline fallback screen
- Deep link forwarding
- Optional push token handoff
SDK package
| Item | Value |
|------|--------|
| npm (scoped) | @zencemarketing/zence-react-native-sdk |
| npm (unscoped) | zence-react-native-sdk |
| Registry | https://www.npmjs.com/package/@zencemarketing/zence-react-native-sdk |
Use whichever package name is published for your environment. Examples below use the scoped name.
Prerequisites
| Requirement | Version |
|-------------|---------|
| React | >= 18 |
| React Native | >= 0.72 |
| react-native-webview | >= 13 |
| Node (development) | >= 18 recommended |
| Platform | Supported | |----------|-----------| | Android | Yes | | iOS | Yes |
Installation
1. Install packages
npm install @zencemarketing/zence-react-native-sdk \
react-native-webview \
@react-native-community/netinfoyarn add @zencemarketing/zence-react-native-sdk \
react-native-webview \
@react-native-community/netinfo2. iOS — CocoaPods
cd ios && pod install && cd ..3. Android
Ensure AndroidManifest.xml includes:
<uses-permission android:name="android.permission.INTERNET" />4. iOS — App Transport Security
Production apps should use HTTPS. For non-standard TLS or HTTP in development, configure NSAppTransportSecurity in Info.plist as required by your policy.
Integration modes
The SDK supports two authentication patterns. Use the one your backend documents.
Mode A — Form SSO (recommended for Kotak / reward portal)
The mobile app passes a customer identifier from your backend. The SDK loads a bootstrap page that POSTs a hidden customer_number field to the SSO endpoint, then follows the server redirect into the portal.
Mobile App
↓
Backend returns customer_number (or signed token used as customer_number)
↓
ZenceRewardPortal (customerNumber + ssoUrl)
↓
SDK auto-submits POST form
↓
Backend validates → HTTP redirect
↓
Reward portal loads in WebViewExample (QA):
import React from "react";
import { ZenceRewardPortal } from "@zencemarketing/zence-react-native-sdk";
const CUSTOMER_NUMBER = "<FROM_YOUR_BACKEND>";
const SSO_URL =
"https://{REWARD_PORTAL_BASE_URL}/auth/SSO?tenantid={YOUR_TENANT_NAME}";
export default function App() {
return (
<ZenceRewardPortal
customerNumber={CUSTOMER_NUMBER}
ssoUrl={SSO_URL}
enableBackButton
enablePullToRefresh
offline={{ enabled: true }}
onMessage={(data) => console.log("Web -> Native:", data)}
onError={(error) => console.log("WebView Error:", error)}
/>
);
}What the SDK does internally:
var form = document.createElement("form");
form.method = "POST";
form.action = "<ssoUrl>";
var input = document.createElement("input");
input.type = "hidden";
input.name = "customer_number"; // override via sso.tokenField
input.value = "<customerNumber>";
form.appendChild(input);
document.body.appendChild(form);
form.submit();Advanced SSO config:
<ZenceRewardPortal
customerNumber={CUSTOMER_NUMBER}
sso={{
url: SSO_URL,
method: "POST", // default: POST
tokenField: "customer_number", // default: customer_number
extraFields: { channel: "MOBILE" },
}}
/>| Environment | SSO URL example |
|-------------|-----------------|
| QA / UAT | https://rp2-rewardportal.erzqa.com/auth/SSO?tenantid=kotak |
| Production | Provided by Zence (HTTPS required) |
Mode B — URL SSO (JWT in query string)
If your tenant expects the token in the URL (not a form POST), load the portal directly:
import { ZenceRewardPortal } from "@zencemarketing/zence-react-native-sdk";
const jwt = "<JWT_FROM_BACKEND>";
<ZenceRewardPortal
url={`https://domain.com/auth/sso?token=${jwt}`}
enableBackButton
enablePullToRefresh
offline={{ enabled: true }}
onMessage={(data) => console.log(data)}
onError={(error) => console.log(error)}
/>Production URL format:
https://domain.com/auth/sso?token=<JWT_TOKEN>Backend token generation (JWT tenants)
For tenants that issue a signed JWT, generation must happen on your server — never in the mobile app.
Sample claims
| Claim | Description |
|-------|-------------|
| customerId | Unique customer identifier |
| tenantId | Brand / tenant identifier |
| channel | Platform source (e.g. MOBILE, WEB) |
| requestId | Request tracking ID |
| returnUrl | Post-login redirect path |
| nonce | Random unique value |
Sample — .NET
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
var claims = new[]
{
new Claim("customerId", "C12345"),
new Claim("tenantId", "kotak"),
new Claim("channel", "MOBILE"),
new Claim("requestId", "REQ7890"),
new Claim("returnUrl", "/dashboard"),
new Claim("nonce", "XYZ123")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_SERVER_SECRET"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "kotak",
audience: "rewards-portal",
claims: claims,
expires: DateTime.UtcNow.AddMinutes(5),
signingCredentials: creds);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);Use the JWT either as:
- Mode B: append to
urlquery string, or - Mode A: pass the value (or a mapped identifier) as
customerNumberif your SSO endpoint expects form POST.
Security recommendations
| Topic | Recommendation | |-------|----------------| | Token expiry | Short-lived tokens (e.g. 5 minutes) | | Signing | HMAC SHA256 (or as specified by Zence) | | Secrets | Never embed signing keys in the mobile app | | Transport | HTTPS only in production | | Validation | Always validate tokens on the backend |
Component props (ZenceRewardPortal)
Core
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| customerNumber | string | — | Value POSTed as hidden customer_number (Mode A). |
| ssoUrl | string | — | SSO endpoint URL (shorthand for sso.url). |
| sso | SSOConfig | — | Full SSO config (url, method, tokenField, extraFields). |
| url | string | — | Direct WebView URL (Mode B or non-SSO). Optional when using SSO props. |
| token | string | — | Deprecated alias for customerNumber; also written to web localStorage / sessionStorage as "token" when set. |
UX & WebView
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableBackButton | boolean | true | Android hardware back navigates WebView history. |
| enablePullToRefresh | boolean | true | Pull-to-refresh on WebView. |
| offline | OfflineConfig | — | Offline fallback when network is unavailable. |
| loader | LoaderConfig | — | Loading overlay color / background. |
| style | ViewStyle | — | Wrapper style. |
| headers | Record<string, string> | — | HTTP headers for document load (URL mode). |
| userAgent | string | — | Custom user agent. |
Callbacks
| Prop | Type | Description |
|------|------|-------------|
| onMessage | (message: BridgeMessage) => void | Parsed messages from the web app. |
| onError | (error: string) => void | Load, HTTP, or bridge errors. |
| onLoadStart / onLoadEnd | (url: string) => void | Navigation lifecycle. |
| onNavigationStateChange | (state) => void | WebView navigation state. |
| onAnalyticsEvent | (event) => void | Analytics hook. |
| onDeepLink | (url: string) => void | App deep link received. |
| onPushTokenRequested | () => Promise<string \| undefined> | Supply push token to web. |
Ref methods (NativeCommands)
| Method | Description |
|--------|-------------|
| postMessageToWeb(message) | Send structured message to the web layer. |
| reload() | Reload WebView. |
| goBack() | WebView back navigation. |
Offline configuration
offline={{ enabled: true }}When enabled and the device is offline:
- A fallback HTML screen is shown.
- When connectivity returns, the SDK switches back to the main WebView automatically.
There is no manual “Retry” button in the default UI. You may supply custom HTML via offline.fallbackHtml.
Web → Native communication
Web (inside portal):
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: "LOGIN_SUCCESS",
payload: { customerId: "C12345" },
}),
);Native:
onMessage={(data) => {
console.log("Message from Web:", data);
}}Built-in message types
| type | Behavior |
|--------|----------|
| REQUEST_PUSH_TOKEN | Native calls onPushTokenRequested and injects PUSH_TOKEN_RESPONSE. |
Native → Web communication
import { useRef } from "react";
import { ZenceRewardPortal, type NativeCommands } from "@zencemarketing/zence-react-native-sdk";
const ref = useRef<NativeCommands>(null);
ref.current?.postMessageToWeb({
type: "SET_THEME",
payload: { theme: "dark" },
});The web app can listen via:
window.ZenceBridge.onNativeMessage = (message) => {
console.log("From native:", message);
};
window.addEventListener("zence-native-message", (event) => {
console.log(event.detail);
});Deep links are forwarded as { type: "DEEPLINK_RECEIVED", payload: { url } }.
Error handling
onError={(error) => {
console.log("WebView Error:", error);
}}Common causes:
- Invalid or missing
url/ SSO configuration - Network failure
- SSL / certificate issues
- HTTP errors from SSO endpoint
- Expired or invalid customer token
Production checklist
| Item | Status | |------|--------| | HTTPS enabled | Required | | Token / customer_number from backend only | Required | | Backend validation on SSO endpoint | Required | | Valid SSL certificate | Required | | Tested on Android | Required | | Tested on iOS | Required | | Release signing keystore (not debug) | Required for store builds |
Troubleshooting
White / blank screen
- Verify
ssoUrlorurlis correct for your environment. - Check device network and
onErrorlogs. - Confirm ATS (iOS) / cleartext (Android) settings for non-HTTPS dev URLs.
SSO login fails
- Confirm backend expects POST
customer_number(Mode A) vs GET token in URL (Mode B). - Verify
customerNumbervalue is current and not expired. - QA URL:
https://rp2-rewardportal.erzqa.com/auth/SSO?tenantid=kotak
Messages not reaching native
- Use
window.ReactNativeWebView.postMessagewithJSON.stringify. - Message must originate from JavaScript running inside the WebView.
Version information
| Item | Value |
|------|--------|
| npm version | 0.1.1 |
| SDK name | Zence React Native SDK |
| Component | ZenceRewardPortal |
| Integration type | WebView hybrid |
| Platforms | Android & iOS |
| Primary auth (Kotak) | Form POST customer_number |
| Alternate auth | JWT in URL query string |
Support
For SDK support or onboarding, contact the Zence technical team.
License
MIT — see LICENSE.
