Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[![Lint](https://img.shields.io/badge/lint-eslint-green.svg?logo=eslint&logoColor=white)](https://eslint.org/)
[![React Native](https://img.shields.io/badge/react--native-%3E%3D0.81.0-61dafb.svg?logo=react)](https://reactnative.dev/)
[![Platform: Android](https://img.shields.io/badge/platform-android-green.svg?logo=android&logoColor=white)](https://developer.android.com/)
[![Platform: iOS](https://img.shields.io/badge/platform-iOS-lightgrey.svg?logo=apple&logoColor=black)](https://developer.apple.com/ios/)
[![Pla[Dependencies.md](../../Downloads/Dependencies.md)tform: iOS](https://img.shields.io/badge/platform-iOS-lightgrey.svg?logo=apple&logoColor=black)](https://developer.apple.com/ios/)

React-native wrapper for android & IOS google maps sdk

Expand All @@ -22,13 +22,15 @@ React-native wrapper for android & IOS google maps sdk
yarn add react-native-google-maps-plus react-native-nitro-modules
```

Dependencies
# Dependencies

This package builds on native SVG rendering libraries:
This package builds on native libraries for SVG rendering and Google Maps integration:

iOS: [SVGKit](https://github.com/SVGKit/SVGKit)

Android: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)
- **iOS**: [SVGKit](https://github.com/SVGKit/SVGKit)
- **Android**: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)
- **iOS Maps SDK**: [Google Maps SDK for iOS](https://developers.google.com/maps/documentation/ios-sdk)
- **Android Maps SDK**: [Google Maps SDK for Android](https://developers.google.com/maps/documentation/android-sdk)
- **Maps Utility Libraries**: [Google Maps Utils for iOS](https://developers.google.com/maps/documentation/ios-sdk/utility) and [Google Maps Utils for Android](https://developers.google.com/maps/documentation/android-sdk/utility)

These are automatically linked when you install the package, but you may need to clean/rebuild your native projects after first install.

Expand Down
5 changes: 3 additions & 2 deletions RNGoogleMapsPlus.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pod::Spec.new do |s|
s.license = package["license"]
s.authors = package["author"]

s.platforms = { :ios => 16.0 }
s.platforms = { :ios => 15.1 }
s.source = { :git => "https://github.com/pinpong/react-native-google-maps-plus.git", :tag => "#{s.version}" }

s.source_files = "ios/**/*.{h,m,mm,swift}"
Expand All @@ -26,7 +26,8 @@ Pod::Spec.new do |s|
s.dependency 'React-jsi'
s.dependency 'React-callinvoker'

s.dependency 'GoogleMaps', '10.3.0'
s.dependency 'GoogleMaps', '10.4.0'
s.dependency 'Google-Maps-iOS-Utils', '6.1.3'
s.dependency 'SVGKit', '3.0.0'

load 'nitrogen/generated/ios/RNGoogleMapsPlus+autolinking.rb'
Expand Down
54 changes: 54 additions & 0 deletions android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.google.android.gms.maps.model.Polygon
import com.google.android.gms.maps.model.PolygonOptions
import com.google.android.gms.maps.model.Polyline
import com.google.android.gms.maps.model.PolylineOptions
import com.google.android.gms.maps.model.TileOverlay
import com.google.android.gms.maps.model.TileOverlayOptions
import com.rngooglemapsplus.extensions.toGooglePriority
import com.rngooglemapsplus.extensions.toLocationErrorCode

Expand Down Expand Up @@ -52,11 +54,13 @@ class GoogleMapsViewImpl(
private val pendingPolylines = mutableListOf<Pair<String, PolylineOptions>>()
private val pendingPolygons = mutableListOf<Pair<String, PolygonOptions>>()
private val pendingCircles = mutableListOf<Pair<String, CircleOptions>>()
private val pendingHeatmaps = mutableListOf<Pair<String, TileOverlayOptions>>()

private val markersById = mutableMapOf<String, Marker>()
private val polylinesById = mutableMapOf<String, Polyline>()
private val polygonsById = mutableMapOf<String, Polygon>()
private val circlesById = mutableMapOf<String, Circle>()
private val heatmapsById = mutableMapOf<String, TileOverlay>()

private var cameraMoveReason = -1
private var lastSubmittedLocation: Location? = null
Expand Down Expand Up @@ -332,6 +336,13 @@ class GoogleMapsViewImpl(
}
pendingCircles.clear()
}

if (pendingHeatmaps.isNotEmpty()) {
pendingHeatmaps.forEach { (id, opts) ->
internalAddHeatmap(id, opts)
}
pendingHeatmaps.clear()
}
}

var uiSettings: RNMapUiSettings? = null
Expand Down Expand Up @@ -772,13 +783,56 @@ class GoogleMapsViewImpl(
pendingCircles.clear()
}

fun addHeatmap(
id: String,
opts: TileOverlayOptions,
) {
if (googleMap == null) {
pendingHeatmaps.add(id to opts)
return
}

onUi {
heatmapsById.remove(id)?.remove()
}
internalAddHeatmap(id, opts)
}

private fun internalAddHeatmap(
id: String,
opts: TileOverlayOptions,
) {
onUi {
val heatmap =
googleMap?.addTileOverlay(opts)
if (heatmap != null) {
heatmapsById[id] = heatmap
}
}
}

fun removeHeatmap(id: String) {
onUi {
heatmapsById.remove(id)?.remove()
}
}

fun clearHeatmaps() {
onUi {
heatmapsById.values.forEach { it.remove() }
}
circlesById.clear()
pendingHeatmaps.clear()
}

fun destroyInternal() {
onUi {
markerBuilder.cancelAllJobs()
clearMarkers()
clearPolylines()
clearPolygons()
clearCircles()
clearHeatmaps()
locationHandler.stop()
googleMap?.apply {
setOnCameraMoveStartedListener(null)
Expand Down
31 changes: 31 additions & 0 deletions android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.rngooglemapsplus

import com.facebook.react.uimanager.PixelUtil.dpToPx
import com.google.android.gms.maps.model.TileOverlayOptions
import com.google.maps.android.heatmaps.Gradient
import com.google.maps.android.heatmaps.HeatmapTileProvider
import com.rngooglemapsplus.extensions.toColor
import com.rngooglemapsplus.extensions.toWeightedLatLngs

class MapHeatmapBuilder {
fun build(heatmap: RNHeatmap): TileOverlayOptions {
val provider =
HeatmapTileProvider
.Builder()
.apply {
weightedData(heatmap.weightedData.toWeightedLatLngs())
heatmap.radius?.let { radius(it.dpToPx().toInt().coerceIn(10, 50)) }
heatmap.opacity?.let { opacity(it) }
heatmap.gradient?.let {
val colors = it.colors.map { c -> c.toColor() }.toIntArray()
val startPoints = it.startPoints.map { p -> p.toFloat() }.toFloatArray()
gradient(Gradient(colors, startPoints))
}
}.build()

return TileOverlayOptions().apply {
tileProvider(provider)
heatmap.zIndex?.let { zIndex(it.toFloat()) }
}
}
}
16 changes: 16 additions & 0 deletions android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class RNGoogleMapsPlusView(
private val polylineBuilder = MapPolylineBuilder()
private val polygonBuilder = MapPolygonBuilder()
private val circleBuilder = MapCircleBuilder()
private val heatmapBuilder = MapHeatmapBuilder()

override val view =
GoogleMapsViewImpl(context, locationHandler, playServiceHandler, markerBuilder)
Expand Down Expand Up @@ -218,6 +219,21 @@ class RNGoogleMapsPlusView(
}
}

override var heatmaps: Array<RNHeatmap>? = null
set(value) {
if (field.contentEquals(value)) return
val prevById = field?.associateBy { it.id } ?: emptyMap()
val nextById = value?.associateBy { it.id } ?: emptyMap()
field = value
(prevById.keys - nextById.keys).forEach { id ->
view.removeHeatmap(id)
}

nextById.forEach { (id, next) ->
view.addHeatmap(id, heatmapBuilder.build(next))
}
}

override var locationConfig: RNLocationConfig? = null
set(value) {
if (field == value) return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.rngooglemapsplus.extensions

import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.heatmaps.WeightedLatLng
import com.rngooglemapsplus.RNHeatmapPoint

fun RNHeatmapPoint.toWeightedLatLng(): WeightedLatLng = WeightedLatLng(LatLng(latitude, longitude), weight)

fun Array<RNHeatmapPoint>.toWeightedLatLngs(): Collection<WeightedLatLng> = map { it.toWeightedLatLng() }
12 changes: 11 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ export default defineConfig([
},
},
{
ignores: ['node_modules/', 'lib/', '.yarn', 'eslint.config.mjs'],
ignores: [
'node_modules/',
'lib/',
'**/build/**',
'**/ios/**',
'**/android/**',
'nitrogen/',
'example/vendor/',
'.yarn',
'eslint.config.mjs',
],
},
]);
60 changes: 30 additions & 30 deletions example/ios/GoogleMapsPlusExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
50142BCB3C4DD87E00709364 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
89A7882DE3880107EB2CBBE5 /* Pods_GoogleMapsPlusExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F220CF45106F6693F3EE2E0 /* Pods_GoogleMapsPlusExample.framework */; };
C278F67776EF7358337EE23E /* Pods_GoogleMapsPlusExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F76B3BA251D3575BE140916E /* Pods_GoogleMapsPlusExample.framework */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
0F220CF45106F6693F3EE2E0 /* Pods_GoogleMapsPlusExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GoogleMapsPlusExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* GoogleMapsPlusExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GoogleMapsPlusExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = GoogleMapsPlusExample/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = GoogleMapsPlusExample/Info.plist; sourceTree = "<group>"; };
Expand All @@ -29,18 +28,19 @@
1CFDC6A32E6CA144005652FB /* InfoPlist.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = InfoPlist.strings; sourceTree = "<group>"; };
1CFDC6A62E6CA144005652FB /* InfoPlist.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = InfoPlist.strings; sourceTree = "<group>"; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = GoogleMapsPlusExample/AppDelegate.swift; sourceTree = "<group>"; };
784D90989C3F0C69A83034D7 /* Pods-GoogleMapsPlusExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoogleMapsPlusExample.debug.xcconfig"; path = "Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample.debug.xcconfig"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = GoogleMapsPlusExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
CE69916FEF4DE92FC3CC2A4C /* Pods-GoogleMapsPlusExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoogleMapsPlusExample.release.xcconfig"; path = "Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample.release.xcconfig"; sourceTree = "<group>"; };
C221050642A048ADBE57AC5E /* Pods-GoogleMapsPlusExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoogleMapsPlusExample.debug.xcconfig"; path = "Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample.debug.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED5CA485AF743A33F395113E /* Pods-GoogleMapsPlusExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoogleMapsPlusExample.release.xcconfig"; path = "Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample.release.xcconfig"; sourceTree = "<group>"; };
F76B3BA251D3575BE140916E /* Pods_GoogleMapsPlusExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GoogleMapsPlusExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
89A7882DE3880107EB2CBBE5 /* Pods_GoogleMapsPlusExample.framework in Frameworks */,
C278F67776EF7358337EE23E /* Pods_GoogleMapsPlusExample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -85,7 +85,7 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
0F220CF45106F6693F3EE2E0 /* Pods_GoogleMapsPlusExample.framework */,
F76B3BA251D3575BE140916E /* Pods_GoogleMapsPlusExample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -122,8 +122,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
784D90989C3F0C69A83034D7 /* Pods-GoogleMapsPlusExample.debug.xcconfig */,
CE69916FEF4DE92FC3CC2A4C /* Pods-GoogleMapsPlusExample.release.xcconfig */,
C221050642A048ADBE57AC5E /* Pods-GoogleMapsPlusExample.debug.xcconfig */,
ED5CA485AF743A33F395113E /* Pods-GoogleMapsPlusExample.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
Expand All @@ -135,13 +135,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "GoogleMapsPlusExample" */;
buildPhases = (
4E15D3C08A668E0F5197AB1A /* [CP] Check Pods Manifest.lock */,
7B8C8319FEFE19D20D861FF9 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
A4CAAB1E58D131C3CE20A532 /* [CP] Embed Pods Frameworks */,
5AC776E708BE569B105221C3 /* [CP] Copy Pods Resources */,
4DCFCDCD0D027DB529AB541C /* [CP] Embed Pods Frameworks */,
8CB46C92B529E2369D8EEACB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -218,7 +218,24 @@
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
4E15D3C08A668E0F5197AB1A /* [CP] Check Pods Manifest.lock */ = {
4DCFCDCD0D027DB529AB541C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
7B8C8319FEFE19D20D861FF9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand All @@ -240,7 +257,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5AC776E708BE569B105221C3 /* [CP] Copy Pods Resources */ = {
8CB46C92B529E2369D8EEACB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand All @@ -257,23 +274,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
A4CAAB1E58D131C3CE20A532 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GoogleMapsPlusExample/Pods-GoogleMapsPlusExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
Expand Down
Loading
Loading