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

miaoda-expo-native-capabilities

v0.2.2

Published

Generate and compare Expo Development Build native capability manifests

Readme

miaoda-expo-native-capabilities

用于生成和比较 Expo Development Build 原生能力 manifest 的 Package。

它可以从当前 Expo 项目中提取 Expo Module、React Native 原生模块、平台原生模块名称、运行时配置以及自定义原生模块源码 hash,并判断当前项目所需能力是否是某个 Development Build 已提供能力的子集。

核心关系

比较方向是:

当前项目所需能力(required)⊆ Development Build 提供能力(provided)

因此:

  • provided 中多出的模块允许存在。
  • required 中缺失的模块、原生模块名称、核心能力会判定为不兼容。
  • 版本、运行时配置或自定义模块源码 hash 不一致会报告具体冲突。
  • 自定义模块缺少源码 hash 时,结果为 unknown,不会被当作兼容。

版本宽容集合

定制 Development Client 四件套(expo-dev-client、expo-dev-launcher、expo-dev-menu、expo-dev-menu-interface)默认在版本宽容集合 VERSION_TOLERANT_PACKAGE_NAMES 中:这些包只比较存在性与注册名称,不比较版本新旧。

理由:四件套是开发工具而非业务能力,版本差异只体现为开发 UI 的新旧(旧客户端由 JS 侧接口探测自动回退旧 UI);真正需要拦截的 SDK 层不兼容由 runtime.expoVersion 等 运行时比对承担。这样服务端更新四件套钉版后,装着旧版本的设备不会被判 version-conflict 弹「建议重新构建开发客户端」打扰用户。

宽容只作用于版本:四件套整个缺失(该构建不是定制 Development Build)或注册名称 缺失仍正常拦截。调用方可通过 compareExpoNativeCapabilities 的第三个参数覆盖集合 (传空集合恢复严格模式):

import {
  compareExpoNativeCapabilities,
  VERSION_TOLERANT_PACKAGE_NAMES,
} from 'miaoda-expo-native-capabilities';

// 扩展宽容范围
const result = compareExpoNativeCapabilities(required, provided, {
  versionTolerantPackages: new Set([...VERSION_TOLERANT_PACKAGE_NAMES, 'my-dev-tool']),
});

// 恢复对所有包的严格版本比较
const strict = compareExpoNativeCapabilities(required, provided, {
  versionTolerantPackages: new Set(),
});

依赖与分析器

Package 不内置 Expo SDK,也不依赖全局 Expo 安装。能力提取时会从目标项目解析实际使用的:

  • expo-modules-autolinking
  • @expo/config
  • expo
  • react-native

目标项目需要能够解析这些 Package。默认情况下,分析器版本跟随目标项目实际参与构建的版本,以保证提取结果和原生构建行为一致。

不同 Expo SDK 的 autolinking 发现规则和 JSON 输出可能发生变化。不能仅凭更新分析器版本就断言它一定兼容旧 SDK;如果要统一使用较新的分析器,应先用真实的 Expo 55、57 等项目 fixture 验证。

Import API

推荐在 Node.js 或服务端代码中直接 Import 使用:

import {
  compareExpoNativeCapabilities,
  createExpoNativeCapabilitiesAsync,
} from 'miaoda-expo-native-capabilities';

// 生成当前项目需要的原生能力
const required = await createExpoNativeCapabilitiesAsync(projectRoot, {
  platform: 'android',
});

// provided 是 Development Build 构建时保存的 manifest
const result = compareExpoNativeCapabilities(required, buildManifest);

if (result.compatible) {
  console.log('Development Build 可以继续使用');
} else {
  console.log('Development Build 不兼容', result);
}

compareExpoNativeCapabilities 接收两份能力数据和一个可选的配置参数:

