@coralogix/react-native-plugin

中文文档
0.16.0发布于 2026/11/09Apache-2.0TypeScriptESM + CJS近 30 天下载 9.9万

Official Coralogix React Native plugin

原始使用文档
文档目录20 节
  1. Links
  2. Usage
  3. Custom Logs
  4. Error Reporting
  5. View Tracking
  6. Recreate Session
  7. Instrumentation's
  8. Mobile Vital Detectors
  9. Exclude From Sampling
  10. Ignore Errors
  11. TraceParentInHeader
  12. Custom Spans
  13. Time Measurement
  14. Traces Exporter
  15. beforeSend
  16. Proxy URL
  17. Session Replay
  18. Masking Sensitive Content
  19. Optional - Coralogix Gradle Plugin (Android)
  20. Troubleshooting

Official Coralogix React Native Plugin

npm version

This package replaces the old @coralogix/react-native-sdk package.

Usage

To use Coralogix SDK, call CoralogixRum.init(options) at the soonest available moment after the app loads. This will initialize the SDK based on the options you provided. init is an async function.

import { CoralogixRum } from '@coralogix/react-native-plugin'

await CoralogixRum.init({
  application: 'app-name',
  environment: 'production',
  public_key: 'abc-123-456',
  coralogixDomain: 'EU2',
  version: 'v1.0.3',
  labels: {
    payment: 'visa',
  },
  ignoreErrors: ['some error message to ignore'],
  ignoreUrls: [/.*\.svg/, /.*\.ico/], // will ignore all requests to .svg and .ico files 
  sessionSampleRate: 100, // Percentage of overall sessions being tracked, Default to 100%
});

The native SDK applies sessionSampleRate once per session, including each new session after the previous one expires. Set it to a whole percentage in 0-100. The plugin rounds a fractional value to an integer, and never rounds a non-zero rate down to 0, because the native bridges read the value as an integer.

A sampled-out session still initializes the SDK and, when traceParentInHeader is enabled, still adds the traceparent header to outgoing requests, so backend traces stay correlated. Beyond that it reports nothing unless excludeFromSampling lists at least one category: no initialization event, and no session_replay_init even when Session Replay starts. List a category and that category is reported, together with the SDK's own internal events.

To provide contextual information or transmit manual logs, utilize the exported functions of CoralogixRum. Keep in mind that these functions will remain inactive until you've invoked CoralogixRum.init().

import { CoralogixRum } from '@coralogix/react-native-plugin';

// Update user context dynamically
CoralogixRum.setUserContext({
  user_id: '123',
  user_name: 'name',
  user_email: '[email protected]',
  account_id: 'acc-42', // optional, from 0.12.0
  account_name: 'Acme Corp', // optional, from 0.12.0
  user_metadata: {
    role: 'admin',
    // ...
  },
});

// Update custom labels dynamically
CoralogixRum.setLabels({
  ...CoralogixRum.getLabels(),
  paymentMethod: 'visa',
  userTheme: 'dark',
  // ...
});

// Update application context dynamically
CoralogixRum.setApplicationContext({
  application: 'app-name',
  version: '1.0.0',
});

CoralogixRum.log(CoralogixLogSeverity.Error, 'this is a log', { key: 'value' });
CoralogixRum.error('this is a log with error severity', { key: 'value' });

Custom Logs

Send structured logs with optional data and labels.

CoralogixRum.log(CoralogixLogSeverity.Error, 'this is a log', { key: 'value' });

Shorthand signatures exists for all log severities:

CoralogixRum.debug('this is a debug log', {key: 'value', pi: 3.14});
CoralogixRum.error('this is an error log', {error: 'yes', is_bad: 'no'});

[!NOTE] Due to React Native limitations, not all value types are supported for the log data values. Our testing shows that React Native can't pass some types to the coralogix native layer; the ones we have identified as problematic are Map, Set, Date and Function. There could be more. For example:

// this would pass as an empty object to the coralogix native layer, same for Set and Date:
CoralogixRum.debug('this will be a problem', {key: new Map().set(1, 2)});

