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

@htyf-mp/rn-sdk

v0.0.1

Published

React Native App SDK — unified native capabilities via ref API

Readme

@htyf-mp/rn-sdk

React Native App SDK — 为红糖云服小程序容器提供统一的原生能力封装。宿主通过 AppSdk 组件挂载 SDK,业务方通过 ref 调用能力;小程序侧通过 @htyf-mp/js-sdk 间接使用同一套引擎。

定位与关系

┌─────────────────────────────────────────────────────────────┐
│  宿主 App(app-core / MiniAppsContainer)                      │
│  ┌─────────────┐    ref / hostAdapter    ┌─────────────────┐  │
│  │   AppSdk    │ ◄────────────────────── │  宿主业务逻辑    │  │
│  └──────┬──────┘                         └─────────────────┘  │
│         │ AppSdkFacade + SDKFuncs                              │
│         ▼                                                      │
│  ┌─────────────┐         全局注入          ┌───────────────┐  │
│  │  沙盒 proxy  │ ───────────────────────► │ @htyf-mp/js-sdk│  │
│  └─────────────┘   DGZ_GLOBAL_CURRENT_    │  (小程序代码)  │  │
│                     MP_CLIENT              └───────────────┘  │
└─────────────────────────────────────────────────────────────┘

| 包 | 角色 | |---|---| | @htyf-mp/rn-sdk | RN 侧 SDK 实现:组件、模块、原生封装、UI 能力 | | @htyf-mp/js-sdk | 小程序 JS 侧 SDK,调用全局注入的 SDKFuncs 实例 | | app-core | 宿主容器,组装 AppSdk、沙盒、胶囊栏等 |

设计原则:

  • 业务方优先通过 AppSdkRef 调用能力,避免直接 import 内部 modules/ / services/
  • 禁止业务代码直接调用 NativeModules;统一走 SDK 的 native/bridge/ 层。
  • UI 类能力(播放器、浏览器、扫码等)通过 HostAdaptercreateSdkHostAdapter 注入,宿主可覆盖默认实现。

安装

本包为 monorepo workspace 成员,在宿主 package.json 中声明:

{
  "dependencies": {
    "@htyf-mp/rn-sdk": "workspace:*"
  }
}

重要: @htyf-mp/rn-sdk 不会自动安装原生依赖。宿主 App 必须自行安装下方 peerDependencies,否则运行时会出现模块找不到、能力降级或报错。在 monorepo 中,这些包应安装在原生 App 目录(以便 autolinking 生效),版本以根 lockfile 为准。

Peer Dependencies(宿主需额外安装)

package.jsonpeerDependencies 对齐。必装依赖:

# pnpm 示例(版本请与 monorepo 根 lockfile 对齐,勿随意升级)
pnpm add react-native-mmkv \
  react-native-permissions \
  react-native-image-picker \
  @react-native-camera-roll/camera-roll \
  @react-native-clipboard/clipboard \
  @react-native-community/netinfo \
  @dr.pogodin/react-native-fs \
  react-native-safe-area-context \
  react-native-orientation-locker \
  react-native-localize \
  react-native-nitro-haptics \
  react-native-nitro-unzip \
  react-native-nitro-http-server \
  react-native-volume-manager \
  react-native-ble-manager \
  @react-native-documents/picker \
  react-native-quick-base64 \
  react-native-quick-crypto \
  md5

| 分类 | 包名 | |---|---| | 核心 | react, react-native(宿主通常已有) | | 存储 | react-native-mmkv | | 权限 | react-native-permissions | | 媒体 | react-native-image-picker, @react-native-camera-roll/camera-roll | | 系统 | @react-native-clipboard/clipboard, @react-native-community/netinfo | | 文件 | @dr.pogodin/react-native-fs, @react-native-documents/picker | | 布局 | react-native-safe-area-context, react-native-orientation-locker | | 本地化 | react-native-localize | | 触觉 | react-native-nitro-haptics | | 压缩 | react-native-nitro-unzip | | 网络 | react-native-nitro-http-server | | 音量 | react-native-volume-manager | | 蓝牙 | react-native-ble-manager | | 编码 | react-native-quick-base64, react-native-quick-crypto | | 工具 | md5 |

