From ec61e1bc442bc21a586dc4ca4610416831805aba Mon Sep 17 00:00:00 2001 From: Julian Bissekkou Date: Sun, 26 Nov 2023 13:20:30 +0100 Subject: [PATCH 1/2] catch exceptions while parsing and fix poliline on mobile --- .../arcgis_map_sdk_android/ArcgisMapView.kt | 12 +++++- .../util/GraphicsParser.kt | 22 ++++++++-- .../ios/Classes/ArcgisMapView.swift | 8 +++- .../ios/Classes/GraphicsParser.swift | 43 +++++++++++-------- .../ios/Classes/ParseException.swift | 13 ++++++ example/ios/Podfile.lock | 2 +- example/lib/main.dart | 13 +++--- example/pubspec.lock | 26 +++++------ 8 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 arcgis_map_sdk_ios/ios/Classes/ParseException.swift diff --git a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/ArcgisMapView.kt b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/ArcgisMapView.kt index 1c48047e..c7086c52 100644 --- a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/ArcgisMapView.kt +++ b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/ArcgisMapView.kt @@ -13,6 +13,7 @@ import com.esri.arcgisruntime.mapping.Basemap import com.esri.arcgisruntime.mapping.BasemapStyle import com.esri.arcgisruntime.mapping.Viewpoint import com.esri.arcgisruntime.mapping.view.AnimationCurve +import com.esri.arcgisruntime.mapping.view.Graphic import com.esri.arcgisruntime.mapping.view.GraphicsOverlay import com.esri.arcgisruntime.mapping.view.MapView import com.google.gson.reflect.TypeToken @@ -50,7 +51,8 @@ internal class ArcgisMapView( private lateinit var zoomStreamHandler: ZoomStreamHandler private lateinit var centerPositionStreamHandler: CenterPositionStreamHandler - private val methodChannel = MethodChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId") + private val methodChannel = + MethodChannel(binaryMessenger, "dev.fluttercommunity.arcgis_map_sdk/$viewId") override fun getView(): View = view @@ -193,7 +195,13 @@ internal class ArcgisMapView( private fun onAddGraphic(call: MethodCall, result: MethodChannel.Result) { val graphicArguments = call.arguments as Map - val newGraphic = GraphicsParser.parse(graphicArguments) + lateinit var newGraphic: List + try { + newGraphic = GraphicsParser.parse(graphicArguments) + } catch (e: Throwable) { + result.error("unknown_error", "Error while adding graphic. $e)", null) + return + } val existingIds = defaultGraphicsOverlay.graphics.mapNotNull { it.attributes["id"] as? String } diff --git a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/util/GraphicsParser.kt b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/util/GraphicsParser.kt index 61e098b1..08eaf2af 100644 --- a/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/util/GraphicsParser.kt +++ b/arcgis_map_sdk_android/android/src/main/kotlin/dev/fluttercommunity/arcgis_map_sdk_android/util/GraphicsParser.kt @@ -1,10 +1,16 @@ package dev.fluttercommunity.arcgis_map_sdk_android.util +import com.esri.arcgisruntime.geometry.Point import com.esri.arcgisruntime.geometry.PointCollection import com.esri.arcgisruntime.geometry.Polygon import com.esri.arcgisruntime.geometry.Polyline +import com.esri.arcgisruntime.geometry.SpatialReferences import com.esri.arcgisruntime.mapping.view.Graphic -import com.esri.arcgisruntime.symbology.* +import com.esri.arcgisruntime.symbology.PictureMarkerSymbol +import com.esri.arcgisruntime.symbology.SimpleFillSymbol +import com.esri.arcgisruntime.symbology.SimpleLineSymbol +import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol +import com.esri.arcgisruntime.symbology.Symbol import dev.fluttercommunity.arcgis_map_sdk_android.model.LatLng import dev.fluttercommunity.arcgis_map_sdk_android.model.symbol.PictureMarkerSymbolPayload import dev.fluttercommunity.arcgis_map_sdk_android.model.symbol.SimpleFillSymbolPayload @@ -51,11 +57,21 @@ class GraphicsParser { } private fun parsePolyline(map: Map): List { - val points = parseToClass>>(map["paths"]!!) + val points = parseToClass>>>(map["paths"]!!) return points.map { subPoints -> Graphic().apply { - geometry = Polyline(PointCollection(subPoints.map { it.toAGSPoint() })) + geometry = Polyline(PointCollection(subPoints.map { coordinateArray -> + val x = coordinateArray.elementAtOrNull(0) + val y = coordinateArray.elementAtOrNull(1) + val z = coordinateArray.elementAtOrNull(2) + if (x == null || y == null) { + throw Exception("Coordinate array needs at least 2 doubles. Got $coordinateArray") + } + + if (z != null) Point(x, y, z, SpatialReferences.getWgs84()) + else Point(x, y, SpatialReferences.getWgs84()) + })) symbol = parseSymbol(map) } } diff --git a/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift b/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift index 72329348..ccb947b6 100644 --- a/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift +++ b/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift @@ -193,7 +193,13 @@ class ArcgisMapView: NSObject, FlutterPlatformView { private func onAddGraphic(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { let parser = GraphicsParser() - let newGraphics = parser.parse(dictionary: call.arguments as! Dictionary) + var newGraphics = [AGSGraphic]() + do { + newGraphics.append(contentsOf: try parser.parse(dictionary: call.arguments as! Dictionary)) + } catch { + result(FlutterError(code: "unknown_error", message: "Error while adding graphic. \(error)", details: nil)) + } + let existingIds = defaultGraphicsOverlay.graphics.compactMap { object in let graphic = object as! AGSGraphic diff --git a/arcgis_map_sdk_ios/ios/Classes/GraphicsParser.swift b/arcgis_map_sdk_ios/ios/Classes/GraphicsParser.swift index a07d9af9..62aebc2a 100644 --- a/arcgis_map_sdk_ios/ios/Classes/GraphicsParser.swift +++ b/arcgis_map_sdk_ios/ios/Classes/GraphicsParser.swift @@ -9,19 +9,19 @@ import Foundation import ArcGIS class GraphicsParser { - func parse(dictionary: Dictionary) -> [AGSGraphic] { + func parse(dictionary: Dictionary) throws -> [AGSGraphic] { let type = dictionary["type"] as! String let newGraphics: [AGSGraphic] switch (type) { case "point": - newGraphics = parsePoint(dictionary) + newGraphics = try! parsePoint(dictionary) case "polygon": - newGraphics = parsePolygon(dictionary) + newGraphics = try! parsePolygon(dictionary) case "polyline": - newGraphics = parsePolyline(dictionary) + newGraphics = try! parsePolyline(dictionary) default: - fatalError("Unknown type: \(type)") + throw ParseException(message: "Unknown graphic type: \(type)") } let attributes = dictionary["attributes"] as? Dictionary @@ -33,32 +33,39 @@ class GraphicsParser { return newGraphics } - private func parsePoint(_ dictionary: [String: Any]) -> [AGSGraphic] { + private func parsePoint(_ dictionary: [String: Any]) throws -> [AGSGraphic] { let point: LatLng = try! JsonUtil.objectOfJson(dictionary["point"] as! Dictionary) let graphic = AGSGraphic() graphic.geometry = point.toAGSPoint() - graphic.symbol = parseSymbol(dictionary["symbol"] as! Dictionary) + graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary) return [graphic] } - private func parsePolyline(_ dictionary: [String: Any]) -> [AGSGraphic] { + private func parsePolyline(_ dictionary: [String: Any]) throws -> [AGSGraphic] { let payload: PathPayload = try! JsonUtil.objectOfJson(dictionary) - return payload.paths.map { coordinates in - let points = coordinates.map { - $0.toAGSPoint() + return try payload.paths.map { coordinates in + let points = try coordinates.map { array in + if(array.count < 2) { + throw ParseException(message: "Size of coordinates need to be at least 2. Got \(array)") + } + if(array.count > 2) { + return AGSPoint(x: array[0], y: array[1], z: array[2], spatialReference: .wgs84()) + } + return AGSPoint(x: array[0], y: array[1], spatialReference: .wgs84()) } + let graphic = AGSGraphic() - graphic.geometry = AGSPolyline(points: points) - graphic.symbol = parseSymbol(dictionary["symbol"] as! Dictionary) + graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary) + return graphic } } - private func parsePolygon(_ dictionary: [String: Any]) -> [AGSGraphic] { + private func parsePolygon(_ dictionary: [String: Any]) throws -> [AGSGraphic] { let payload: PolygonPayload = try! JsonUtil.objectOfJson(dictionary) return payload.rings.map { ring in @@ -67,7 +74,7 @@ class GraphicsParser { AGSPoint(x: coordinate[0], y: coordinate[1], spatialReference: .wgs84()) } graphic.geometry = AGSPolygon(points: points) - graphic.symbol = parseSymbol(dictionary["symbol"] as! Dictionary) + graphic.symbol = try! parseSymbol(dictionary["symbol"] as! Dictionary) return graphic } @@ -75,7 +82,7 @@ class GraphicsParser { // region symbol parsing - private func parseSymbol(_ dictionary: [String: Any]) -> AGSSymbol { + private func parseSymbol(_ dictionary: [String: Any]) throws -> AGSSymbol { let type = dictionary["type"] as! String; switch (type) { case "simple-marker": @@ -87,7 +94,7 @@ class GraphicsParser { case "simple-line": return parseSimpleLineSymbol(dictionary) default: - fatalError("Unknown type: \(type)") + throw ParseException(message: "Unknown symbol type: \(type)") } } @@ -153,7 +160,7 @@ class GraphicsParser { } private struct PathPayload: Codable { - let paths: [[LatLng]] + let paths: [[[Double]]] } private struct PolygonPayload: Codable { diff --git a/arcgis_map_sdk_ios/ios/Classes/ParseException.swift b/arcgis_map_sdk_ios/ios/Classes/ParseException.swift new file mode 100644 index 00000000..35090d0f --- /dev/null +++ b/arcgis_map_sdk_ios/ios/Classes/ParseException.swift @@ -0,0 +1,13 @@ +// +// ParseException.swift +// arcgis_map_sdk_ios +// +// Created by Julian Bissekkou on 26.11.23. +// + +import Foundation + + +struct ParseException: Error { + let message: String +} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index ed197dc9..390c17b8 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -30,4 +30,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b -COCOAPODS: 1.13.0 +COCOAPODS: 1.12.1 diff --git a/example/lib/main.dart b/example/lib/main.dart index 3cdaab40..f0433577 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -119,12 +119,6 @@ class _ExampleMapState extends State { layerId: _lineLayerId, elevationMode: ElevationMode.onTheGround, ); - _connectTwoPinsWithPolyline( - id: 'connecting-polyline-01', - name: 'Connecting polyline', - start: _firstPinCoordinates, - end: _secondPinCoordinates, - ); // Create GraphicsLayer with 3D Pins await _createGraphicLayer(layerId: _pinLayerId); @@ -136,6 +130,13 @@ class _ExampleMapState extends State { }); } + _connectTwoPinsWithPolyline( + id: 'connecting-polyline-01', + name: 'Connecting polyline', + start: _firstPinCoordinates, + end: _secondPinCoordinates, + ); + // Add Polygons to the PolyLayer _addPolygon( layerId: _polyLayerId, diff --git a/example/pubspec.lock b/example/pubspec.lock index 219468c9..be84cb57 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -79,10 +79,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" cupertino_icons: dependency: "direct main" description: @@ -166,10 +166,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" path: dependency: transitive description: @@ -203,18 +203,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -235,10 +235,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" vector_math: dependency: transitive description: @@ -251,10 +251,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.4-beta" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.1.0 <4.0.0" flutter: ">=3.10.0" From 8bcefcdb8ddba1e6cb227a615c6d23296be79d84 Mon Sep 17 00:00:00 2001 From: Julian Bissekkou Date: Mon, 27 Nov 2023 08:29:45 +0100 Subject: [PATCH 2/2] add missing return --- arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift b/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift index ccb947b6..bc376210 100644 --- a/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift +++ b/arcgis_map_sdk_ios/ios/Classes/ArcgisMapView.swift @@ -198,6 +198,7 @@ class ArcgisMapView: NSObject, FlutterPlatformView { newGraphics.append(contentsOf: try parser.parse(dictionary: call.arguments as! Dictionary)) } catch { result(FlutterError(code: "unknown_error", message: "Error while adding graphic. \(error)", details: nil)) + return }