// this would pass as null to the coralogix native layer
CoralogixRum.debug('this will be a problem too', {key: () => {}});

If you need to pass any of these types, stringify them before you pass them to the log method.

Error Reporting

Report handled errors with optional structured data and labels. Choose one of the variants below per error event — each call generates a single error report.

Parameters:

  • error (Error): The error object to report.
  • isCrash (boolean): Whether this error represents a crash (true) or a handled exception (false).
  • data (optional): Structured data object attached to the error event. Empty objects are omitted.
  • labels (optional): Key-value pairs for categorizing the error event. Empty objects are omitted.

Variant 1: Basic error reporting

import { CoralogixRum } from '@coralogix/react-native-plugin';

try {
  await processPayment(order);
} catch (error) {
  CoralogixRum.reportError(error, false);
}

Variant 2: With structured data

try {
  await processPayment(order);
} catch (error) {
  CoralogixRum.reportError(error, false, {
    orderId: '12345',
    paymentMethod: 'visa',
    amount: 99.99,
  });
}

Variant 3: With data and labels

try {
  await processPayment(order);
} catch (error) {
  CoralogixRum.reportError(
    error,
    false,
    { orderId: '12345', amount: 99.99 },
    { team: 'payments', severity: 'high' }
  );
}

Reporting crashes:

try {
  await criticalOperation();
} catch (error) {
  CoralogixRum.reportError(
    error,
    true, // isCrash = true
    { operation: 'criticalTask', stage: 'initialization' },
    { environment: 'production' }
  );
}

View Tracking

To track views, set the view context whenever a view changes.

CoralogixRum.setViewContext({
  view: 'Home',
});

You can automatically track view changes by using react-navigation. Use the NavigationContainer onStateChange callback to track route changes and update the view context manually, as shown below:

<NavigationContainer
  ref={navigationRef}
  onStateChange={() => {
    const currentRouteName = navigationRef.current.getCurrentRoute().name;

    CoralogixRum.setViewContext({ view: currentRouteName });
  }}
>
  {/* ... */}
</NavigationContainer>

Recreate Session

Recreate the RUM session on demand — for example, on user logout — so that subsequent events belong to a fresh session with a new session id.

CoralogixRum.createNewSession();

Instrumentation's

Turn on/off specific instrumentation; defaults to true for all. Each instrumentation is responsible for which data the SDK will track and collect for you.

await CoralogixRum.init({
  // ...
  instrumentations: {
    errors: true,
    custom: true,
    mobile_vitals: true,
    anr: true,
    lifecycle: true,
    user_interaction: true,
    network: true
  },
});

[!NOTE] The network instrumentation also injects the W3C traceparent header. Setting network to false stops trace context propagation as well, even when traceParentInHeader is enabled.

Mobile Vital Detectors

Disable specific mobile vitals detection and collection

await CoralogixRum.init({
  // ...
  mobileVitals: {
    warm: true,
    cold: true,
    cpu: true,
    memory: true,
    rendering: true,
    slowFrozenFrames: true,
  }
});

Cold start

Two cold-start values are reported per user-visible launch:

  • cold — measured by the native SDK: process start to the first native frame.
  • cold_hybrid — measured by the plugin: process start to the first frame with React content on screen. This is the launch time your users actually see, so it is always at least cold.

Setting mobileVitals.cold (or instrumentations.mobile_vitals) to false disables both. Launches that start in the background (headless JS, background fetch, push) and prewarmed iOS launches do not report cold_hybrid.

[!NOTE] On Android, cold_hybrid is not reported in bridgeless mode (the New Architecture default since React Native 0.74): React Native only emits the content-appeared marker it relies on when the app runs with the bridge.

Exclude From Sampling

By default, when a session is sampled out (via sessionSampleRate), none of its RUM events are reported. Use excludeFromSampling to keep reporting specific event categories even when the session is sampled out.

import { CoralogixRum } from '@coralogix/react-native-plugin';

await CoralogixRum.init({
  // ...
  sessionSampleRate: 10,
  excludeFromSampling: ['errors', 'logs'], // always emitted, even for sampled-out sessions
});

