@codemagic/react-native-patch

中文文档
0.6.0发布于 2026/10/28Apache-2.0TypeScriptCommonJS零依赖近 30 天下载 3002

React Native客户端 SDK for Codemagic Patch – 为 React Native 和 Expo apps 提供超空 JavaScript & 资产更新.

中文使用文档
文档目录14 节
  1. 你得到的东西
  2. 所需资源
  3. 安装
  4. 快开始
  5. 博览( 配置插件)
  6. 裸体反应原生
  7. 环绕根元件
  8. 配置
  9. 裸体反应原生
  10. 博览应用程序
  11. 使用量
  12. 测试
  13. 文档
  14. 许可证

@codemagic/react-native-patch

客户端 SDK 为 密码补丁:一个自发托管的CodePush接班人,在React Introduct和Expoapps上进行超空更新. 下载、核实和启动JS/资产捆绑在设备上,这样你就可以在没有新商店二进制的情况下运送JS更改.

此软件包只是设备上的一面 。 您还需要一个 Patch 服务器( 自托管) 和 cmpatch 国 际 发布发行。 单相机有两种,外加一个仪表板和一个本地评价堆.

你得到的东西

从 单相数字 :

  • 通过 Docker 编译(API, 工人, Postgres, Silo, 仪表板) 完成堆栈
  • 与非洲区域局的网络仪表板和发行管理
  • 快速尝试OTA更新的在线演示应用程序

从这个SDK:

  • 可用时的二进制补丁, 用于较小的下载( 返回到完整捆绑)

  • 配置公钥时签名验证

  • 如果新软件包在应用程序报告准备好前失败, 则自动回滚

  • 用于预建项目的 Expo 配置插件, 外加赤色反射原生接线

  • 单行 Patch.wrap(App) 根包件, 代码Push 样式 sync(),或需要控制时的分步API

    the self-hosted Patch dashboard

所需资源

  • 原生反应 0.73+ ——新架构支持起始时间为RN 0.76;RN 0.73–0.75仅在旧(纸)架构上支持
  • 机器人 minSdkVersion 23+(图书馆遵循主机 rootProject.ext.minSdkVersion;没有一块,它建于23)
  • 支持 CMake/JNI 的 Android 本地建筑
  • 使用 CocoaPods 并混合 Swift/ ObjC++ 编译的 iOS 本地建筑
  • 曝光 SDK 52+ (通过捆绑的配置插件 —— 见) 博览应用程序(中文(简体) )
  • 博览 无法支持 Go - 本地模块不是世博会的一部分 Go runtime

包括世博会SDK 58 / RN 0.88.0主机在内的参考固定应用程序列于 E2E 固定工作空间。 。 。 .

安装

npm install @codemagic/react-native-patch
# or
yarn add @codemagic/react-native-patch

react (单位:千美元)>=18和 react-native (单位:千美元)>=0.73)是同伴的依赖关系。 在 iOS 上,安装本地 sock :

cd ios && pod install

快开始

配置居住于 本地资源 (部署密钥,API URL,下载基址,可选的公钥),不在JS配置对象中. 博览会插件为您写出这些; 赤裸的应用程序设置在其中 Info.plist 编号 : strings.xml 和钢丝捆绑选择.

博览( 配置插件)

如果您手动维护本地工程, 请遵循 手动本地设置。 。 。 .

{
  "plugins": [
    ["@codemagic/react-native-patch", {
      "ios": {
        "deploymentKey": "<key>",
        "downloadBaseUrl": "<url>",
        "apiUrl": "<url>",
        "publicKey": "<pem>"
      },
      "android": {
        "deploymentKey": "<key>",
        "downloadBaseUrl": "<url>",
        "apiUrl": "<url>",
        "publicKey": "<pem>"
      }
    }]
  ]
}

配置至少一个平台 。 你提供所需的每个街区 deploymentKey, (中文(简体) ), downloadBaseUrl,以及 apiUrl (单位:千美元)publicKey 财务报告和审定财务报表 maxLaunchAttempts )),可选. 然后运行 expo prebuild。见 配置 对于每个值的来源.

裸体反应原生

