npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zencemarketing/zence-react-native-sdk

v0.1.0

Published

Reusable React Native SDK to wrap any web app URL in a native WebView shell.

Readme

@zencemarketing/zence-react-native-sdk

npm version license

React Native library that loads your web app inside a native WebView with a small native ↔ web bridge (JWT bootstrap, postMessage, deep links, optional push token handoff).

Platforms: Android and iOS (JavaScript + react-native-webview; no custom native module is required from this package).


Requirements

| Requirement | Notes | |-------------|--------| | React | >= 18 (peer) | | React Native | >= 0.72 (peer) | | react-native-webview | >= 13 (peer) | | Node | >= 18 recommended for local development / publishing |


Installation

In your host React Native app (not inside this repo unless you are developing the SDK):

npm install @zencemarketing/zence-react-native-sdk react-native-webview @react-native-async-storage/async-storage @react-native-community/netinfo
yarn add @zencemarketing/zence-react-native-sdk react-native-webview @react-native-async-storage/async-storage @react-native-community/netinfo
pnpm add @zencemarketing/zence-react-native-sdk react-native-webview @react-native-async-storage/async-storage @react-native-community/netinfo

Then install native dependencies.

iOS

From your app root:

cd ios && pod install && cd ..
  • HTTPS / ATS: Loading arbitrary HTTPS URLs is usually fine. For HTTP or non-standard TLS, configure App Transport Security in your app’s Info.plist.
  • Geolocation in WebView: If you use allowLocationAccess, add usage strings (e.g. NSLocationWhenInUseUsageDescription) in Info.plist.
  • Camera / mic in WebView: Add the corresponding privacy usage keys if your web app uses them.

Android

  • Ensure android.permission.INTERNET is present in your app AndroidManifest.xml (default templates include it).
  • For cleartext HTTP, set android:usesCleartextTraffic="true" or a network security config as required by your policy.

Expo

Use a dev client or bare workflow so native modules apply, then align versions with Expo’s installer where applicable:

npx expo install react-native-webview @react-native-async-storage/async-storage @react-native-community/netinfo

Add @zencemarketing/zence-react-native-sdk with your package manager as above.


Quick start

import React from "react";
import { ZenceWebSDK } from "@zencemarketing/zence-react-native-sdk";

export default function App() {
  return (
    <ZenceWebSDK
      url="https://myreactapp.com"
      token="jwt-token"
      enableBackButton
      enablePullToRefresh
      onMessage={(data) => console.log("Web message:", data)}
      onError={(error) => console.log("WebView error:", error)}
    />
  );
}

Features

  • WebView with configurable URL, headers, and user agent
  • Optional JWT bootstrap into web localStorage and sessionStorage
  • Native ↔ web bridge (postMessage + injectJavaScript)
  • Android hardware back navigates WebView history when enableBackButton is true
  • Pull-to-refresh toggle
  • Deep link forwarding into the web layer
  • Offline fallback HTML when connectivity is lost (offline + @react-native-community/netinfo)
  • Loader overlay and analytics-style callbacks
  • Optional push token request/response from web to native

Web → native

From JavaScript inside the page (standard WebView pattern):

window.ReactNativeWebView.postMessage(
  JSON.stringify({
    type: "LOGIN_SUCCESS",
    payload: { id: 10, name: "John" },
  }),
);

The SDK parses JSON messages with a type field and passes them to onMessage.

Built-in web → native message type

| type | Behavior | |--------|-----------| | REQUEST_PUSH_TOKEN | If onPushTokenRequested is set, native resolves a token and injects a response into the page (see below). |


Native → web

Use a ref and postMessageToWeb to push structured messages into the WebView:

import React, { useRef } from "react";
import { Button, View } from "react-native";
import { ZenceWebSDK, type NativeCommands } from "@zencemarketing/zence-react-native-sdk";

export default function App() {
  const sdkRef = useRef<NativeCommands>(null);

  return (
    <View style={{ flex: 1 }}>
      <Button
        title="Set dark theme"
        onPress={() =>
          sdkRef.current?.postMessageToWeb({
            type: "SET_THEME",
            payload: { theme: "dark" },
          })
        }
      />
      <ZenceWebSDK ref={sdkRef} url="https://myreactapp.com" />
    </View>
  );
}

NativeCommands (ref handle)

| Method | Description | |--------|-------------| | postMessageToWeb(message) | Delivers message to window.ZenceBridge.onNativeMessage and dispatches zence-native-message on window. | | reload() | Reloads the WebView. | | goBack() | WebView back navigation. |

Events and payloads the web app can observe

After load, the SDK injects window.ZenceBridge and dispatches:

  • zence-native-readyevent.detail.token mirrors the token prop (or null).
  • zence-native-messageevent.detail is the bridge message object.

Native-initiated messages (including deep links) also call:

window.ZenceBridge = window.ZenceBridge || {};
window.ZenceBridge.onNativeMessage = (message) => {
  console.log("From native:", message);
};