Allowed values: 'errors', 'logs', 'network', 'userInteractions', 'mobileVitals', 'customSpan', 'customMeasurement', 'navigation', and 'lifecycle'. 'navigation' and 'lifecycle' are available from version 0.15.0. These are the same values the native iOS and Android SDKs accept. The plugin ignores an unrecognized value and logs a warning that names it.

excludeFromSampling only affects sampled-out sessions; a sampled-in session reports everything that is enabled. It never re-enables an instrumentation you turned off in instrumentations: with instrumentations: { network: false }, listing 'network' here has no effect.

Listing anything here also brings back the SDK's own internal events — the initialization event, and session_replay_init when Session Replay starts — for that sampled-out session. Leave the list empty and the session reports nothing at all.

Inside a beforeSend callback, session_context.isSessionSampledIn tells you whether an event came from a sampled-in session or reached you only via excludeFromSampling, so excluded categories can be filtered further.

Ignore Errors

The ignoreErrors option allows you to exclude errors that meet specific criteria. This options accepts a set of strings and regular expressions to match against the event's error message. Use regular expressions for exact matching as strings remove partial matches.

import { CoralogixRum } from '@coralogix/react-native-plugin';

await CoralogixRum.init({
  // ...
  ignoreErrors: [/Exact Match Error Message/, 'partial/match'],
});

TraceParentInHeader

Add trace context propagation in headers across service boundaries

await CoralogixRum.init({
  // ...
  traceParentInHeader: {
    enabled: true
  },
});

[!NOTE] The traceparent header is added by the network instrumentation, so this feature depends on it. If you set instrumentations.network to false, no trace headers are sent even with enabled: true.

From version 0.15.0, the trace flags at the end of traceparent follow the session's sampling decision, on iOS and Android alike:

  • 01 (sampled) when the session is sampled in, or when it is sampled out and excludeFromSampling includes 'network'.
  • 00 (not sampled) when the session is sampled out and 'network' is not excluded.

A request that starts before CoralogixRum.init completes carries no traceparent header.

If your Android app doesn't apply the Coralogix Gradle plugin, the plugin adds the header from JavaScript. Each fetch that gets a traceparent then waits up to 500 ms for the native SDK's sampling decision, and goes out without the header if the decision doesn't arrive in time. To keep that wait off requests you don't need to trace, list only your own services in traceParentInHeader.options.allowedTracingUrls.

Custom Spans

Create manual RUM spans to instrument custom flows in your application. Requires traceParentInHeader.enabled: true.

Prerequisite:

await CoralogixRum.init({
  // ...
  traceParentInHeader: { enabled: true },
});

Basic usage — global span with a child:

import { CoralogixRum } from '@coralogix/react-native-plugin';

const tracer = CoralogixRum.getCustomTracer();

const globalSpan = await tracer.startGlobalSpan('checkout', { step: 'start' });
if (!globalSpan) return; // another global span is already active

const childSpan = await globalSpan.startCustomSpan('validate-cart');
await childSpan?.endSpan();

await globalSpan.endSpan();

Linking network requests with withContext:

When you call fetch inside withContext, the network request is automatically linked to the active global span's trace.

const globalSpan = await tracer.startGlobalSpan('checkout');

await globalSpan.withContext(async () => {
  await fetch('https://api.example.com/cart'); // linked to globalSpan's traceId
});

await globalSpan.endSpan();

ignoredInstruments — exclude auto-instrumentation from the trace:

Pass instrument names to prevent network requests, errors, or interactions fired during this tracer's spans from being linked to your custom trace.

const tracer = CoralogixRum.getCustomTracer(['networkRequests', 'userInteractions', 'errors']);

[!NOTE] Only one global span may be active at a time. startGlobalSpan returns null if a global span is already open.

Time Measurement

Measure the duration of arbitrary flows with a pair of startTimeMeasure(name, labels?) / endTimeMeasure(name) calls. The native SDK records start/end timestamps and reports the delta as a custom-measurement span (milliseconds).