安装原生依赖后需重新执行 iOS pod install / Android 同步,并重新编译原生 App。


快速开始

1. 挂载 AppSdk

import React, { useRef, useCallback } from 'react';
import {
  AppSdk,
  createSdkHostAdapter,
  type AppSdkRef,
  type AppSdkConfig,
} from '@htyf-mp/rn-sdk';

const config: AppSdkConfig = {
  apiBaseUrl: 'https://api.example.com',
  token: '',
  userId: '',
  debug: __DEV__,
};

function MiniAppHost() {
  const sdkRef = useRef<AppSdkRef>(null);

  const handleReady = useCallback((ref: AppSdkRef) => {
    sdkRef.current = ref;
  }, []);

  return (
    <AppSdk
      ref={sdkRef}
      appId="my-mini-app"
      config={config}
      launchOptions={{ path: '/index', query: {} }}
      hostAdapter={createSdkHostAdapter()}
      onReady={handleReady}
      setGlobal
      currentGlobal={sandboxProxy}
    >
      {/* 小程序 Root 组件,需等 SDK ready 且沙盒配置完成后再渲染 */}
    </AppSdk>
  );
}

2. 通过 ref 调用能力

const sdk = sdkRef.current;
if (!sdk) return;

await sdk.showToast('操作成功');
await sdk.showModal({
  title: '确认',
  description: '是否继续?',
  onConfirm: () => {},
  onCancel: () => {},
});

const qr = await sdk.scanQRCode({ text: '请扫描二维码' });
const image = await sdk.pickImage({ mediaType: 'photo', includeBase64: true });
const device = await sdk.getDeviceInfo();

3. 监听 SDK 事件

const unsubscribe = sdk.on('networkChange', ({ state }) => {
  console.log(state.type, state.isConnected);
});

sdk.on('appStateChange', ({ state }) => {
  console.log('AppState:', state);
});

// 组件卸载时
unsubscribe();

AppSdk Props

| Prop | 类型 | 说明 | |---|---|---| | config | AppSdkConfig | API 地址、token、debug 等运行时配置 | | appId / appid | string | 小程序唯一 ID | | hostAdapter | HostAdapter \| SDKHostAdapter | 宿主能力注入(登录、分享、UI 弹层等) | | adAdapter | MiniAppAdAdapter | 广告 Banner / 激励视频 / 插屏 | | launchOptions | Partial<LaunchOptions> | 启动参数(path、query、isVip 等) | | capsuleBarLayout | Partial<CapsuleBarLayout> | 胶囊栏布局,会同步到引擎 | | currentGlobal | Record<string, unknown> | 注入 SDK 的全局对象(通常为沙盒 proxy) | | setGlobal / setGloabl | boolean | 是否向 currentGlobal 写入 DGZ_GLOBAL_CURRENT_MP_CLIENT(默认 true) | | storage | StorageInterface | 自定义存储;默认按 appId 创建 MMKV 实例 | | isNative | boolean | 是否原生小程序模式(影响 MagicModal 实例隔离) | | isVip | boolean | VIP 标识,透传给引擎 | | getAppConfig | (appUrl) => Promise<AppInfoType> | 拉取应用配置 | | handleOpenApp | (appInfo) => Promise<boolean> | 打开其他小程序 | | handleCloseApp | () => Promise<boolean> | 关闭当前小程序 | | handleRestartApp | () => void | 重启当前小程序 | | onReady | (ref: AppSdkRef) => void | SDK 初始化完成回调 | | children | ReactNode | 子树(SDK ready 后才渲染) |

AppSdkConfig

interface AppSdkConfig {
  apiBaseUrl?: string;
  baseUrl?: string;
  token?: string;
  userId?: string;
  env?: 'development' | 'staging' | 'production';
  debug?: boolean;          // true 时开启 SDK 日志
  theme?: { mode?: 'light' | 'dark' | 'system'; primaryColor?: string };
  locale?: string;
  headers?: Record<string, string>;
}

AppSdkRef API

AppSdkRef 是推荐对外使用的统一接口,由 AppSdkFacade 实现,内部按职责拆分为多个 Module。

生命周期