Deep links received via React Native Linking are forwarded as a bridge message with type: "DEEPLINK_RECEIVED" and payload.url, and the same injection path runs.

Push token flow from web:

// Web requests a token; native responds via onPushTokenRequested
window.ReactNativeWebView.postMessage(JSON.stringify({ type: "REQUEST_PUSH_TOKEN" }));

Native responds by injecting { type: "PUSH_TOKEN_RESPONSE", payload: { token: string } } into the page.


Props (ZenceWebSDKProps)

| Prop | Type | Default | Description | |------|------|---------|-------------| | url | string | required | Initial WebView URL. | | token | string | — | Written to localStorage / sessionStorage as "token" when present. | | headers | Record<string, string> | — | Request headers for the main document load. | | userAgent | string | — | Custom user agent string. | | customInjectedJavaScript | string | — | Appended to the bootstrap script run at load. | | enableBackButton | boolean | true | Android hardware back steps WebView history when possible. | | enablePullToRefresh | boolean | true | Enables pull-to-refresh on the WebView. | | allowFileAccess | boolean | true | Maps to WebView read-access behavior where supported. | | allowCameraAccess | boolean | true | Reserved / policy flag surface (WebView permissions still depend on OS + manifest). | | allowLocationAccess | boolean | true | Enables geolocation in WebView when the OS allows it. | | allowBiometrics | boolean | true | When true, emits an analytics event once (see source). | | enableCookies | boolean | true | sharedCookiesEnabled on WebView. | | enableThirdPartyCookies | boolean | true | thirdPartyCookiesEnabled (where supported). | | offline | { enabled?: boolean; fallbackHtml?: string } | — | When enabled, shows offline HTML while the device reports no connectivity. | | loader | { color?; backgroundColor?; testID? } | — | Overlay loader styling during loads. | | style | StyleProp<ViewStyle> | — | Wrapper View style. | | onMessage | (message: BridgeMessage) => void | — | Parsed web messages. | | onError | (error: string) => void | — | Load / HTTP / push token errors. | | onLoadStart / onLoadEnd | (url: string) => void | — | Navigation lifecycle. | | onNavigationStateChange | (state: WebViewNavigation) => void | — | Forwarded from WebView. | | onAnalyticsEvent | (event: { name: string; payload?: Record<string, unknown> }) => void | — | Hook for your analytics pipeline. | | onDeepLink | (url: string) => void | — | Called when app receives a deep link URL. | | onPushTokenRequested | () => Promise<string \| undefined> | — | Supplies token to web when REQUEST_PUSH_TOKEN is received. |

Exported types: ZenceWebSDKProps, BridgeMessage, OfflineConfig, LoaderConfig, AnalyticsEvent, AnalyticsHandler, DeepLinkHandler, NativeCommands.


Advanced example

<ZenceWebSDK
  url="https://myreactapp.com/?{jwt}"
  headers={{ "x-tenant-id": "tenant_001" }}
  offline={{ enabled: true }}
  loader={{ color: "#0F62FE", backgroundColor: "rgba(0,0,0,0.12)" }}
  onPushTokenRequested={async () => {
    // Return FCM / APNs token from your push setup
    return "push-token";
  }}
  onAnalyticsEvent={(event) => {
    console.log(event.name, event.payload);
  }}
/>

Troubleshooting

| Issue | What to check | |-------|----------------| | Blank WebView | URL, ATS / cleartext, device network, onError logs. | | Messages not reaching native | Must use window.ReactNativeWebView.postMessage inside the WebView page; body must be a string (JSON.stringify). | | iOS pod errors | Run pod repo update and align react-native-webview with your RN version. | | Types not found | Ensure typescript in your app resolves dist/index.d.ts (ships with the package). |


Developing this SDK (clone of repo)

npm install
npm run build
npm run typecheck

Publishing to npm (maintainers)

  1. Account: Create an account on https://www.npmjs.com/ and enable two-factor authentication (npm requires 2FA for publishing as of policy updates).

  2. Login: npm login (or npm adduser) on the machine that will publish; verify with npm whoami.

  3. Package name: name in package.json must be available on the registry. Scoped packages (@your-org/name) need "publishConfig": { "access": "public" } if you want them public.

  4. Metadata: Add a real repository and bugs URL in package.json when you have a Git host—improves discoverability and issue links on the npm page.

  5. Version: Bump semver in package.json (or use npm version patch|minor|major).

  6. Dry run: From the package root (with a clean git state recommended):

    npm run build
    npm pack --dry-run

    Confirm the tarball lists dist/, README.md, LICENSE, and placeholder android / ios folders as intended.

  7. Publish:

    npm publish

    Use npm publish --tag beta and a prerelease version for pre-releases.

  8. Provenance (optional): On supported CI, you can use npm provenance for supply-chain transparency.

Do not publish node_modules, example-app, or .gradle-home; the files field in package.json already limits what is packed. The prepack script runs npm run build so dist/ is up to date when packing or publishing.


License

MIT — see LICENSE.