Skip to content

Commit 4881349

Browse files
wf9a5m75claude
andcommitted
feat: add ArcGIS provider to reactnative-basic example and refactor provider views
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fc0a682 commit 4881349

27 files changed

Lines changed: 631 additions & 355 deletions

examples/reactnative-basic/App.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import {
1212
View,
1313
} from 'react-native';
1414
import { MapScreen } from 'src/screens/MapScreen';
15-
16-
type MapProvider = 'google-maps' | 'maplibre' | 'here';
15+
import type { MapProvider } from 'src/providers/types';
1716

1817
export interface SamplePageDefinition {
1918
id: string;
@@ -67,7 +66,9 @@ function Header({
6766
? 'GoogleMapView'
6867
: provider === 'here'
6968
? 'HereMapView'
70-
: 'MapLibreMapView';
69+
: provider === 'arcgis'
70+
? 'ArcGISMapView'
71+
: 'MapLibreMapView';
7172

7273
const selectProvider = (nextProvider: MapProvider) => {
7374
onProviderChange(nextProvider);
@@ -161,6 +162,20 @@ function Header({
161162
HereMapView
162163
</Text>
163164
</TouchableOpacity>
165+
<TouchableOpacity
166+
style={[styles.providerMenuItem, provider === 'arcgis' && styles.providerMenuItemActive]}
167+
activeOpacity={0.75}
168+
onPress={() => selectProvider('arcgis')}
169+
>
170+
<Text
171+
style={[
172+
styles.providerMenuItemText,
173+
provider === 'arcgis' && styles.providerMenuItemTextActive,
174+
]}
175+
>
176+
ArcGISMapView
177+
</Text>
178+
</TouchableOpacity>
164179
</View>
165180
</View>
166181
</Modal>

examples/reactnative-basic/android/app/build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,14 @@ android {
9797

9898
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
9999

100-
// Set directly here (rather than relying solely on reactnative-for-here's own
101-
// rootProject.subprojects manifestPlaceholders hook) for reliability during local testing.
100+
// Set directly here (rather than relying solely on reactnative-for-here's/
101+
// reactnative-for-arcgis's own rootProject.subprojects manifestPlaceholders hooks) for
102+
// reliability during local testing.
102103
def localProps = new Properties()
103104
file("${rootDir}/local.properties").withInputStream { localProps.load(it) }
104105
manifestPlaceholders["hereAccessKeyId"] = localProps.getProperty("HERE_ACCESS_KEY_ID", "")
105106
manifestPlaceholders["hereAccessKeySecret"] = localProps.getProperty("HERE_ACCESS_KEY_SECRET", "")
107+
manifestPlaceholders["arcgisApiKey"] = localProps.getProperty("ARCGIS_API_KEY", "")
106108
}
107109
signingConfigs {
108110
debug {

examples/reactnative-basic/android/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ allprojects {
1818
google()
1919
mavenCentral()
2020
maven { url 'https://www.jitpack.io' }
21+
// com.mapconductor:for-arcgis's POM depends on com.esri:arcgis-maps-kotlin-toolkit-bom,
22+
// published only here - reactnative-for-arcgis/android/build.gradle declares this repo too,
23+
// but the :app project's own dependency resolution needs it listed at this (root) level.
24+
maven { url 'https://esri.jfrog.io/artifactory/arcgis' }
2125
}
2226
}
2327

examples/reactnative-basic/android/gradle.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
# Specifies the JVM arguments used for the daemon process.
1111
# The setting is particularly useful for tweaking memory settings.
1212
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13-
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
13+
# Bumped from 2048m: packaging debug APKs with reactnative-for-arcgis's ArcGIS Maps SDK for
14+
# Kotlin (large native .so libraries) runs the packaging worker out of heap at the default size.
15+
org.gradle.jvmargs=-Xmx6144m -XX:MaxMetaspaceSize=1024m
1416

1517
# When configured, Gradle will run in incubating parallel mode.
1618
# This option should only be used with decoupled projects. More details, visit

examples/reactnative-basic/ios/Podfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ target 'MapConductorBasic' do
5151
# only covers npm packages, so these path pods must be declared explicitly.
5252
pod 'MapConductorCore', :path => '../../../../ios-sdk/ios-sdk-core'
5353
pod 'MapConductorForGoogleMaps', :path => '../../../../ios-sdk/ios-for-googlemaps'
54+
# MapConductorForHERE is also a path pod for the same reason - it additionally vendors the
55+
# proprietary heresdk.xcframework itself (see MapConductorForHERE.podspec), since HERE has no
56+
# public pod to depend on.
57+
pod 'MapConductorForHERE', :path => '../../../../ios-sdk/ios-for-here'
58+
# MapConductorForArcGIS is also a path pod for the same reason - it additionally vendors
59+
# Esri's ArcGIS.xcframework/CoreArcGIS.xcframework itself (see MapConductorForArcGIS.podspec),
60+
# since Esri only distributes this SDK via Swift Package Manager (no public CocoaPods spec).
61+
pod 'MapConductorForArcGIS', :path => '../../../../ios-sdk/ios-for-arcgis'
62+
pod 'MapConductorMarkerCluster', :path => '../../../../ios-sdk/ios-marker-cluster'
63+
pod 'MapConductorForMapLibre', :path => '../../../../ios-sdk/ios-for-maplibre'
64+
pod 'MapConductorHeatmap', :path => '../../../../ios-sdk/ios-heatmap'
65+
pod 'MapConductorGeoJSON', :path => '../../../../ios-sdk/ios-geojson-layer'
5466

5567
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
5668
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']

examples/reactnative-basic/ios/Podfile.properties.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"ios.deploymentTarget": "17.0",
23
"expo.jsEngine": "hermes",
34
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
45
"expo.inlineModules.watchedDirectories": "[]",

examples/reactnative-basic/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@mapconductor/reactnative-for-googlemaps": "*",
1717
"@mapconductor/reactnative-for-maplibre": "*",
1818
"@mapconductor/reactnative-for-here": "*",
19+
"@mapconductor/reactnative-for-arcgis": "*",
1920
"@mapconductor/react-geojson-layer": "*",
2021
"@mapconductor/react-heatmap": "*",
2122
"@mapconductor/react-marker-clustering": "*",
Lines changed: 23 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,28 @@
1-
import type {
2-
MapDesignTypeInterface,
3-
MapViewStateInterface,
4-
MarkerTilingOptions,
5-
} from '@mapconductor/js-sdk-core';
6-
import type { MapViewBaseProps } from '@mapconductor/js-sdk-react/native';
7-
import {
8-
GoogleMapView,
9-
GoogleMapViewState,
10-
} from '@mapconductor/reactnative-for-googlemaps';
11-
import {
12-
MapLibreMapView,
13-
MapLibreViewState,
14-
} from '@mapconductor/reactnative-for-maplibre';
15-
import {
16-
HereMapView,
17-
HereViewState,
18-
} from '@mapconductor/reactnative-for-here';
1+
import React from 'react';
2+
import type { ProviderDesignOverrides, ProviderViewProps, MapProvider } from '../providers/types';
3+
import { MapLibreProviderView } from '../providers/MapLibreProviderView';
4+
import { GoogleMapsProviderView } from '../providers/GoogleMapsProviderView';
5+
import { HereProviderView } from '../providers/HereProviderView';
6+
import { ArcGISProviderView } from '../providers/ArcGISProviderView';
197

20-
type CommonMapViewState = MapViewStateInterface<MapDesignTypeInterface<unknown>>;
21-
type MapViewContainerProps = MapViewBaseProps<CommonMapViewState> & {
22-
markerTilingOptions?: MarkerTilingOptions;
23-
};
8+
export type { MapProvider, ProviderDesignOverrides };
249

25-
export function MapViewContainer({
26-
state,
27-
children,
28-
...props
29-
}: MapViewContainerProps) {
30-
if (state instanceof GoogleMapViewState) {
31-
return (
32-
<GoogleMapView state={state} {...props}>
33-
{children}
34-
</GoogleMapView>
35-
);
36-
}
37-
38-
if (state instanceof MapLibreViewState) {
39-
return (
40-
<MapLibreMapView state={state} {...props}>
41-
{children}
42-
</MapLibreMapView>
43-
);
44-
}
10+
interface MapViewContainerProps extends ProviderViewProps {
11+
provider: MapProvider;
12+
designTypes?: ProviderDesignOverrides;
13+
}
4514

46-
if (state instanceof HereViewState) {
47-
// accessKeyId/accessKeySecret aren't passed here: on Android, HereMapViewControllerStore
48-
// reads HERE_ACCESS_KEY_ID/HERE_ACCESS_KEY_SECRET from AndroidManifest.xml meta-data instead
49-
// (see reactnative-for-here/android/build.gradle's manifestPlaceholders injection). iOS has
50-
// no manifest equivalent and would need these two props supplied here.
51-
return (
52-
<HereMapView state={state} {...props}>
53-
{children}
54-
</HereMapView>
55-
);
15+
export function MapViewContainer({ provider, designTypes, ...rest }: MapViewContainerProps) {
16+
switch (provider) {
17+
case 'maplibre':
18+
return <MapLibreProviderView mapDesignType={designTypes?.maplibre} {...rest} />;
19+
case 'google-maps':
20+
return <GoogleMapsProviderView mapDesignType={designTypes?.['google-maps']} {...rest} />;
21+
case 'here':
22+
return <HereProviderView mapDesignType={designTypes?.here} {...rest} />;
23+
case 'arcgis':
24+
return <ArcGISProviderView mapDesignType={designTypes?.arcgis} {...rest} />;
25+
default:
26+
return null;
5627
}
57-
58-
throw new Error('No container is available for specified provider');
5928
}

examples/reactnative-basic/src/pages/heatmaplayer/HeatmapLayerPage.tsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,17 @@ import {
77
} from 'react-native';
88

99
import { GeoPoint, MapCameraPosition } from '@mapconductor/js-sdk-core';
10-
import {
11-
GoogleMapDesign,
12-
useGoogleMapViewState,
13-
} from '@mapconductor/reactnative-for-googlemaps';
14-
import {
15-
MapLibreDesign,
16-
useMapLibreViewState,
17-
} from '@mapconductor/reactnative-for-maplibre';
10+
import { GoogleMapDesign } from '@mapconductor/reactnative-for-googlemaps';
11+
import { MapLibreDesign } from '@mapconductor/reactnative-for-maplibre';
1812
import {
1913
HeatmapOverlay,
2014
HeatmapPointState,
2115
} from '@mapconductor/react-heatmap';
2216

2317
import postOfficesJson from '../../data/postoffice/postoffices.json';
2418
import { MapViewContainer } from '../MapViewContainer';
19+
import type { MapProvider } from '../../providers/types';
2520

26-
type MapProvider = 'maplibre' | 'google-maps' | 'here';
2721
type PostOfficeRow = [number, number, string, string];
2822

2923
const POST_OFFICES = postOfficesJson as PostOfficeRow[];
@@ -37,16 +31,6 @@ const INIT_CAMERA = MapCameraPosition.from({
3731

3832
export function HeatmapLayerPage({ provider }: { provider: MapProvider }) {
3933
const [mapReady, setMapReady] = useState(false);
40-
const mapLibreState = useMapLibreViewState({
41-
id: 'heatmap-layer-maplibre',
42-
mapDesignType: MapLibreDesign.MapTilerTonerEn,
43-
cameraPosition: INIT_CAMERA,
44-
});
45-
const googleState = useGoogleMapViewState({
46-
id: 'heatmap-layer-google',
47-
mapDesignType: GoogleMapDesign.Hybrid,
48-
cameraPosition: INIT_CAMERA,
49-
});
5034

5135
useEffect(() => {
5236
setMapReady(false);
@@ -65,12 +49,17 @@ export function HeatmapLayerPage({ provider }: { provider: MapProvider }) {
6549
);
6650

6751
const heatmap = <HeatmapOverlay points={heatmapPoints} />;
68-
const state = provider === 'google-maps' ? googleState : mapLibreState;
6952

7053
return (
7154
<View style={styles.mapContainer}>
7255
<MapViewContainer
73-
state={state}
56+
provider={provider}
57+
cameraPosition={INIT_CAMERA}
58+
mapId="heatmap-layer"
59+
designTypes={{
60+
maplibre: MapLibreDesign.MapTilerTonerEn,
61+
'google-maps': GoogleMapDesign.Hybrid,
62+
}}
7463
style={styles.map}
7564
onMapLoaded={() => setMapReady(true)}
7665
>

examples/reactnative-basic/src/pages/map/basic/StoreMapPage.tsx

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,10 @@ import {
2020
Markers,
2121
ReactNativeImageDefaultIcon,
2222
} from '@mapconductor/js-sdk-react/native';
23-
import {
24-
GoogleMapDesign,
25-
useGoogleMapViewState,
26-
} from '@mapconductor/reactnative-for-googlemaps';
27-
import {
28-
MapLibreDesign,
29-
useMapLibreViewState,
30-
} from '@mapconductor/reactnative-for-maplibre';
31-
import {
32-
HereMapDesign,
33-
useHereViewState,
34-
} from '@mapconductor/reactnative-for-here';
3523

3624
import { STORES, type StoreInfo } from '../../../data/storeData';
3725
import { MapViewContainer } from '../../MapViewContainer';
38-
39-
type MapProvider = 'maplibre' | 'google-maps' | 'here';
26+
import type { MapProvider } from '../../../providers/types';
4027

4128
const INIT_CAMERA = MapCameraPosition.from({
4229
position: GeoPoint.from({ latitude: 21.382314, longitude: -157.933097, altitude: 0 }),
@@ -157,17 +144,11 @@ function StoreMarkers({ onSelectMarker }: { onSelectMarker: (marker: MarkerState
157144

158145
function StoreMap({
159146
provider,
160-
mapLibreState,
161-
googleState,
162-
hereState,
163147
onMapClick,
164148
onSelectMarker,
165149
selectedMarker,
166150
}: {
167151
provider: MapProvider;
168-
mapLibreState: ReturnType<typeof useMapLibreViewState>;
169-
googleState: ReturnType<typeof useGoogleMapViewState>;
170-
hereState: ReturnType<typeof useHereViewState>;
171152
onMapClick: () => void;
172153
onSelectMarker: (marker: MarkerState) => void;
173154
selectedMarker: MarkerState | null;
@@ -178,10 +159,14 @@ function StoreMap({
178159
</InfoBubble>
179160
) : null;
180161

181-
const state =
182-
provider === 'google-maps' ? googleState : provider === 'here' ? hereState : mapLibreState;
183162
return (
184-
<MapViewContainer state={state} style={styles.map} onMapClick={onMapClick}>
163+
<MapViewContainer
164+
provider={provider}
165+
cameraPosition={INIT_CAMERA}
166+
mapId="store-map"
167+
style={styles.map}
168+
onMapClick={onMapClick}
169+
>
185170
<StoreMarkers onSelectMarker={onSelectMarker} />
186171
{overlay}
187172
</MapViewContainer>
@@ -194,29 +179,10 @@ export function MapPage({ provider }: { provider: MapProvider }) {
194179
setSelectedMarker(marker);
195180
}, []);
196181

197-
const mapLibreState = useMapLibreViewState({
198-
id: 'store-map-maplibre',
199-
mapDesignType: MapLibreDesign.DemoTiles,
200-
cameraPosition: INIT_CAMERA,
201-
});
202-
const googleState = useGoogleMapViewState({
203-
id: 'store-map-google',
204-
mapDesignType: GoogleMapDesign.Normal,
205-
cameraPosition: INIT_CAMERA,
206-
});
207-
const hereState = useHereViewState({
208-
id: 'store-map-here',
209-
mapDesignType: HereMapDesign.NormalDay,
210-
cameraPosition: INIT_CAMERA,
211-
});
212-
213182
return (
214183
<View style={styles.mapContainer}>
215184
<StoreMap
216185
provider={provider}
217-
mapLibreState={mapLibreState}
218-
googleState={googleState}
219-
hereState={hereState}
220186
onMapClick={() => setSelectedMarker(null)}
221187
onSelectMarker={handleSelectMarker}
222188
selectedMarker={selectedMarker}

0 commit comments

Comments
 (0)