Skip to main content
Glama
third-party-library.md11.6 kB
--- title: Wrap third-party native libraries description: Learn how to create a simple wrapper around two separate native libraries using Expo Modules API. hasVideoLink: true --- Expo modules make it possible to easily use native, external libraries built for Android and iOS in React Native projects. This tutorial focuses on utilizing the Expo Modules API to create radial charts using two similar libraries accessible on both native platforms. - [MPAndroidChart by PhilJay](https://github.com/PhilJay/MPAndroidChart) - [Charts by Daniel Cohen Gindi](https://github.com/danielgindi/Charts) The iOS library is inspired by the Android library, so they both have similar API and functionality. This makes them a good example for this tutorial. --- ## Create a new module The following steps assume that the new module is created inside a new Expo project. However, you can create a new module inside an existing project by following the alternative instructions. ### Start with a new project Create a new empty Expo module that can be published on npm and utilized in any Expo app by running the following command: > **info** **Tip**: If you aren't going to ship this library, press <kbd>return</kbd> for all the prompts to accept the default values in the terminal window. Now, open the newly created `expo-radial-chart` directory to start editing the native code. ### Start with an existing project Alternatively, you can use the new module as a view inside the existing project. Run the following command in your project's directory: Now, open the newly created `modules/expo-radial-chart` directory to start editing the native code. ## Run the example project To verify that everything is functioning correctly, let's run the example project. In a terminal window, start the TypeScript compiler to watch for changes and rebuild the module JavaScript: In another terminal window, compile and run the example app: ## Add native dependencies Add the native dependencies to the module by editing the **android/build.gradle** and **ios/ExpoRadialChart.podspec** files: ```diff android/build.gradle dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' } ``` ```diff ios/ExpoRadialChart.podspec s.static_framework = true s.dependency 'ExpoModulesCore' + s.dependency 'DGCharts', '~> 5.1.0' # Swift/Objective-C compatibility ``` <Collapsible summary={<>Are you trying to use a <CODE>.aar</CODE> dependency?</>}> <Tabs> <Tab label="SDK 52 and above"> Inside the **android** directory, create another directory called **libs** and place the **.aar** file inside it. Then, add the file as a Gradle project from autolinking: ```diff expo-module.config.json "android": { + "gradleAarProjects": [ + { + "name": "test-aar", + "aarFilePath": "android/libs/test.aar" + } + ], "modules": [ ``` Finally, add the dependency to the `dependencies` list in the **android/build.gradle** file, using the dependency's specified name with `${project.name}$` prefix: ```diff android/build.gradle dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" + implementation project(":${project.name}\$test-aar") } ``` </Tab> <Tab label="SDK 51 and below"> Inside the **android** directory, create another directory called **libs** and place the **.aar** file inside it. Then, add the directory as a repository: ```diff android/build.gradle repositories { mavenCentral() + flatDir { + dirs 'libs' + } } ``` Finally, add the dependency to the `dependencies` list. Instead of the filename, use the package path, which includes the `@aar` at the end: ```diff android/build.gradle dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" + implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0@aar' } ``` </Tab> </Tabs> </Collapsible> <Collapsible summary={<>Are you trying to use an <CODE>.xcframework</CODE> or <CODE>.framework</CODE> dependency?</>}> On iOS, you can also use dependencies bundled as a framework by using the `vendored_frameworks` config option. ```diff ios/ExpoRadialChart.podspec s.static_framework = true s.dependency 'ExpoModulesCore' + s.vendored_frameworks = 'Frameworks/MyFramework.framework' # Swift/Objective-C compatibility ``` > **info** **Note**: The file pattern used to specify the path to the framework is relative to the podspec file, > and doesn't support traversing the parent directory (`..`), meaning you need to place the framework inside the **ios** directory > (or a subdirectory of **ios**). Once the framework is added, make sure that the `source_files` option file pattern doesn't match any files inside the framework. One way to achieve this is to move your iOS source Swift files (that is `ExpoRadialChartView.swift` and `ExpoRadialChartModule.swift`) into a **src** directory separate from where you placed your framework(s) and update the `source_files` option to only match the **src** directory: ```diff ios/ExpoRadialChart.podspec - s.source_files = '**/*.{h,m,mm,swift,hpp,cpp}' + s.source_files = 'src/**/*.{h,m,mm,swift,hpp,cpp}' ``` Your **ios** directory should end up with a file structure similar to this: </Collapsible> ## Define an API To use the module in the app, define the types for the props. It accepts a list of series &mdash; each with a color and a percentage value. ```ts src/ExpoRadialChart.types.ts value: string; }; type Series = { color: string; percentage: number; }; style?: ViewStyle; data: Series[]; }; ``` Since the module isn't implemented for web in this example, let's replace the **src/ExpoRadialChartView.web.tsx** file: ```tsx src/ExpoRadialChartView.web.tsx return <div>Not implemented</div>; } ``` ## Implement the module on Android Now you can implement the native functionality by editing the placeholder files with the following changes: 1. Create a `PieChart` instance and set its `layoutParams` to match the parent view. Then, add it to the view hierarchy using the `addView` function. 2. Define a `setChartData` function that accepts a list of `Series` objects. You can iterate over the list, create a `PieEntry` for each series and store the colors in a separate list. 3. Create a `PieDataSet`, use it to create a `PieData` object, and set it as data on the `PieChart` instance. ```kotlin android/src/main/java/expo/modules/radialchart/ExpoRadialChartView.kt 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(); } } ``` You also need to use the [`Prop`](/modules/module-api/#prop) function to define the `data` prop and call the native `setChartData` function when the prop changes: ```kotlin android/src/main/java/expo/modules/radialchart/ExpoRadialChartModule.kt 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); } } } } ``` ## Implement the module on iOS Now you can implement the native functionality by editing the placeholder files with the following changes: 1. Create a new `PieChartView` instance and use the `addSubview` function to add it to the view hierarchy. 2. Set the `clipsToBounds` property and override the `layoutSubviews` function to make sure the chart view is always the same size as the parent view. 3. Create a `setChartData` function that accepts a list of series, creates a `PieChartDataSet` instance with the data, and assigns it to the `data` property of the `PieChartView` instance. ```swift ios/ExpoRadialChartView.swift 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 } } ``` You also need to use the [`Prop`](/modules/module-api/#prop) function to define the `data` prop and call the native `setChartData` function when the prop changes: ```swift ios/ExpoRadialChartModule.swift 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) } } } } ``` ## Write an example app to use the module You can update the app inside the **example** directory to test the module. Use the `ExpoRadialChartView` component to render a pie chart with three slices: ```tsx example/App.tsx return ( ); } const styles = StyleSheet.create({ container: { flex: 1, }, }); ``` > **info** **Tip**: If you created the module inside an existing app, make sure to import it directly from your **modules** directory by using a relative import: `import { ExpoRadialChartView } from '../modules/expo-radial-chart';` ## Rebuild and launch your application To make sure your app builds successfully on both platforms, rerun the build commands from step 2. After the app is successfully built on any of the platform you'll see a pie chart with three slices: Congratulations! You have created your first simple wrapper around two separate third-party native libraries using Expo Modules API. ## Next step

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server