| 参数 | 含义 | | --- | --- | | required | 当前项目运行所需的能力,通常由当前源码实时生成 | | provided | Development Build 编译时保存的能力,通常从构建元数据读取 | | options | 可选行为配置;versionTolerantPackages 覆盖版本宽容集合(默认为 VERSION_TOLERANT_PACKAGE_NAMES,见上文「版本宽容集合」) |

返回值 ExpoNativeCompatibilityResult 包含:

  • compatible:是否兼容。只有没有任何缺失或冲突时才为 true。
  • status:compatible、incompatible 或 unknown。
  • missingModules:缺失的 Package。
  • missingNativeModuleNames:缺失的平台原生模块名称。
  • missingCoreFeatures:缺失的 Expo 核心能力。
  • versionConflicts:Package 版本冲突(版本宽容集合中的包不会出现在这里)。
  • customModuleConflicts:自定义模块来源或源码 hash 冲突。
  • runtimeConflicts:Expo、React Native、JS Engine、New Architecture 或平台冲突。
  • reasons:每条不兼容原因的结构化双语提示,包含稳定的 code、messageZh、messageEn,以及可选的 packageName。

调用方可以根据用户语言选择 messageZh 或 messageEn,不要根据提示文本判断原因,应使用 code。

生成 manifest

应在编译 Development Build 的同一个源码 checkout 中生成 manifest,并将它和构建元数据一起保存:

expo-native-capabilities generate --root . --platform android --output development-build.android.json
expo-native-capabilities generate --root . --platform ios --output development-build.ios.json

manifest 按平台分别生成。Android 和 iOS 的原生能力不能混用,应分别保存和比较。

Package 不会在编译完成后读取 APK 或 IPA 来反向推断能力。必须在原生编译之前生成 manifest,这样自定义模块的源码 hash 才对应实际被编译的源码。

比较两份 manifest

如果已经有两份 manifest,可以直接通过 Import API 比较:

const result = compareExpoNativeCapabilities(requiredManifest, providedManifest);

也可以使用 CLI:

expo-native-capabilities check \
  --required current-project.android.json \
  --provided development-build.android.json

CLI 会输出 JSON 格式的比较结果,适合 CI、构建脚本或构建元数据服务使用。

自定义原生模块

模块 Package 根目录位于 node_modules 之外时,会被识别为 custom 模块,并计算确定性的 SHA-256 源码 hash。这样可以识别:

  • 当前项目新增了原生模块。
  • 自定义模块的 Android 或 iOS 原生实现发生变化。
  • Development Build 中编译的自定义模块源码与当前源码不一致。

如果自定义模块通过 workspace 或 symlink 引入,Package 会使用 realpath 判断真实位置,避免把本地源码误判成普通依赖。

Dev Server HTTP API

仓库中的 Expo Dev Server 提供以下接口:

读取当前项目能力

GET /innerapi/v1/sourcecode/expo/native-capabilities

接口会重新计算当前项目的 Android 和 iOS manifest,返回当前源码的原生能力。

检查 Development Build 是否兼容

POST /innerapi/v1/sourcecode/expo/native-capabilities/check

请求体可以直接传入一份 provided manifest,也可以传入:

{
  "provided": {
    "schemaVersion": 1,
    "platform": "android",
    "runtime": {
      "expoVersion": "55.0.0",
      "reactNativeVersion": "0.83.0",
      "jsEngine": "hermes",
      "newArchitecture": true
    },
    "modules": [],
    "coreFeatures": []
  }
}

服务端会实时生成当前项目的 required manifest,再和传入的 provided manifest 比较,并在 data.result 中返回兼容关系和所有冲突详情。

当前边界

能力比较依赖规范化后的 manifest schema,不依赖 Expo SDK 的具体版本。能力提取仍然使用目标项目自己的 Expo 配置和 autolinking 版本。

当前方案重点覆盖 autolinking 原生模块、运行时配置、核心能力和自定义模块源码 hash;它不是完整的 @expo/fingerprint,尚未覆盖所有 app-level config plugin、权限声明或任意原生工程文件变化。