包装第三方原生库
编辑页面
了解如何使用 Expo Modules API 围绕两个独立的原生库创建一个简单的包装器。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
Expo 模块使得在 React Native 项目中轻松使用为 Android 和 iOS 构建的原生外部库成为可能。本教程重点介绍如何利用 Expo Modules API,使用两个可在两个原生平台上访问的相似库创建径向图表。
iOS 库受到 Android 库的启发,因此它们都具有相似的 API 和功能。这使它们成为本教程的一个很好的示例。

在这个视频中,你将学习如何使用 Expo Modules API 包装原生库。
1
创建一个新模块
以下步骤假设新模块是在一个新的 Expo 项目中创建的。不过,你也可以按照替代说明在现有项目中创建新模块。
或者,你可以将新模块作为现有 Expo 项目目录中的一个视图来使用。在项目目录中运行以下命令:
- npx create-expo-module --local expo-radial-chart现在,打开新创建的 modules/expo-radial-chart 目录,开始编辑原生代码。
通过运行以下命令,创建一个可以发布到 npm 并在任何 Expo 应用中使用的空 Expo 模块:
- npx create-expo-module expo-radial-chart提示:如果你不打算发布这个库,请在终端窗口中对所有提示按 return 以接受默认值。
现在,打开新创建的 expo-radial-chart 目录,开始编辑原生代码。
2
运行示例项目
为了验证一切是否正常运行,让我们运行示例项目。
如果你是从现有 Expo 项目开始的,请在 Expo 项目的根目录中运行以下命令:
# 在 Android 上运行 example-expo-app- npx expo run:android# 在 iOS 上运行示例应用- npx expo run:ios如果你是从一个新的模块项目开始的,请打开一个终端窗口,启动 TypeScript 编译器以监视更改,并重新构建模块 JavaScript:
# 在运行下面的命令之前,请确保你位于 expo-radial-chart 目录中- npm run build在另一个终端窗口中,编译并运行示例应用:
- cd example-expo-app# 在 Android 上运行 example-expo-app- npx expo run:android# 在 iOS 上运行示例应用- npx expo run:ios3
添加原生依赖
通过编辑 expo-radial-chart/android/build.gradle 和 expo-radial-chart/ios/ExpoRadialChart.podspec 文件,将原生依赖添加到模块中:
你是否想使用 .aar 依赖?
在 android 目录中,再创建一个名为 libs 的目录,并将 .aar 文件放入其中。然后,通过 autolinking 将该文件作为 Gradle 项目添加:
最后,将依赖添加到 android/build.gradle 文件中的 dependencies 列表里,并使用依赖指定的名称,前面加上 ${project.name}$ 前缀:
在 android 目录中,再创建一个名为 libs 的目录,并将 .aar 文件放入其中。然后,将该目录添加为仓库:
最后,将依赖添加到 dependencies 列表中。不要使用文件名,而是使用包路径,并在末尾加上 @aar:
你是否想使用 .xcframework 或 .framework 依赖?
在 iOS 上,你也可以通过使用 vendored_frameworks 配置选项来使用以 framework 形式打包的依赖。
注意:用于指定 framework 路径的文件模式是相对于 podspec 文件的, 并且不支持遍历父目录(..),这意味着你需要将 framework 放在 ios 目录 中(或 ios 的子目录中)。
添加 framework 后,请确保 source_files 选项的文件模式不会匹配 framework 中的任何文件。实现这一点的一种方法是将 iOS 源 Swift 文件(即 ExpoRadialChartView.swift 和 ExpoRadialChartModule.swift)移动到一个与放置 framework 的位置分开的 src 目录中,并将 source_files 选项更新为只匹配 src 目录:
你的 ios 目录最终应具有类似以下的文件结构:
FrameworksMyFramework.frameworksrcExpoRadialChartView.swiftExpoRadialChartModule.swiftExpoRadialChart.podspec4
定义一个 API
为了在应用中使用该模块,请定义 props 的类型。它接受一个 series 列表——每个 series 都包含一个颜色和一个百分比值。
import { ViewStyle } from 'react-native/types'; export type ChangeEventPayload = { value: string; }; type Series = { color: string; percentage: number; }; export type ExpoRadialChartViewProps = { style?: ViewStyle; data: Series[]; };
由于本示例中该模块没有为 web 实现,我们将替换 src/ExpoRadialChartView.web.tsx 文件:
import * as React from 'react'; export default function ExpoRadialChartView() { return <div>未实现</div>; }
5
在 Android 上实现模块
现在你可以通过编辑占位文件并进行以下更改来实现原生功能:
- 创建一个
PieChart实例,并将其layoutParams设置为与父视图一致。然后,使用addView函数将其添加到视图层级中。 - 定义一个接受
Series对象列表的setChartData函数。你可以遍历该列表,为每个 series 创建一个PieEntry,并将颜色存储在一个单独的列表中。 - 创建一个
PieDataSet,使用它创建一个PieData对象,并将其设置为PieChart实例的数据。
package expo.modules.radialchart import android.content.Context import android.graphics.Color import androidx.annotation.ColorInt import com.github.mikephil.charting.charts.PieChart import com.github.mikephil.charting.data.PieData import com.github.mikephil.charting.data.PieDataSet import com.github.mikephil.charting.data.PieEntry import expo.modules.kotlin.AppContext import expo.modules.kotlin.records.Field import expo.modules.kotlin.records.Record import expo.modules.kotlin.views.ExpoView class Series : Record { @Field val color: String = "#ff0000" @Field val percentage: Float = 0.0f } class ExpoRadialChartView(context: Context, appContext: AppContext) : ExpoView(context, appContext) { internal val chartView = PieChart(context).also { it.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) addView(it) } fun setChartData(data: ArrayList<Series>) { val entries: ArrayList<PieEntry> = ArrayList() val colors: ArrayList<Int> = ArrayList() for (series in data) { entries.add(PieEntry(series.percentage)) colors.add(Color.parseColor(series.color)) } val dataSet = PieDataSet(entries, "DataSet"); dataSet.colors = colors; val pieData = PieData(dataSet); chartView.data = pieData; chartView.invalidate(); } }
你还需要使用 Prop 函数来定义 data prop,并在 prop 变化时调用原生的 setChartData 函数:
package expo.modules.radialchart import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition class ExpoRadialChartModule : Module() { override fun definition() = ModuleDefinition { Name("ExpoRadialChart") View(ExpoRadialChartView::class) { Prop("data") { view: ExpoRadialChartView, prop: ArrayList<Series> -> view.setChartData(prop); } } } }
6
在 iOS 上实现模块
现在你可以通过编辑占位文件并进行以下更改来实现原生功能:
- 创建一个新的
PieChartView实例,并使用addSubview函数将其添加到视图层级中。 - 设置
clipsToBounds属性,并重写layoutSubviews函数,以确保图表视图始终与父视图大小相同。 - 创建一个接受 series 列表的
setChartData函数,使用数据创建一个PieChartDataSet实例,并将其赋值给PieChartView实例的data属性。
import ExpoModulesCore import DGCharts struct Series: Record { @Field var color: UIColor = UIColor.black @Field var percentage: Double = 0 } class ExpoRadialChartView: ExpoView { let chartView = PieChartView() required init(appContext: AppContext? = nil) { super.init(appContext: appContext) clipsToBounds = true addSubview(chartView) } override func layoutSubviews() { chartView.frame = bounds } func setChartData(data: [Series]) { let set1 = PieChartDataSet(entries: data.map({ (series: Series) -> PieChartDataEntry in return PieChartDataEntry(value: series.percentage) })) set1.colors = data.map({ (series: Series) -> UIColor in return series.color }) let chartData: PieChartData = [set1] chartView.data = chartData } }
你还需要使用 Prop 函数来定义 data prop,并在 prop 变化时调用原生的 setChartData 函数:
import ExpoModulesCore public class ExpoRadialChartModule: Module { public func definition() -> ModuleDefinition { Name("ExpoRadialChart") View(ExpoRadialChartView.self) { Prop("data") { (view: ExpoRadialChartView, prop: [Series]) in view.setChartData(data: prop) } } } }
7
编写一个使用该模块的示例应用
你可以更新 src/app 目录中的应用来测试该模块。使用 ExpoRadialChartView 组件渲染一个包含三个扇区的饼图:
import { ExpoRadialChartView } from '@/modules/expo-radial-chart'; import { StyleSheet } from 'react-native'; export default function App() { return ( <ExpoRadialChartView style={styles.container} data={[ { color: '#ff0000', percentage: 0.5, }, { color: '#00ff00', percentage: 0.2, }, { color: '#0000ff', percentage: 0.3, }, ]} /> ); } const styles = StyleSheet.create({ container: { flex: 1, }, });
提示:如果你创建的是新模块,请确保将导入语句更新为:import { ExpoRadialChartView } from 'expo-radial-chart';
恭喜!你已经使用 Expo Modules API 创建了第一个围绕两个独立第三方原生库的简单封装。
下一步
使用 Kotlin 和 Swift 创建原生模块的参考。