添加 CodemagicPatchDeploymentKey, (中文(简体) ), CodemagicPatchApiUrl,以及 CodemagicPatchDownloadBaseUrl (可选) CodemagicPatchPublicKey)去安卓号 strings.xml 和iOS系统 Info.plist,然后指出RN的JS捆绑路径 CodemagicPatch.getJSBundleFile 编号 : CodemagicPatch.bundleURL() 因此,启动命令正在等待包 → 当前包 → 嵌入式捆绑 。 完整片段进入 配置 见下文.

环绕根元件

import * as Patch from "@codemagic/react-native-patch";

function App() {
  return <AppNavigator />;
}

export default Patch.wrap(App);

wrap() 让你的应用程序马上运行 sync() 一旦根已经挂起。 没有选项, 普通更新在下次重新启动时安装, 强制更新立即安装; 通过 WrapOptions 作为改变这种情况的第二个论据(Patch.wrap(App, { installMode: Patch.InstallMode.ON_NEXT_RESUME })) (中文(简体) ).

设定 checkFrequency: "ON_APP_RESUME" 以检查挂载和前景返回; 默认值 "ON_APP_START" 只检查挂载。 例如: Patch.wrap(App, { checkFrequency: Patch.CheckFrequency.ON_APP_RESUME, installMode: Patch.InstallMode.ON_NEXT_RESTART })。用于手动检查时,使用没有 wrap()。 。 。 . Patch.CheckFrequency 财务报告和审定财务报表 Patch.InstallMode 提供命名常数; 现有的字符串文字仍然支持.

wrap() 向您的根组件转发道具和校对。 它不复制自定义静态属性, 例如 : App.navigationOptions在包装上.

上载被包裹的根 sync() 电话 notifyAppReady() 首先,这证实了运行的包 和武器回滚的下一个。 如果您的应用程序必须完成同步的靴子陷阱( 认证、 数据库迁移) , 才能保证运行的捆绑, 请跳过 wrap() 打电话 sync() 那时你自己:

import { sync } from "@codemagic/react-native-patch";
import { bootstrapApp } from "./bootstrap"; // Your app's initialization routine.

await bootstrapApp(); // If initialization fails, do not confirm the bundle.
const status = await sync();
// "update-installed" | "up-to-date" | "embedded-revert-applied"
// | "sync-in-progress" | "error"

sync() 从来没有扔过。 它检查一个更新,下载和安装 在适当的时候, 和报告应用准备.

检查/ 下载/ 安装为单独的步骤, 重新启动计时帮助器( E) :restartApp, (中文(简体) ), allowRestart 编号 : disallowRestart, (中文(简体) ), getRunningBundleUpdateMetadata() 读取 OTA 发布正在运行中,或 isNextVersionReady() 以了解是否正在等待下一次重新装入已安装的更新,请参见 SDK 类型。 。 。 .

配置

密码补丁通过配置 本地资源,而不是一个JS API——在SDK初始化之前,在本地读取部署密钥,URL,公钥和二进制版本. 每个主机应用程序提供这些值 :

资源需求含义
CodemagicPatchDeploymentKey对此应用程序/ 轨道的部署密钥
CodemagicPatchApiUrl对API 服务器来源( 服务器的) SERVER_URL),例如. https://updates.example.com。SDK附件 /v1/...
CodemagicPatchDownloadBaseUrl对艺术来源( 服务器的) PUBLIC_BASE_URL),例如. https://storage.example.com/codemagic-patch。可能包括桶/路径前缀;SDK附件显示/艺术路径
CodemagicPatchPublicKey没有PEM 公钥; 仅在执行客户端签名验证时需要
CodemagicPatchMaxLaunchAttempts没有正整数; 连续发射未完成的更新可能会启动, 不包含 notifyAppReady() 在坠入前。 默认 2; 见 notifyAppReady()

这两个URL指向不同的系统(API服务器对对象存储 / CDN),这就是一个通常携带路径而另一个不携带路径的原因.

数值来自: 部署键为 DEPLOYMENT_KEY 页:1 cmpatch deployment list --app <app-name> --format table (或部署在仪表板中的页面);API URL和下载基础URL由自主机安装者在服务器设置时打印出. 使用 iOS和Android的单独应用软件,因此也分别部署密钥。 。 。 .

