Skip to content

Commit

Permalink
feat: add Expo plugin props (#589)
Browse files Browse the repository at this point in the history
  • Loading branch information
KiwiKilian authored Jan 10, 2025
1 parent 7159ba1 commit 51fbb00
Show file tree
Hide file tree
Showing 21 changed files with 679 additions and 69 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ diverged, it has become necessary to separate the projects into specific wrapper
- Installation
- [Expo](/docs/guides/setup/Expo.md)
- [React Native](/docs/guides/setup/React-Native.md)
- [Customization](/docs/guides/setup/Customization.md)
- Migrations
- [Migrating to v10](/docs/guides/migrations/v10.md)

Expand Down
22 changes: 11 additions & 11 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,24 @@ dependencies {
implementation "com.facebook.react:react-native:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

// MapLibre SDK
implementation "org.maplibre.gl:android-sdk:11.7.1"
implementation "org.maplibre.gl:android-sdk-turf:6.0.1"
// MapLibre Native
implementation "org.maplibre.gl:android-sdk:${getConfigurableExtOrDefault('nativeVersion')}"

// MapLibre Plugins
implementation "org.maplibre.gl:android-plugin-localization-v9:${getConfigurableExtOrDefault('pluginVersion')}"
implementation "org.maplibre.gl:android-plugin-annotation-v9:${getConfigurableExtOrDefault('pluginVersion')}"
implementation "org.maplibre.gl:android-plugin-markerview-v9:${getConfigurableExtOrDefault('pluginVersion')}"

// Dependencies
implementation "org.maplibre.gl:android-sdk-turf:${getConfigurableExtOrDefault('turfVersion')}"
implementation "com.squareup.okhttp3:okhttp:${getConfigurableExtOrDefault('okhttpVersion')}"
implementation "com.squareup.okhttp3:okhttp-urlconnection:${getConfigurableExtOrDefault('okhttpVersion')}"
implementation "androidx.vectordrawable:vectordrawable:1.1.0"
implementation "androidx.annotation:annotation:1.7.0"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "com.squareup.okhttp3:okhttp:${getConfigurableExtOrDefault('okhttpVersion')}"
implementation "com.squareup.okhttp3:okhttp-urlconnection:${getConfigurableExtOrDefault('okhttpVersion')}"

// MapLibre Plugins
implementation ("org.maplibre.gl:android-plugin-localization-v9:3.0.1")
implementation ("org.maplibre.gl:android-plugin-annotation-v9:3.0.1")
implementation ("org.maplibre.gl:android-plugin-markerview-v9:3.0.1")

// Dependencies for Google Location Engine
if (getConfigurableExtOrDefault("locationEngine") == "google") {
implementation "com.google.android.gms:play-services-location:21.3.0"
implementation "com.google.android.gms:play-services-location:${getConfigurableExtOrDefault('googlePlayServicesLocationVersion')}"
}
}
9 changes: 6 additions & 3 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ org.maplibre.reactnative.targetSdkVersion=31
org.maplibre.reactnative.compileSdkVersion=31
org.maplibre.reactnative.ndkVersion=21.4.7075529

# MapLibre React Native Customizations

# MapLibre React Native
org.maplibre.reactnative.nativeVersion=11.7.1
org.maplibre.reactnative.pluginVersion=3.0.1
org.maplibre.reactnative.turfVersion=6.0.1
org.maplibre.reactnative.okhttpVersion=4.9.0

# Available values: default, google
org.maplibre.reactnative.locationEngine=default
# Only applied if locationEngine=google
org.maplibre.reactnative.googlePlayServicesLocationVersion=21.3.0
101 changes: 101 additions & 0 deletions docs/guides/setup/Customization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Setup Customization

It's possible to customize the native setup of the library. These props must be applied differently, based on
the project setup.

## Expo

When using Expo, simply add the customizations in the projects `app.json` or `app.config.{js,ts}`. Here is an
example customization for in a `app.config.ts`:

```ts
import type { MapLibrePluginProps } from "@maplibre/maplibre-react-native";

export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
plugins: [
[
"@maplibre/maplibre-react-native",
{
android: {
nativeVersion: "x.x.x",
},
ios: {
nativeVersion: "x.x.x",
},
} as MapLibrePluginProps,
],
],
});
```

## React Native

When using React Native, the customizations have to be applied differently for each platform.

On Android they are set in the `gradle.properties`, each of them prefixed with `org.maplibre.reactnative`. Example:

```diff
+ org.maplibre.reactnative.nativeVersion=x.x.x
```

On iOS global variables in the `Podfile` are used, prefixed with `$MLRN`.

```diff
+ $MLRN_NATIVE_VERSION="x.x.x"

target "AppName" do
```

## Available Customizations

### Android

| Prop Key | Type | Description |
| ----------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| `nativeVersion` | `VersionString` | Version for [`org.maplibre.gl:android-sdk`](https://mvnrepository.com/artifact/org.maplibre.gl/android-sdk) |
| `pluginVersion` | `VersionString` | Version for `org.maplibre.gl:android-plugin-*-v9` |
| `turfVersion` | `VersionString` | Version for `org.maplibre.gl:android-sdk-turf` |
| `okhttpVersion` | `VersionString` | Version for `com.squareup.okhttp3:okhttp` |
| `locationEngine` | `"default" \| "google"` | [Location engine to be used](#location-engine) |
| `googlePlayServicesLocationVersion` | `VersionString` | Version for `com.google.android.gms:play-services-location`, only used with `locationEngine: "google"` |

For default values see [`gradle.properties` of the library](/android/gradle.properties).

#### Location Engine

Two location engines are available on Android:

- `default`
- Default location engine provided by the device
- Doesn't work with emulator
- F-Droid compatible
- `google`
- Google Play Services Location Engine
- Possibly more accurate
- Works with emulator
- Not F-Droid compatible

### iOS

| Prop Key | `Podfile` Global Variable | Type | Description |
| --------------- | ------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------- |
| `nativeVersion` | `$MLRN_NATIVE_VERSION` | `VersionString` | Version for [`maplibre-gl-native-distribution`](https://github.com/maplibre/maplibre-gl-native-distribution/releases) |
| `spmSpec` | `$MLRN_SPM_SPEC` | `string` | [Swift Package Manager Spec](#spm-spec) |

For default values see [`maplibre-react-native.podspec` of the library](/maplibre-react-native.podspec).

#### SPM Spec

Setting a Swift Package Manager Spec allows further customization over setting the native version:

```rb
$MLRN_SPM_SPEC = {
url: "https://github.com/maplibre/maplibre-gl-native-distribution",
requirement: {
kind: "upToNextMajorVersion",
minimumVersion: "x.x.x"
},
product_name: "MapLibre"
}
```
16 changes: 10 additions & 6 deletions docs/guides/setup/Expo.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ After installing the package, add the [config plugin](https://docs.expo.io/guide
```json
{
"expo": {
"plugins": ["@maplibre/maplibre-react-native"]
"plugins": [
"@maplibre/maplibre-react-native"
]
}
}
```

Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/)
guide.
Next, rebuild your app as described in the ["Add custom native code"](https://docs.expo.io/workflow/customizing/) guide.

## Plugin Properties
The plugin is required to properly install MapLibre Native on iOS, where it adds `$MLRN.post_install(installer)` to the
`post_install` block in the `ios/Podfile`. On Android it only serves customizations.

This plugin doesn't currently provide any additional properties for customization. The plugin simply generates the
post-install block in the `ios/Podfile`. No additional changes are done on Android.
## Plugin Props

The plugin allows to customize the setup of MapLibre React Native through plugin props. Find out more in
the [customization guide](/docs/guides/setup/Customization.md).
18 changes: 4 additions & 14 deletions docs/guides/setup/React-Native.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,7 @@ pod install

Now rebuild your app.

### Installing a specific version

If you want to modify the MapLibre Native iOS version, you can override as follows in your `Podfile`:

```rb
$MLRN_SPM_Spec = {
url: "https://github.com/maplibre/maplibre-gl-native-distribution",
requirement: {
kind: "upToNextMajorVersion",
minimumVersion: "<Set your version here>"
},
product_name: "MapLibre"
}
```
## Customzations

You can customize the setup of MapLibre React Native through `gradle.properties` on Android or global variables in the
`Podfile` on iOS. Find out more in the [customization guide](/docs/guides/setup/Customization.md).
29 changes: 15 additions & 14 deletions maplibre-react-native.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ require 'json'

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))

# Global Variable Defaults
$MLRN_NATIVE_VERSION ||= "6.9.0"
$MLRN_SPM_SPEC ||= {
url: "https://github.com/maplibre/maplibre-gl-native-distribution",
requirement: {
kind: "exactVersion",
version: $MLRN_NATIVE_VERSION
},
product_name: "MapLibre"
}

$MLRN = Object.new

def $MLRN._add_spm_to_target(project, target, url, requirement, product_name)
Expand All @@ -24,18 +35,8 @@ def $MLRN._add_spm_to_target(project, target, url, requirement, product_name)
end

def $MLRN.post_install(installer)
spm_spec = {
url: "https://github.com/maplibre/maplibre-gl-native-distribution",
requirement: {
kind: "exactVersion",
version: "6.9.0"
},
product_name: "MapLibre"
}
spm_spec = $MLRN_SPM_SPEC

if $MLRN_SPM_Spec.is_a?(Hash)
spm_spec = $MLRN_SPM_Spec
end
project = installer.pods_project
self._add_spm_to_target(
project,
Expand All @@ -61,9 +62,9 @@ def $MLRN.post_install(installer)
end

Pod::Spec.new do |s|
s.name = "maplibre-react-native"
s.summary = "React Native library for creating maps with MapLibre Native"
s.version = package['version']
s.name = "maplibre-react-native"
s.summary = "React Native library for creating maps with MapLibre Native"
s.version = package['version']
s.authors = { "MapLibre" => "" }
s.homepage = "https://github.com/maplibre/maplibre-react-native"
s.source = { :git => "https://github.com/maplibre/maplibre-react-native.git" }
Expand Down
12 changes: 11 additions & 1 deletion packages/expo-app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import "ts-node/register";
import { type ExpoConfig, type ConfigContext } from "expo/config";

import type { MapLibrePluginProps } from "../../src";

export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: "Expo App",
Expand Down Expand Up @@ -33,5 +35,13 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
backgroundColor: "#285daa",
translucent: false,
},
plugins: ["../../src/plugin/withMapLibre.ts"],
plugins: [
[
"../../src/plugin/withMapLibre.ts",
{
android: {},
ios: {},
} as MapLibrePluginProps,
],
],
});
6 changes: 3 additions & 3 deletions scripts/utils/getNativeVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ let cachedIosVersion: string;
export const getAndroidVersion = async () => {
if (!cachedAndroidVersion) {
cachedAndroidVersion = await getNativeVersion(
["android", "build.gradle"],
/^\s+implementation\s+"org.maplibre.gl:android-sdk:(\d+\.\d+\.\d+)"$/,
["android", "gradle.properties"],
/^org\.maplibre\.reactnative\.nativeVersion=(\d+\.\d+\.\d+)$/,
);
}

Expand All @@ -32,7 +32,7 @@ export const getIosVersion = async () => {
if (!cachedIosVersion) {
cachedIosVersion = await getNativeVersion(
["maplibre-react-native.podspec"],
/^\s+version:\s*"(\d+\.\d+\.\d+)"$/,
/^\$MLRN_NATIVE_VERSION \|\|= "(\d+\.\d+\.\d+)"$/,
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/MapLibreRN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,5 @@ export type {
BackgroundLayerStyle,
LightLayerStyle,
} from "./types/MapLibreRNStyles";

export type { MapLibrePluginProps } from "./plugin/MapLibrePluginProps";
41 changes: 41 additions & 0 deletions src/__tests__/plugin/android/getGradleProperties.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getGradleProperties } from "../../../plugin/android";

describe("Expo Plugin Android – getGradleProperties", () => {
it("removes empty property keys", () => {
const result = getGradleProperties({
android: {
// @ts-expect-error
"": "default",
},
});

expect(result).toEqual([]);
});

it("removes empty property values", () => {
const result = getGradleProperties({
android: {
// @ts-expect-error
locationEngine: "",
},
});

expect(result).toEqual([]);
});

it("adds valid properties", () => {
const result = getGradleProperties({
android: {
locationEngine: "google",
},
});

expect(result).toEqual([
{
type: "property",
key: "org.maplibre.reactnative.locationEngine",
value: "google",
},
]);
});
});
37 changes: 37 additions & 0 deletions src/__tests__/plugin/android/mergeGradleProperties.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { mergeGradleProperties } from "../../../plugin/android";

const PROPERTY = {
type: "property",
key: "exampleProperty",
value: "value",
} as const;

const NEW_PROPERTY = {
type: "property",
key: "newProperty",
value: "new",
} as const;

describe("Expo Plugin Android – mergeGradleProperties", () => {
it("replaces duplicate property", () => {
expect(
mergeGradleProperties(
[
PROPERTY,
{
...NEW_PROPERTY,
value: "old",
},
],
[NEW_PROPERTY],
),
).toEqual([PROPERTY, NEW_PROPERTY]);
});

it("adds new property", () => {
expect(mergeGradleProperties([PROPERTY], [NEW_PROPERTY])).toEqual([
PROPERTY,
NEW_PROPERTY,
]);
});
});
Loading

0 comments on commit 51fbb00

Please sign in to comment.