| 方法 | 说明 | |---|---| | initialize() | 初始化(挂载时自动调用) | | destroy() | 销毁模块与事件总线 | | reload() | 销毁后重新注册模块 | | pause() / resume() | 暂停 / 恢复 | | updateConfig(partial) | 热更新配置 |

用户与路由(依赖 hostAdapter)

| 方法 | 说明 | |---|---| | login(credentials?) | 登录 | | logout() | 登出 | | share(options) | 系统分享 | | openPage(options) / closePage() | 打开 / 关闭宿主页面 | | navigate(route, params?) | 路由跳转 | | openApp(appInfo) / closeApp() / restartApp() | 小程序生命周期 |

UI 与交互

| 方法 | 说明 | |---|---| | showToast(msg \| ToastOptions) | Toast 提示 | | showLoading(msg?) / hideLoading() | 全局 Loading | | showModal(options) | 确认对话框 | | scanQRCode(options?) | 二维码扫描 | | openCamera() | 相机拍照(返回 base64 或 uri) |

媒体与文件

| 方法 | 说明 | |---|---| | pickImage(options?) | 相册选图 | | launchCamera(options?) | 调起相机 | | getPhotos(params) | 分页读取相册 | | uploadFile(file) | 上传文件 | | downloadFile(options) | 下载并保存到本地 |

设备与权限

| 方法 | 说明 | |---|---| | requestPermission(permission) | 请求权限(含说明弹窗) | | getDeviceInfo() | 语言、时区、安全区等 | | getLocation() | 定位 | | getNetworkType() | 当前网络状态 | | callNative(module, method, params?) | 通用原生桥接 |

事件与扩展

| 方法 | 说明 | |---|---| | on(event, handler) | 订阅事件,返回取消函数 | | off(event, handler) | 取消订阅 | | emit(event, payload) | 派发事件 | | registerModule(module) | 注册自定义模块 | | unregisterModule(name) | 移除模块 | | getEngine?() | 获取底层 SDKFuncs(mp-jssdk 兼容,标注为 internal) |

SDK 事件

| 事件 | Payload | |---|---| | sdkReady | { appId: string } | | sdkDestroyed | {} | | configUpdated | { config } | | networkChange | { state: NetInfoState } | | appStateChange | { state: AppStateStatus } | | analytics | { name, params? } |


SDKFuncs(引擎层)

SDKFuncs 是底层能力引擎,承载全部原生 API。小程序通过 @htyf-mp/js-sdk 访问的正是该实例(经全局 key 注入)。

新宿主代码应优先使用 AppSdkRef;仅在需要与 jssdk 对齐或访问完整原生 API 时使用 getEngine()

UI 能力(也可由 HostAdapter 覆盖)

await engine.openVideoPlayer({ url: 'https://...', title: '视频' });
await engine.openAudioPlayer({ type: 'open', items: [...] });
await engine.openBrowser('https://example.com');
await engine.openImages({ images: [{ uri }], imageIndex: 0, visible: true });
await engine.openQR({ text: '扫码' });
await engine.showToast({ type: 'success', title: '完成' });
await engine.showModal({ title, description, onConfirm, onCancel });
await engine.openCamera();
await engine.puppeteer({ url, jscode }); // WebView 执行脚本

原生能力一览

完整参数与返回值见 SDK_NATIVE_APIS.md

| 分类 | 代表方法 | |---|---| | 图片 / 相册 | launchImageLibrary, launchCamera, getPhotos, saveImageToAlbum, saveVideoToAlbum | | 文档 | pickDocument | | 剪贴板 | setClipboardString, getClipboardString | | 网络 | getNetworkState, addNetworkListener | | 文件系统 | getDocumentDir, getCachesDir, fsReadFile, fsWriteFile, fsReadDir, fsMkdir, fsExists, fsUnlink, fsCopyFile, fsMoveFile | | 下载 / 服务 | downloadAndSaveFile, createStaticServer | | 触觉 | triggerHaptic | | 本地化 | getLocales, getCurrencies, getCountry, getTimeZone | | 压缩 | unzip, zip | | 音量 | getVolume, setVolume, addVolumeListener | | 编码 | encodeBase64, decodeBase64, getRandomBytes | | 屏幕方向 | lockToPortrait, lockToLandscapeLeft, unlockAllOrientations, getOrientation, addOrientationListener 等 | | 安全区 | getSafeAreaInsets | | 广告 | showRewardedAd, showInterstitialAd, AdBanner | | BLE | bleStart, bleScan, bleConnect, bleRead, bleWrite, bleStartNotification, bleAddListener 等 | | 应用 | openApp, closeApp, restartApp, getAppConfig | | 存储 | getStorage, storage(MMKV) |