import { CoralogixRum } from '@coralogix/react-native-plugin';

CoralogixRum.startTimeMeasure('checkout', { flow: 'checkout' });

await validateCart();
await charge();
await confirm();

CoralogixRum.endTimeMeasure('checkout');

Behaviour:

  • Both calls are fire-and-forget — they cross the bridge directly into native and return immediately.
  • The JS side keeps no state; the native SDK owns the in-flight registry.
  • You are responsible for pairing every startTimeMeasure(name, labels?) with exactly one endTimeMeasure(name). Leaked starts persist in memory until CoralogixRum.shutdown().
  • Unmatched endTimeMeasure calls are dropped silently by the native SDK.
  • Calling startTimeMeasure again with an open name overwrites the previous start.

Traces Exporter

Receive OTLP-formatted trace batches from the native SDK in your JavaScript code. Use this to forward spans to an OTLP-compatible backend (e.g. Jaeger, custom collector) alongside Coralogix.

await CoralogixRum.init({
  // ...
  tracesExporter: (data) => {
    // data.resource_spans contains OTLP JSON-format span data
    sendToMyOtlpBackend(JSON.stringify(data));
  },
});

The callback receives a TraceExporterData object following the OTLP JSON format:

{
  resource_spans: [
    {
      resource: { attributes: [{ key: string, value: { string_value: string } }] },
      scope_spans: [
        {
          scope: { name: string, version?: string },
          spans: [
            {
              trace_id: string,
              span_id: string,
              parent_span_id?: string,
              name: string,
              start_time_unix_nano: string,
              end_time_unix_nano: string,
              attributes: [{ key: string, value: {...} }],
              status: { code: string },
            }
          ]
        }
      ]
    }
  ]
}

[!NOTE] The callback fires once per native export batch, which typically contains several spans rather than one per span.

beforeSend

Enable event access and modification before sending to Coralogix, supporting content modification, and event discarding.

await CoralogixRum.init({
  // ...
  beforeSend: (event) => {
    // Discard events from @company.com users.
    if (event.session_context.user_email?.endsWith('@company.com')) {
      return null;
    }

    // Redact sensitive information.
    event.session_context.user_email = '***@***';

    return event;
  },
});

Telling excluded events apart in beforeSend

Every event carries session_context.isSessionSampledIn. false means the event reached you from a session that was sampled out. That happens when the event's category is listed in excludeFromSampling, and for the SDK's own internal events, which travel with any non-empty exclude list. Use it to apply your own filtering on top of the exclude list, for example to keep only error-severity events from sampled-out sessions:

await CoralogixRum.init({
  // ...
  sessionSampleRate: 10,
  excludeFromSampling: ['errors', 'logs'],
  beforeSend: (event) => {
    // Default to `true`: a native SDK older than the one this plugin pins does not
    // stamp the flag, and `!undefined` would drop everything but errors.
    const sampledIn = event.session_context.isSessionSampledIn ?? true;

    // Session sampled out: forward only error-severity events, drop the rest.
    if (
      !sampledIn &&
      event.event_context?.severity !== CoralogixLogSeverity.Error
    ) {
      return null;
    }

    return event;
  },
});

[!NOTE] Always read it as isSessionSampledIn ?? true. The field is absent on native SDKs that predate it, and the SDK never invents a value it was not given.

isSessionSampledIn is read-only: it reports the SDK's sampling decision for the session, so assigning to it has no effect on the sent event. The decision is recorded when the event is created, so events buffered across a session rotation keep the decision of the session they belong to.

Read-only fields

Some fields exist for the callback to read, not to change. The SDK restores its own values after beforeSend returns, so assigning to any of them — or injecting one into a returned object — has no effect on the sent event.

Inside session_context, only the user fields are editable:

EditableRead-only
user_id, user_name, user_email, user_metadatasession_id, session_creation_date, isSessionSampledIn, hasRecording

Any other key in session_context — including one your callback invents — is discarded, so session identity cannot be forged.

Deleting an editable field is honored, since redaction-by-deletion is a valid use. That means returning a hand-built partial session_context drops the user fields you left out; edit the event you were given (or spread it) if you want to change one field and keep the rest.