裸体反应原生

  1. 申报资源.

    iOS - (英语) ios/<YourApp>/Info.plist数字 :

    <key>CodemagicPatchDeploymentKey</key>
    <string>ios-staging-deployment-key</string>
    <key>CodemagicPatchDownloadBaseUrl</key>
    <string>https://storage-updates.example.com/codemagic-patch</string>
    <key>CodemagicPatchApiUrl</key>
    <string>https://updates.example.com</string>
    <!-- optional, only when enforcing code signing -->
    <key>CodemagicPatchPublicKey</key>
    <string>-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----</string>
    <!-- optional, defaults to 2 -->
    <key>CodemagicPatchMaxLaunchAttempts</key>
    <integer>2</integer>
    

    Android(英语: android/app/src/main/res/values/strings.xml数字 :

    <resources>
      <string name="CodemagicPatchDeploymentKey" translatable="false">android-staging-deployment-key</string>
      <string name="CodemagicPatchDownloadBaseUrl" translatable="false">https://storage-updates.example.com/codemagic-patch</string>
      <string name="CodemagicPatchApiUrl" translatable="false">https://updates.example.com</string>
      <!-- optional, only when enforcing code signing -->
      <string name="CodemagicPatchPublicKey" translatable="false">-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----</string>
      <!-- optional, defaults to 2 -->
      <string name="CodemagicPatchMaxLaunchAttempts" translatable="false">2</string>
    </resources>
    

    释放随着资源收缩而形成,保持这些串:从0.5.2起,SDK飞船是保持规则(res/raw/codemagic_patch_keep.xml合并到应用程序中。 在旧版本中, 在应用程序中添加相同的文件为 android/app/src/main/res/raw/codemagic_patch_keep.xml (无) keep.xml,由它执行土著捆绑的任务; 解决问题 有内容.

  2. 有线本地捆绑选择 在RN桥开通之前, 启动命令是 待处理软件包 → 当前软件包 → 嵌入式捆绑。 。 。 .

    Android——饲料 CodemagicPatch.getJSBundleFile(applicationContext) 进入本地状态 MainApplication关于RN 0.81(ReactNativeHost), 覆盖 getJSBundleFile()数字 :

    override fun getJSBundleFile(): String? =
        CodemagicPatch.getJSBundleFile(applicationContext)
    

    在RN 0.82+(新存档) reactHost,通过它作为 jsBundleFilePath数字 :

    override val reactHost: ReactHost by lazy {
      getDefaultReactHost(
        context = applicationContext,
        packageList = PackageList(this).packages,
        jsBundleFilePath = CodemagicPatch.getJSBundleFile(applicationContext),
      )
    }
    

    iOS - 导入 CodemagicPatchClient 并覆盖 bundleURL() 编号 : sourceURL(for:) 内 AppDelegate 选择顺序相同 留着 DEBUG 分公司指向Metro,所以本地开发继续工作:

    import CodemagicPatchClient
    
    class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
      override func sourceURL(for bridge: RCTBridge) -> URL? {
        self.bundleURL()
      }
    
      override func bundleURL() -> URL? {
    #if DEBUG
        RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
    #else
        CodemagicPatch.bundleURL() ?? Bundle.main.url(forResource: "main", withExtension: "jsbundle")
    #endif
      }
    }
    

    在RN Q 0.76上,应用程序模板仍装有目标-C++ AppDelegate.mm覆盖 sourceURLForBridge: 同样的选择。 原生模块是一个Swift舱 暴露在目标C @objc(CodemagicPatch); 生成 -Swift.h 不在主机目标头搜索路径上,并且 @import 在 ObjC++ 中不可用,所以向前声明您称之为表面 :

    // CodemagicPatch is a Swift pod exposed as @objc(CodemagicPatch); forward-declare it —
    // the implementation links in from the pod's static library.
    @interface CodemagicPatch : NSObject
    + (NSURL *_Nullable)bundleURL;
    @end
    
    - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
    {
    #if DEBUG
      return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
    #else
      return [CodemagicPatch bundleURL] ?: [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    #endif
    }
    

    预期嵌入式捆绑名称为 index.android.bundle (机器人)和 main.jsbundle (iOS) (中文(简体) ). 如果 SDK 无法确定非空白二进制版本( S)versionName 编号 : CFBundleShortVersionString),它不 -ops并倒回嵌入式捆绑.

    调试从 Metro 创建负载 JS,所以OTA的更新没有被接收到那里——这是预期的,不是一个接线问题. 要看到更新应用程序, 请运行一个发布样式的构建 .

  3. 注册本地模块 用于您的架构 — TurboModule (新架构) 或桥模块/包 (旧架构) 。 自动链接在大多数应用程序中处理此操作 .

博览应用程序

对于使用预建工程,请使用捆绑的配置插件( P)app.plugin.js如所示 快开始. 人工维护的本地项目使用本地配置和捆绑选择步骤取而代之。 插件配置为:

{
  "plugins": [
    ["@codemagic/react-native-patch", {
      "ios":     { "deploymentKey": "<key>", "downloadBaseUrl": "<url>", "apiUrl": "<url>", "publicKey": "<pem>" },
      "android": { "deploymentKey": "<key>", "downloadBaseUrl": "<url>", "apiUrl": "<url>", "publicKey": "<pem>" }
    }]
  ]
}

插件会自动写入本地资源并捆绑选择( Confignation steps 1–3) 。 配置 至少一个平台,并完成你提供的每一块块—— deploymentKey, (中文(简体) ), downloadBaseUrl,以及 apiUrl 需要每个区块(publicKey 财务报告和审定财务报表 maxLaunchAttempts )),可选. 插件解析 expo/config-plugins 从你的应用程序的 Expo SDK, 所以没有额外的安装; expo 不是此软件包的运行时间或同行依赖.

