
Expo Inline Modules 如何在 app 目录内直接创建原生模块与原生视图【免费下载链接】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 项目中如果你想调用一段原生代码Kotlin/Swift标准做法是用create-expo-module脚手架生成一个独立的 Expo Module 包。而 Inline Modules 提供了另一条路径直接把原生模块和原生视图的源文件写在项目的app目录里Expo 会自动发现这些文件并纳入构建不需要单独的包。本文章基于 Expo 官方文档中的教程与参考演示从配置、prebuild、编写 Kotlin/Swift 文件到在 React Native 代码中使用并完成验证的完整流程。需要注意的前提Inline modules 目前是experimental实验性状态要求Expo SDK 56 及更高版本API 存在破坏性变更的可能。配置 app.json 开启 inline modules打开项目的 app config设置expo.experiments.inlineModules.watchedDirectories为[app]{ expo: { experiments: { inlineModules: { watchedDirectories: [app] } } } }只要定义了expo.experiments.inlineModules就会在 Expo 项目中启用 inline modules 功能。watchedDirectories指定 inline module 文件可以放在哪些目录里。配置时有几条明确的限制来自 inline modules reference目录必须位于一个 TypeScript/JavaScript 项目内即目录树的某个祖先目录下存在package.json不能是整个项目目录如./也不能是其祖先目录如../不能是watchedDirectories中其他目录的子目录例如不能同时写[app, app/nested/directory]只写[app]即可不能包含 、(、)、$等特殊字符所以app/(tabs)不能直接作为条目但设置app后app/(tabs)目录下的原生文件仍会被使用。被监听目录下的嵌套目录同样生效如果watchedDirectories [app]而app/nested/directory/SomeModule.kt存在那么SomeModule就可以在你的应用中使用。可选配置iOS 上可以通过expo.experiments.inlineModules.xcodeProjectTargets指定 inline module 文件被加入哪些 Xcode target。缺省时只加入 app 的主 target。每个条目是 Xcode 工程中以及ios/Podfile的target块里出现的 target 名称即使 target 嵌套在abstract_target内也不要包含 abstract target 的名称{ expo: { experiments: { inlineModules: { xcodeProjectTargets: [MyApp, MyAppWidgets] } } } }修改 app config 后需要重新运行npx expo prebuild才会生效。运行 prebuild 生成原生工程在修改完配置后运行 prebuild 命令生成带有 inline modules 配置的android和ios原生工程npx expo prebuild其他包管理器对应yarn expo prebuild、pnpm expo prebuild、bun expo prebuild。在 app 目录内创建 inline module接下来创建第一个 inline module。命名规则inline module 的文件名必须与原生模块名一致该名字必须在你整个应用中唯一。requireNativeModule(FirstInlineModule)要能引用到模块文件名就得是FirstInlineModule.kt/FirstInlineModule.swift文件内的类名也要与文件名一致。Android在app目录内创建 Kotlin 文件FirstInlineModule.ktpackage app import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition class FirstInlineModule : Module() { override fun definition() ModuleDefinition { Constant(Hello) { - Hello Android inline modules! } } }iOS在app目录内创建 Swift 文件FirstInlineModule.swiftinternal import ExpoModulesCore class FirstInlineModule: Module { public func definition() - ModuleDefinition { Constant(Hello) { return Hello iOS inline modules! } } }在应用代码中使用 inline module在 TypeScript/JavaScript 侧通过expo包导出的requireNativeModule按模块名获取import { requireNativeModule } from expo; import { Text } from react-native; const FirstInlineModule requireNativeModule(FirstInlineModule); export default function InlineModulesDemoComponent() { return Text {FirstInlineModule.Hello} /Text; }requireNativeModule返回的是any类型没有类型安全也不提供自动补全。如果你需要生成的 TS 接口可以在项目根目录运行npx expo-type-information inline-modules-interface --app-json ./app.json --watcher流程见 type generation tutorial这一步属于可选增强不影响模块本身运行。在 app 目录内创建原生视图原生视图inline view的创建方式与 module 相同。教程以一个类似ExpoWebView的示例说明封装原生WebView/WKWebView暴露一个urlProp 和一个onLoad事件。Android在app目录创建FirstInlineView.ktpackage app import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import java.net.URL import android.content.Context import android.webkit.WebView import android.webkit.WebViewClient import expo.modules.kotlin.AppContext import expo.modules.kotlin.viewevent.EventDispatcher import expo.modules.kotlin.views.ExpoView class FirstInlineView : Module() { override fun definition() ModuleDefinition { View(ExpoWebView::class) { Events(onLoad) Prop(url) { view: ExpoWebView, url: URL? - view.webView.loadUrl(url.toString()) } } } } class ExpoWebView(context: Context, appContext: AppContext) : ExpoView(context, appContext) { private val onLoad by EventDispatcher() internal val webView WebView(context).also { it.layoutParams LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT ) it.webViewClient object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { onLoad(mapOf(url to url)) } } addView(it) } }iOS在app目录创建FirstInlineView.swiftinternal import ExpoModulesCore import WebKit class FirstInlineView: Module { public func definition() - ModuleDefinition { View(ExpoWebView.self) { Events(onLoad) Prop(url) { (view, url: URL) in if view.webView.url ! url { let urlRequest URLRequest(url: url) view.webView.load(urlRequest) } } } } } class ExpoWebView: ExpoView, WKNavigationDelegate { let webView WKWebView() let onLoad EventDispatcher() required init(appContext: AppContext? nil) { super.init(appContext: appContext) clipsToBounds true webView.navigationDelegate self addSubview(webView) } override func layoutSubviews() { webView.frame bounds } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { if let url webView.url { onLoad([ url: url.absoluteString ]) } } }在 React 侧用requireNativeView按视图名获取视图的 Prop 和事件以 React 属性的形式传入import { requireNativeModule, requireNativeView } from expo; import { StyleSheet, Text, View } from react-native; const FirstInlineModule requireNativeModule(FirstInlineModule); const FirstInlineView requireNativeView(FirstInlineView); export default function InlineModulesDemoComponent() { return ( View style{styles.textBox} Text style{styles.text} {FirstInlineModule.Hello} /Text /View FirstInlineView style{styles.inlineView} urlhttps://docs.expo.dev/modules/ / / ); } const styles StyleSheet.create({ textBox: { height: 100, justifyContent: flex-end, alignItems: center }, text: { fontSize: 26 }, inlineView: { flex: 1 }, });url属性按你的实际页面地址替换示例中的地址来自文档示例。编译运行与结果验证分别编译运行到 Android 或 iOS# Run the example app on Android npx expo run:android # Run the example app on iOS npx expo run:ios运行后的预期结果来自文档描述应用界面上会显示来自原生 Android/iOS 模块的文本常量即Hello内容分别为 Hello Android inline modules! 或 Hello iOS inline modules!文档示例值以及一个来自 inline 原生视图的 web view加载urlProp 指定的页面页面加载完成时会触发onLoad事件并携带url字段。限制与注意事项Inline modules 是实验性功能仅限 Expo SDK 56API 可能发生破坏性变更评估是否用于生产前建议先阅读 release statuses 中对 experimental 状态的说明每次修改 app config 中的inlineModules配置后都要重新执行npx expo prebuild文件名、类名与requireNativeModule/requireNativeView中的模块名三者必须一致否则无法被正确引用。完成上述流程后你的项目里就是一个可运行的最小 inline module inline view 结构app/FirstInlineModule.kt、app/FirstInlineModule.swift、app/FirstInlineView.kt、app/FirstInlineView.swift加上一处requireNativeModule/requireNativeView调用。更多 API 细节可继续查阅 inline modules reference需要 TypeScript 接口的读者可接着看 type generation tutorial。【免费下载链接】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),仅供参考