These top-level fields are read-only too, because rewriting them would corrupt trace correlation, event dedup or product analytics rather than redact anything:

spanId, traceId, fingerPrint, timestamp, platform, mobile_sdk, snapshot_context, isSnapshotEvent, prev_session, view_number, isNavigationEvent

view_number and isNavigationEvent record what the SDK observed when it built the event. They are deliberately not recomputed from event_context.type, so if you relabel an event the two can differ — filter on isNavigationEvent when you need "was this actually a navigation".

Everything else — event_context (including severity), labels, error_context, log_context, network_request_context, view_context, environment, device_context, device_state, version_metadata — is editable, and returning null still drops the event entirely.

Proxy URL

Proxy configuration to route requests.
By specifying a proxy URL, all RUM data will be directed to this URL via the POST method. However, it is necessary for this data to be subsequently relayed from the proxy to Coralogix. The Coralogix route for each request that is sent to the proxy is available in the request's cxforward parameter (for example, https://www.your-proxy.com/endpoint?cxforward=https%3A%2F%2Fingress.eu1.rum-ingress-coralogix.com%2Fbrowser%2Fv1beta%2Flogs).

await CoralogixRum.init({
  // ...
  coralogixDomain: 'EU1',
  proxyUrl: 'https://www.your-proxy.com/endpoint',
});

Session Replay

Session Replay allows you to record and replay user sessions to understand user behavior and debug issues.

Initialize Session Replay

To initialize Session Replay, call SessionReplay.init(options) with the desired configuration options.

import { SessionReplay } from '@coralogix/react-native-plugin';

await SessionReplay.init({
  captureScale: 0.5,                    // Scale factor for screenshots (0.0 to 1.0)
  captureCompressQuality: 0.8,         // Compression quality for screenshots (0.0 to 1.0)
  sessionRecordingSampleRate: 100,      // Percentage of sessions to record (0 to 100)
  autoStartSessionRecording: true,      // Automatically start recording when initialized
  maskAllTexts: true,                   // Mask all text content by default (optional, default: true)
  textsToMask: ['password', '^card.*'], // Array of strings/regex patterns for specific text masking (optional)
  maskAllImages: false,                 // Mask all images (optional, default: false)
});

Options:

  • captureScale (required): Scale factor for screenshots. Must be between 0.0 and 1.0. Lower values reduce file size but may decrease quality.
  • captureCompressQuality (required): Compression quality for screenshots. Must be between 0.0 and 1.0. Higher values improve quality but increase file size.
  • sessionRecordingSampleRate (required): Percentage of sessions to record. Must be between 0 and 100. Use 100 to record all sessions.
  • autoStartSessionRecording (required): If true, recording starts automatically after initialization. If false, you must manually call startSessionRecording().
  • maskAllTexts (optional): If true, all text content is masked by default. Defaults to true.
  • textsToMask (optional): Array of strings or regex patterns to mask specific text content. Only used when maskAllTexts is false.
  • maskAllImages (optional): If true, all images are masked. Defaults to false.

Check Initialization Status

Check if Session Replay has been initialized:

const isInited = await SessionReplay.isInited();
console.log('Session Replay initialized:', isInited);

Check Recording Status

Check if Session Replay is currently recording:

const isRecording = await SessionReplay.isRecording();
console.log('Session Replay recording:', isRecording);

Start Recording

Manually start session recording:

SessionReplay.startSessionRecording();

Note: If autoStartSessionRecording is set to true in the init options, recording starts automatically and you don't need to call this method.

Stop Recording

Manually stop session recording:

SessionReplay.stopSessionRecording();

Capture Screenshot

Manually capture a screenshot during a session:

SessionReplay.captureScreenshot();

This is useful for capturing specific moments in the user journey that you want to highlight.

Shutdown Session Replay

Shutdown Session Replay to clean up resources:

await SessionReplay.shutdown();

Masking Sensitive Content

Masking is not gated on Session Replay. It redacts sensitive content from user-interaction events whether or not you record replays, and when Session Replay is enabled the same mask also hides that content in the recording.