使用量

最简单的整合是 Patch.wrap(App),使您的根组件立即运行 sync() 在它升起之后. sync() 检查更新,下载,安装, 并报告应用准备在一个呼叫中。 它从不扔出——它解决了一个状态字符串. 当您需要自己选择时刻时直接拨打它, 例如在同步的靴子后:

import { sync } from "@codemagic/react-native-patch";
import { bootstrapApp } from "./bootstrap"; // Your app's initialization routine.

await bootstrapApp(); // If initialization fails, do not confirm the bundle.
const status = await sync();
// "update-installed" | "up-to-date" | "embedded-revert-applied"
// | "sync-in-progress" | "error"

更精细的控制,你自己开车 并打电话 notifyAppReady() 一旦应用程序成功启动( 所以更新不会回滚) :

import {
  checkForUpdate,
  downloadUpdate,
  installUpdate,
  notifyAppReady,
} from "@codemagic/react-native-patch";

restartApp, (中文(简体) ), allowRestart 编号 : disallowRestart,以及 hydrate 也用于控制重装时间, getRunningBundleUpdateMetadata() 报告运行中的OTA发布({ label, packageHash, releaseNotes },或 null 在嵌入的捆绑上 isNextVersionReady() 报告是否安装了新的软件包并等待下一次重新装入。 见 类型定义 对于完整的API表面.

测试

SDK在被导入时解决了它的涡轮Module,所以在Jest下,在没有本土二进制的情况下,一个在任何测试运行前导入失败的套件. 包裹为杰斯特装了个假的本地舱 真正的SDK运行在它上面,所以 sync(), (中文(简体) ), checkForUpdate() 其余的都按程序行事.

保留您已经使用的预设, 添加设置文件并添加 @codemagic 到允许列表 transformIgnorePatterns 已经拥有 :

// jest.config.js
module.exports = {
  preset: '@react-native/jest-preset', // or 'react-native' on older RN, or 'jest-expo'
  setupFiles: ['@codemagic/react-native-patch/jest-setup'],
  transformIgnorePatterns: [
    'node_modules/(?!((jest-)?react-native|@react-native(-community)?|@codemagic)/)',
  ],
};

需要许可名单条目是因为 react-native 导出条件 此软件包会像 React 原住民本身那样解决其类型Script 源头, 而 Jest 也不会变换 node_modules 默认.

设置文件安装了默认情景:应用程序运行商店二进制,服务器没有更新. 这足以进行SDK装入的测试. 对于另一种情况,安装有种子的假象,然后装入SDK:

import { installPatchFake, loadSdk } from '@codemagic/react-native-patch/jest';

test('reports the running release', async () => {
  installPatchFake({ running: { label: 'v4' } });
  const Patch = await loadSdk();
  expect(await Patch.getRunningBundleUpdateMetadata()).toMatchObject({ label: 'v4' });
});

test('an update is ready for the next launch', async () => {
  installPatchFake({ server: { release: { label: 'v5' } } });
  const Patch = await loadSdk();
  const status = await Patch.sync({
    installMode: Patch.InstallMode.ON_NEXT_RESTART,
    mandatoryInstallMode: Patch.InstallMode.ON_NEXT_RESTART,
  });
  expect(status).toBe('update-installed');
  expect(await Patch.isNextVersionReady()).toBe(true);
});

种子也带走了 binaryVersion, (中文(简体) ), runningUnconfirmed 与 previous, (中文(简体) ), failedInstall,以及 server.latestBinaryVersion 编号 : server.error· ; fake.fail(method, error) 让一个本地人拒绝呼叫 fake.setServer() 更改服务器的答案。 见 src/fake/types.ts。 。 。 .

隔离规则:

  • SDK每个模块实例读取原生模块和启动状态一次. installPatchFake() 仅会影响SDK 之后导入的例, 因此在导入正在测试的代码之前安装, 或调用 loadSdk() 安装后.
  • loadSdk() 电话 jest.resetModules() 并导入新的 SDK,取消上一个 loadSdk() 案件未决 ON_NEXT_SUSPEND 重新装入。 需要其他任何使用SDK(例如,你的组件)的,所以他们分享这个实例.
  • loadSdk() 不重置假件: 失败、 服务器答覆和下载的软件包 。 以新的方案开始 installPatchFake()。 。 。 .
  • sync() 先确认一个未确认的运行软件包; 使用 checkForUpdate() 编号 : downloadUpdate() 编号 : installUpdate() 保持它未经证实. restartApp() 在不重装JS的情况下解决.

在 Vitest 上,添加插件和设置文件,然后使用 installPatchFake 编号 : loadSdk 从 @codemagic/react-native-patch/vitest 同样的方式。 插件在它的TypeScript源头指向包,所以Vitest的模块会模拟到SDK. 适配器替换 react-native 带有一个只有SDK使用的模拟器(TurboModuleRegistry, (中文(简体) ), AppState, (中文(简体) ), DeviceEventEmitter因此,使组件与 react-dom 在一个 jsdom 环境。 在 Jest 下, 导入您使用 SDK 的模块 loadSdk(); React本身没有被重置,所以测试的React和SDK保持不变.

// vitest.config.ts
import { defineConfig } from 'vitest/config';
import { codemagicPatch } from '@codemagic/react-native-patch/vitest-plugin';

export default defineConfig({
  plugins: [codemagicPatch()],
  test: { setupFiles: ['@codemagic/react-native-patch/vitest-setup'] },
});

尚未覆盖:代码签名(假报告没有签名密钥),下载进度,推出百分比,以及检查SDK发送的度量事件.

文档

全面整合指南,更新协议,以及自我托管指令在 编码补丁寄存器。 。 。 .

来自 react-native-code-push♪ The 代码Push 迁移指南 绘制本地配置资源、 JS API 和 CLI 命令的代码补丁.

许可证

阿帕奇 - 2.0

版本与发布记录

@codemagic/react-native-patch 共发布 13 个版本,首次发布于 2026/07/01;过去 12 个月发布了 13 个版本。

版本发布日期距今
0.6.0latest2026/10/2813 天前
0.5.12026/10/1922 天前
0.5.02026/09/231 个月前
0.4.02026/09/141 个月前
0.3.02026/09/072 个月前
0.2.02026/08/222 个月前

关于 @codemagic/react-native-patch 的常见问题

@codemagic/react-native-patch 是什么?

React Native客户端 SDK for Codemagic Patch – 为 React Native 和 Expo apps 提供超空 JavaScript & 资产更新.

如何安装 @codemagic/react-native-patch?

在项目目录运行 npm install @codemagic/react-native-patch,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18)、react-native(>=0.73)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@codemagic/react-native-patch 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@codemagic/react-native-patch 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@codemagic/react-native-patch 可以商用吗?

@codemagic/react-native-patch 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@codemagic/react-native-patch 的下载量有多少?

根据 npm 官方下载统计,@codemagic/react-native-patch 在 2026/10/10 – 2026/11/08 这 30 天内被下载 3,002 次,日均约 100 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@codemagic/react-native-patch 还在维护吗?

最新版本 0.6.0 发布于 2026/10/28(13 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/07/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。