Host Adapter

SDKHostAdapter 定义宿主可注入的 UI 弹层 能力。HostAdapter 在其基础上扩展登录、分享、路由等宿主业务方法。

SDKHostAdapter 接口

interface SDKHostAdapter {
  openVideoPlayer?: (options: unknown) => Promise<() => void>;
  openAudioPlayer?: (items: unknown) => Promise<() => void>;
  puppeteer?: (items: unknown) => Promise<unknown>;
  openBrowser?: (url, options?) => Promise<() => void>;
  openQR?: (props?: { text?: string }) => Promise<unknown>;
  openPermissions?: (info: unknown) => Promise<boolean>;
  openImages?: (data: unknown) => Promise<() => void>;
  showToast?: (options: unknown) => Promise<() => void>;
  showModal?: (options: unknown) => Promise<() => void>;
  openCamera?: () => Promise<unknown>;
}

多数 UI 方法返回 关闭函数 () => void,用于主动 dismiss 弹层。

createSdkHostAdapter

工厂函数,供 app-core 侧生成默认 Host Adapter(基于 MagicModal + features/*):

import { createSdkHostAdapter } from '@htyf-mp/rn-sdk';

// 方式一:使用内置默认实现(需传入 modal 上下文,AppSdk 内部已自动处理)
const adapter = createSdkHostAdapter({
  magicModal,
  useMagicModal,
  getSDK: () => engineRef.current,
});

// 方式二:完全自定义
const adapter = createSdkHostAdapter({
  adapter: myCustomHostAdapter,
});

// 方式三:不传参 — 返回 undefined,由 SDKFuncs 内置逻辑兜底
const adapter = createSdkHostAdapter();

AppSdk 在挂载时会自动调用 createSdkHostAdapter:若传入 hostAdapter prop 则优先使用;否则在具备 magicModal 上下文时生成默认实现。


与 mp-jssdk 的全局契约

SDK 初始化后,会将 SDKFuncs 适配实例写入全局对象:

import { DGZ_GLOBAL_CURRENT_MP_CLIENT, SDK_GLOBAL_KEYS } from '@htyf-mp/rn-sdk';

// 等价常量
SDK_GLOBAL_KEYS.CURRENT_MP_CLIENT; // '__DGZ_GLOBAL_CURRENT_MP_CLIENT__'

小程序代码通过 @htyf-mp/js-sdk 读取该全局变量并调用方法,例如:

import jssdk from '@htyf-mp/js-sdk';

await jssdk.showToast({ type: 'success', title: 'Hello' });
const result = await jssdk.launchImageLibrary({ mediaType: 'photo' });

注意: 沙盒环境下应将 currentGlobal 设为沙盒 proxy,并确保 setGlobal={true},以便每个小程序实例拥有隔离的全局作用域。


自定义模块

实现 ISdkModule 可扩展 SDK 能力:

import type { ISdkModule, SdkContextValue } from '@htyf-mp/rn-sdk';

class MyModule implements ISdkModule {
  readonly name = 'myFeature';
  private ctx!: SdkContextValue;

  initialize(ctx: SdkContextValue) {
    this.ctx = ctx;
  }

  async doSomething() {
    this.ctx.logger.info('hello');
  }

  destroy() {
    // 清理
  }
}

sdkRef.current?.registerModule(new MyModule());

内置模块包括:toast, loading, modal, qrcode, camera, image, file, upload, download, share, clipboard, permission, network, device, location, storage, auth, router, media, browser, analytics, notification, bridge, ble


存储

默认按 appId 创建 MMKV 加密存储:

import { NewMMKVStorage, createStorageForApp } from '@htyf-mp/rn-sdk';

const storage = createStorageForApp('my-app-id');
// 或
const storage = new NewMMKVStorage('__dgz996_app_appid_[my-app-id]_for__');

实现 StorageInterface 可注入自定义存储到 AppSdkstorage prop。


日志

import { logger, createComponentLogger } from '@htyf-mp/rn-sdk';

logger.configure({ enabled: true });

const log = createComponentLogger('MyFeature');
log.info('ready');
log.warn('something odd');
log.error('failed', error);

config.debug === trueAppSdk 会自动开启 SDK 日志。


错误类型

import {
  SdkError,
  NativeError,
  PermissionError,
  NetworkError,
} from '@htyf-mp/rn-sdk';

| 类 | code | 场景 | |---|---|---| | SdkError | 多种 | 通用 SDK 错误 | | NativeError | NATIVE_ERROR | 原生模块调用失败 | | PermissionError | PERMISSION_DENIED | 权限被拒绝 | | NetworkError | NETWORK_ERROR | 网络相关错误 |


导出说明

推荐入口(@htyf-mp/rn-sdk

| 导出 | 用途 | |---|---| | AppSdk, AppSdkFacade | 主组件与 Facade 类 | | AppSdkRef, AppSdkConfig, HostAdapter | 类型 | | createSdkHostAdapter | Host Adapter 工厂 | | NewMMKVStorage, createStorageForApp | 存储 | | logger, createComponentLogger | 日志 | | SDK_GLOBAL_KEYS, DGZ_GLOBAL_CURRENT_MP_CLIENT | 全局契约 | | features/* | UI 组件与 API(宿主集成 Modal、Toast 等) | | contracts/* | SDKHostAdapter, SDKClientLike 等契约类型 |

稳定子入口(publicApi.ts 语义)

面向后续独立 npm 包抽离,新代码可优先从主入口导入;publicApi.ts 聚合了 SDKFuncscreateSdkHostAdaptercontractsfeatures 等稳定符号。

已废弃

| 符号 | 替代 | |---|---| | SDKPortal | AppSdk | | 直接依赖 app-core/features/* | @htyf-mp/rn-sdkfeatures 导出 |


目录结构

src/
├── AppSdk.tsx              # 主组件:Provider、EventBus、全局注入
├── AppSdkFacade.ts         # AppSdkRef 实现,模块编排
├── SDKFuncs.tsx            # 底层引擎,全量原生 API
├── createSdkHostAdapter.tsx# 默认 Host Adapter 工厂
├── ModuleRegistry.ts       # 模块注册表
├── modules/                # 按职责拆分的能力模块
├── services/               # ApiService、Storage、File、Router 等
├── native/                 # 原生模块懒加载
├── bridge/                 # NativeBridge 通用桥接
├── features/               # UI 能力(播放器、浏览器、扫码、Toast…)
├── contracts/              # 与 mp-jssdk 共享的运行时契约
├── compat/                 # SDKPortal、SDKFuncsAdapter 兼容层
├── types/                  # sdk 引擎类型、AppSdkRef、Config、事件、错误类型
├── events/                 # EventBus
├── providers/              # SdkProviders(Context)
└── SDK_NATIVE_APIS.md      # 原生库 API 对照文档

架构要点

  1. 双 API 层AppSdkRef(Facade + Modules)面向宿主新业务;SDKFuncs(Engine)面向 jssdk 与历史代码。
  2. Host Adapter 模式:UI 弹层与宿主业务解耦,默认实现可替换。
  3. 模块注册表:核心能力模块化,支持 registerModule 扩展。
  4. 事件总线:网络、前后台、配置变更等通过 on / emit 统一分发。
  5. 全局契约DGZ_GLOBAL_CURRENT_MP_CLIENT 连接 RN SDK 与 JS SDK,保证小程序代码零改动迁移。

从 SDKPortal 迁移

- import { SDKPortal } from '@htyf-mp/rn-sdk';
+ import { AppSdk, type AppSdkRef } from '@htyf-mp/rn-sdk';

- <SDKPortal appid="x" launchOptions={...} onReady={(sdk) => ...} />
+ <AppSdk appId="x" config={{ debug: __DEV__ }} launchOptions={...} onReady={(ref) => ...} />

onReady 回调参数由 SDKFuncs 变为 AppSdkRef;若仍需引擎实例,使用 ref.getEngine?.()


相关文档


开发

# 类型检查
pnpm --filter @htyf-mp/rn-sdk type-check

License

MIT