There are two ways to mask, and Masked is recommended. Mask the whole logical element — the field, the row, the button — rather than an inner fragment of it.

Masked is exported from the plugin itself and needs no Session Replay setup. Wrap anything sensitive in it — it renders a View and accepts the View props, so it can wrap a whole control or just the sensitive part of one:

import { Text } from 'react-native';
import { Masked } from '@coralogix/react-native-plugin';

<Masked>
  <Text>Card: {cardNumber}</Text>
</Masked>

Do not put Masked inside a <Text> — wrap the outermost <Text> instead.

SessionReplay.maskView

Alternatively, pass SessionReplay.maskView to the onLayout prop of any view. It accepts a LayoutChangeEvent and works on both the legacy and the New Architecture (Fabric):

import { Text, View } from 'react-native';
import { SessionReplay } from '@coralogix/react-native-plugin';

<View onLayout={SessionReplay.maskView}>
  <Text>{cardNumber}</Text>
</View>

Attach it to a host component — a custom component that accepts onLayout but never forwards it to a real view is silently not masked. Use Masked for a Switch; maskView cannot flag its interactions.

Masked interactions

A tap on masked content is still reported, with interaction_context.target_element_inner_text redacted to *** and interaction_context.is_masked_element: true. Identity fields and tap coordinates are reported as-is, and a replay recording shows no tap marker. is_masked_element is read-only, so use it in beforeSend to drop or further redact masked interactions.

Note that target_element falls back to accessibilityLabel, which is not redacted — give masked keypad keys a shared label (accessibilityLabel="pin-key") rather than the digit they enter.

Optional - Coralogix Gradle Plugin (Android)

The Coralogix Gradle Plugin automatically instruments all OkHttp clients in your app (including third-party SDKs) at build time. This ensures that all network traffic is automatically traced and reported to Coralogix, with no manual setup or code changes required. This plugin is especially useful for instrumenting networking libraries that create their own OkHttpClient instances internally and would otherwise be impossible to monitor.

Apply the plugin

  1. Add the plugin to your project classpath
    In your project-level build.gradle file:

    buildscript {
        dependencies {
            classpath "com.coralogix.gradle.plugin:gradle-plugin:0.0.2"
        }
    }
    
  2. Apply the plugin in your app module
    At the top of your app-level build.gradle file:

    apply plugin: "com.coralogix.gradle.plugin"
    

Configure the plugin

The plugin exposes a simple Gradle extension you can use in your app module:

coralogix {
  // Enable or disable instrumentation (default: true)
  enabled = true

  // Print debug logs during the build process (default: false)
  log = false
}

If the default configuration suits your needs, you can safely omit this block — the defaults will apply automatically.

Note

This plugin is optional. Regular JavaScript fetch calls and standard network requests will still be instrumented without it.

However, the plugin is the only way to capture network activity from third-party libraries or SDKs that use their own OkHttpClient instances internally.

Troubleshooting

URL.origin is not implemented

  1. npm install react-native-url-polyfill
  2. At the top of your entry-point file (index.js) add: import "react-native-url-polyfill/auto"

版本与发布记录

@coralogix/react-native-plugin 共发布 52 个版本,首次发布于 2025/09/01;过去 12 个月发布了 42 个版本。

版本发布日期距今
0.16.0latest2026/11/092 天前
0.15.02026/11/019 天前
0.14.22026/10/2120 天前
0.14.12026/10/1625 天前
0.14.02026/10/1526 天前
0.13.12026/10/1229 天前

关于 @coralogix/react-native-plugin 的常见问题

@coralogix/react-native-plugin 是什么?

Official Coralogix React Native plugin

如何安装 @coralogix/react-native-plugin?

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

@coralogix/react-native-plugin 支持 TypeScript 吗?

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

@coralogix/react-native-plugin 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@coralogix/react-native-plugin 可以商用吗?

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

@coralogix/react-native-plugin 的下载量有多少?

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

@coralogix/react-native-plugin 还在维护吗?

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