
Expo Application在 React Native 运行时读取原生应用信息的完整指南【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo导读本文围绕 Expo 官方原生模块expo-application仓库位置packages/expo-application展开讲解如何在 Android、iOS 与 Web 三端运行时获取原生应用信息包括应用 ID、应用名、版本号、构建号、安装时间以及各平台特有的设备标识与发布渠道判定等能力。读完本文你将掌握该模块的安装方式、全部 API 的用法与返回值语义、各平台的差异与底层实现原理并能在分析、埋点、灰度与合规场景中直接落地使用。一、模块定位运行时读取原生应用元数据expo-application是一个通用模块universal module其官方定位一句话即可概括在运行时获取原生应用信息例如应用 ID、应用名称与构建版本见 package.json 中的描述A universal module that gets native application information such as its ID, app name, and build version at runtime。它解决的典型问题是JS 侧无法直接读取 AndroidPackageInfo或 iOSInfo.plist中的元数据而这些数据在以下场景中不可或缺版本兼容判断读取nativeApplicationVersion与服务端下发的能力阈值比较决定是否展示升级引导渠道与归因分析通过getInstallReferrerAsyncAndroid获取安装来源灰度与发布渠道识别通过 iOS 的getIosApplicationReleaseTypeAsync判断当前是 App Store、Ad Hoc 还是开发构建安装/更新时间统计通过getInstallationTimeAsync、getLastUpdateTimeAsync计算留存与更新周期。模块采用 Expo Modules 标准架构三端实现分别位于TypeScript 统一入口与类型声明src/Application.ts、src/Application.types.tsAndroid 原生实现android/src/main/java/expo/modules/application/ApplicationModule.ktiOS 原生实现ios/ApplicationModule.swiftWeb 降级实现src/ExpoApplication.web.ts。二、安装与前置条件2.1 Managed Expo 项目在受管的 Expo 托管项目中直接使用npx expo install安装即可该命令会自动选取与当前 SDK 匹配的版本并同步安装其 peer 依赖exponpx expo install expo-application2.2 Bare React Native 项目在裸 React Native 项目中需要先确保已安装并配置好expo包即完成 Expo Modules 的接入然后再添加本模块npx expo install expo-applicationexpo-application的 peer 依赖为expoexpo: *见 package.json自身没有其他第三方运行时依赖dependencies为空接入成本很低。在 Expo 自动链接机制autolinking下原生工程构建时会自动注册该模块无需手动改动 Android/iOS 工程文件。三、同步常量一行代码读取基础应用信息expo-application暴露了四个同步常量它们都是模块加载时从原生层一次性读取的模块常量Module Constant类型均为string | null。在 Web 平台上这四个值恒为null见 src/ExpoApplication.web.ts。3.1 nativeApplicationVersion —— 面向用户展示的版本号import * as Application from expo-application; console.log(Application.nativeApplicationVersion); // 例如 2.11.0Android读取PackageInfo.versionName即 app config 中version字段在构建时写入的值iOS读取Info.plist的CFBundleShortVersionStringWebnull。3.2 nativeBuildVersion —— 内部构建号console.log(Application.nativeBuildVersion); // 例如 114Android读取PackageInfo.versionCode底层经getLongVersionCode兼容 API 28 前后的取值差异即 app config 中android.versionCode的值iOS读取Info.plist的CFBundleVersion独立构建中对应 app config 的ios.buildNumber注意Android 与 iOS 上返回类型均为stringWebnull。3.3 applicationName —— 桌面/主屏显示的应用名console.log(Application.applicationName); // 例如 Expo、Yelp、InstagramAndroid通过applicationInfo.loadLabel(packageManager)读取见 ApplicationModule.ktiOS读取CFBundleDisplayName若名称无法获取则返回nullWeb 恒为null。3.4 applicationId —— 应用唯一标识console.log(Application.applicationId); // 例如 com.cocoacasts.scribblesAndroid即 application IDpackageNameiOS即 bundle IDCFBundleIdentifierWebnull。从源码结构看这四个常量在 Android 侧均通过getPackageInfoCompat统一封装获取PackageInfo内部按 API 33 以上使用PackageInfoFlags新 API旧版本走废弃的getPackageInfo(packageName, flags)见 ApplicationModule.kt失败时抛出带明确错误文案的ApplicationPackageNameNotFoundException。四、异步 API安装信息、设备标识与归因4.1 getInstallationTimeAsync —— 首次安装时间双端支持const installTime await Application.getInstallationTimeAsync(); // 2019-07-18T18:08:26.121Z返回Date对象语义为应用安装到设备的时间不包含后续更新若应用被卸载后重装则返回重装时间。Android底层读取PackageInfo.firstInstallTimeiOS读取应用 Documents 根目录文件的创建时间NSFileCreationDate见 ApplicationModule.swift并以毫秒时间戳返回后在 JS 层包装为Date见 Application.tsWebnull。4.2 getLastUpdateTimeAsync —— 最近更新时间仅 Androidconst lastUpdate await Application.getLastUpdateTimeAsync(); // 2019-07-18T21:20:16.887Z底层读取PackageInfo.lastUpdateTime语义为最近一次从 Google Play 更新的时间。该 API 标注platform android在 iOS 上调用会因原生方法缺失而抛出UnavailabilityError。4.3 getAndroidId —— ANDROID_ID仅 Androidconst androidId Application.getAndroidId(); // dd96dec43fb81c97同步方法返回Settings.Secure.ANDROID_ID。这是一个十六进制字符串对应用签名密钥 用户 设备的组合唯一因此设备恢复出厂设置、或 APK 签名密钥变化时该值可能改变Android 8.0API 26及以上ANDROID_ID的取值规则受平台隐私策略影响不同签名、不同用户会得到不同值Android 8.0 以下该值在设备生命周期内保持恒定在非 Android 平台iOS/Web调用会抛出UnavailabilityError见 Application.ts。4.4 getInstallReferrerAsync —— 安装来源归因仅 Androidconst referrer await Application.getInstallReferrerAsync(); // utm_sourcegoogle-playutm_mediumorganic通过 Google Play 的 [Install Referrer API] 获取应用安装时的 referrer 信息。返回值不一定是一个完整的绝对 URL通常是utm_*参数串可直接用于渠道归因分析。底层实现值得展开模块通过InstallReferrerClient建立异步连接并根据响应码分情况处理见 ApplicationModule.kt响应码含义处理OK连接成功且收到响应解析installReferrer并 resolveFEATURE_NOT_SUPPORTED当前 Play Store 不提供该 APIrejectERR_APPLICATION_INSTALL_REFERRER_UNAVAILABLESERVICE_UNAVAILABLE连接建立失败rejectERR_APPLICATION_INSTALL_REFERRER其他通用错误reject 并附带响应码连接中断onInstallReferrerServiceDisconnected服务失联rejectERR_APPLICATION_INSTALL_REFERRER_SERVICE_DISCONNECTED连接期间若抛RemoteException则 rejectERR_APPLICATION_INSTALL_REFERRER_REMOTE_EXCEPTION。可见该 API 在模拟器或缺少 Play Store 的环境下会失败落地时务必做好错误兜底。4.5 getIosIdForVendorAsync —— IDFV 厂商标识仅 iOSconst idfv await Application.getIosIdForVendorAsync(); // 68753A44-4D6F-1226-9C60-0050E4C00067返回 iOS 的 identifierForVendorIDFV语义要点同一厂商vendor的所有 App 返回相同 ID可用于跨 App 的用户关联偶尔会返回null典型场景是设备重启后、用户尚未解锁之前此时应稍等再重试若该厂商的所有 App 均被卸载系统会更换 vendor ID因此不宜将其作为永久设备标识持久化。4.6 getIosApplicationReleaseTypeAsync —— 发布渠道判定仅 iOSimport { ApplicationReleaseType } from expo-application; const releaseType await Application.getIosApplicationReleaseTypeAsync(); if (releaseType ApplicationReleaseType.APP_STORE) { // 商店正式包 }返回枚举ApplicationReleaseType定义见 src/Application.types.ts枚举值数值含义UNKNOWN0无法判定SIMULATOR1模拟器构建ENTERPRISE2企业分发In-HouseDEVELOPMENT3开发构建AD_HOC4Ad Hoc 分发APP_STORE5App Store 正式版底层判定逻辑在 Objective-C 的 EXProvisioningProfile.m 中依据嵌入二进制内的embedded.mobileprovision内容逐步判断无 provisioning profile模拟器返回SIMULATOR真机返回APP_STOREprofile 解析失败返回UNKNOWNProvisionsAllDevices为 true企业分发 →ENTERPRISE存在ProvisionedDevices包含 UDID 列表再按Entitlements.get-task-allow区分为 true 是DEVELOPMENT开发否则是AD_HOC其余情况APP_STORE。该枚举在原生侧EXProvisioningProfile.h与 JS 侧保持同步定义方便做灰度或调试态逻辑分流。4.7 getIosPushNotificationServiceEnvironmentAsync —— APNs 环境仅 iOSconst apnsEnv await Application.getIosPushNotificationServiceEnvironmentAsync(); // development | production | null返回类型PushNotificationServiceEnvironment取值为development、production或null见 src/Application.types.ts。它映射到原生 target 注册的 entitlements 中的aps-environment键底层直接读取 provisioning profile 的Entitlements字典见 EXProvisioningProfile.m。在模拟器上运行会返回null因为模拟器不支持向 APNs 注册也没有对应的 entitlements该信息可用于确认推送通知当前走的是沙箱环境还是生产环境辅助排查推送配置问题。五、平台差异速查表APIAndroidiOSWebnativeApplicationVersion✅versionName✅CFBundleShortVersionStringnullnativeBuildVersion✅versionCode✅CFBundleVersionnullapplicationName✅loadLabel✅CFBundleDisplayNamenullapplicationId✅packageName✅CFBundleIdentifiernullgetInstallationTimeAsync✅firstInstallTime✅ Documents 目录创建时间nullgetLastUpdateTimeAsync✅lastUpdateTime❌ 抛 UnavailabilityError❌getAndroidId✅ANDROID_ID❌ 抛 UnavailabilityError❌getInstallReferrerAsync✅ Install Referrer API❌❌getIosIdForVendorAsync❌✅ IDFV❌getIosApplicationReleaseTypeAsync❌✅ 解析 mobileprovision❌getIosPushNotificationServiceEnvironmentAsync❌✅aps-environment❌整体模式是双端共用的基础元数据 各平台独占的设备标识/发布渠道能力。非目标平台调用时JS 层统一通过UnavailabilityError来自expo包抛出明确错误见 Application.ts 中各函数的平台守卫。六、原生调用链与模块结构一览从模块结构看expo-application的调用链清晰分层JS 统一 API 层src/Application.ts 负责导出常量与函数、做平台守卫、把原生返回值包装为Date并 re-export 类型原生桥接层requireNativeModule(ExpoApplication)获取原生模块见 src/ExpoApplication.ts平台实现层Android 的 ApplicationModule.ktModuleDefinition中注册名为ExpoApplication的常量与 AsyncFunction、iOS 的 ApplicationModule.swiftWeb 降级层src/ExpoApplication.web.ts 将所有属性置为null、异步方法返回null保证 Web 端不崩溃。这一分层也符合 Expo Modules 的通用架构约定参考仓库内 Expo Module Infrastructure 文档即可进一步了解模块编写规范。七、版本信息与维护当前仓库中expo-application版本为57.0.2见 package.jsonMIT 协议开源。近期版本迭代要点见 CHANGELOG.md57.0.22026-07iOS 侧新增暴露 embedded provisioning profile 的expirationDate57.0.1 / 57.0.0 / 56.x 系列无用户可见变更主要为版本同步与内部维护。八、最佳实践建议Web 端判空四个同步常量在 Web 上为null做版本展示或判断前先判空平台 API 错误兜底getInstallReferrerAsync、getAndroidId等在受限环境无 Play Store、模拟器会抛错务必 try/catchIDFV 不可依赖getIosIdForVendorAsync可能返回null且厂商 App 全卸载后会变化不适合作为永久设备指纹版本语义区分对外展示用nativeApplicationVersion二进制唯一性判断用nativeBuildVersion发布渠道判定iOS 灰度/测试包识别优先使用getIosApplicationReleaseTypeAsync配合ApplicationReleaseType枚举分流无需自维护构建标记。结语expo-application虽然 API 数量不多但覆盖了应用元数据、安装信息、设备标识与发布渠道四大类运行时信息三端行为语义清晰、实现可读性高。结合本文给出的平台差异与底层源码解读你可以在版本判断、渠道归因、灰度与合规统计等场景中放心使用它。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考