Open yiannis-spyridakis opened 1 month ago
Hi,
For Android I have confirmed that the plugin currently doesn't support data urls. It either opens a url starting with https://
or it looks for a sub-path under public
:
(code in CapacitorGoogleMap.buildMarker)
var stream: InputStream? = null
if (marker.iconUrl!!.startsWith("https:")) {
stream = URL(marker.iconUrl).openConnection().getInputStream()
} else {
stream = this.delegate.context.assets.open("public/${marker.iconUrl}")
}
var bitmap = BitmapFactory.decodeStream(stream)
this.markerIcons[marker.iconUrl!!] = bitmap
markerOptions.icon(getResizedIcon(bitmap, marker))
This works for me:
var stream: InputStream? = null
if (marker.iconUrl!!.startsWith("data:")) {
// Extract the base64 part for the data URL
val base64Data = marker.iconUrl!!.split(",")[1]
// Decode the base64 string into a byte array
val decodedBytes = Base64.decode(base64Data, Base64.DEFAULT)
// Convert the byte array to an InputStream
stream = ByteArrayInputStream(decodedBytes)
}
else if (marker.iconUrl!!.startsWith("https:")) {
stream = URL(marker.iconUrl).openConnection().getInputStream()
} else {
stream = this.delegate.context.assets.open("public/${marker.iconUrl}")
}
val bitmap = BitmapFactory.decodeStream(stream)
this.markerIcons[marker.iconUrl!!] = bitmap
markerOptions.icon(getResizedIcon(bitmap, marker))
Please let me know if you are interested in accepting contributions. Is the plugin actively maintained?
For completeness, as expected the behavior is the same on IOS.
The relevant function is Map.buildMarker
The relevant code section is here:
// cache and reuse marker icon uiimages
if let iconUrl = marker.iconUrl {
if let iconImage = self.markerIcons[iconUrl] {
newMarker.icon = getResizedIcon(iconImage, marker)
} else {
if iconUrl.starts(with: "https:") {
if let url = URL(string: iconUrl) {
URLSession.shared.dataTask(with: url) { (data, _, _) in
DispatchQueue.main.async {
if let data = data, let iconImage = UIImage(data: data) {
self.markerIcons[iconUrl] = iconImage
newMarker.icon = getResizedIcon(iconImage, marker)
}
}
}.resume()
}
} else if let iconImage = UIImage(named: "public/\(iconUrl)") {
self.markerIcons[iconUrl] = iconImage
newMarker.icon = getResizedIcon(iconImage, marker)
And this fix works for me:
if let iconUrl = marker.iconUrl {
if let iconImage = self.markerIcons[iconUrl] {
newMarker.icon = getResizedIcon(iconImage, marker)
} else {
if iconUrl.starts(with: "data") {
// Handle base64 encoded image
if let dataRange = iconUrl.range(of: "base64,") {
let base64String = String(iconUrl[dataRange.upperBound...])
if let imageData = Data(base64Encoded: base64String, options: .ignoreUnknownCharacters),
let iconImage = UIImage(data: imageData) {
self.markerIcons[iconUrl] = iconImage
newMarker.icon = getResizedIcon(iconImage, marker)
} else {
print("CapacitorGoogleMaps Wanring: could not decode base64 image. Using default marker icon.")
}
} else {
print("CapacitorGoogleMaps Warning: invalid data URL format. Using default marker icon.")
}
} else if iconUrl.starts(with: "https:") {
if let url = URL(string: iconUrl) {
URLSession.shared.dataTask(with: url) { (data, _, _) in
DispatchQueue.main.async {
if let data = data, let iconImage = UIImage(data: data) {
self.markerIcons[iconUrl] = iconImage
newMarker.icon = getResizedIcon(iconImage, marker)
}
}
}.resume()
}
} else if let iconImage = UIImage(named: "public/\(iconUrl)") {
self.markerIcons[iconUrl] = iconImage
newMarker.icon = getResizedIcon(iconImage, marker)
}
Bug Report
I am adding markers with code like this:
The image is ignored, I just get the standard marker icon.
Is this a known missing feature? By investigating, I was able to find some discussions regarding base64 svg icons but no direct confirmation that data urls are unsupported.
Can you please confirm?
Plugin(s)
@capacitor/google-maps
Capacitor Version
Platform(s)
Android IOS? (only tested on Android so far)
Current Behavior
Data urls are ignored when adding Markers.
Expected Behavior
A workaround or confirmation that this is expected.
Other Technical Details
The data url is exported from an HTML canvas like so: