From 449243141bb1a6310d94113ae29d2d4fb8d7031c Mon Sep 17 00:00:00 2001 From: Rodrigo Lago Date: Thu, 7 Aug 2025 12:05:13 +0200 Subject: [PATCH] PoC: replace flutter_webview, use native MapViews instead --- android/build.gradle | 2 +- .../situm/situm_flutter/SitumFlutterPlugin.kt | 11 +- .../situm/situm_flutter/webview/WebView.kt | 46 ++++++ .../situm_flutter/webview/WebViewFactory.kt | 13 ++ example/ios/Podfile.lock | 20 +-- example/ios/Runner.xcodeproj/project.pbxproj | 58 +++---- example/pubspec.lock | 108 +++++--------- ios/Classes/SITFSDKPlugin.m | 81 ++++++++++ lib/src/controller.dart | 11 +- lib/src/situm_map_view.dart | 141 +++--------------- lib/src/webview/webview.dart | 63 ++++++++ lib/wayfinding.dart | 18 +-- pubspec.yaml | 4 - 13 files changed, 314 insertions(+), 262 deletions(-) create mode 100644 android/src/main/kotlin/com/situm/situm_flutter/webview/WebView.kt create mode 100644 android/src/main/kotlin/com/situm/situm_flutter/webview/WebViewFactory.kt create mode 100644 lib/src/webview/webview.dart diff --git a/android/build.gradle b/android/build.gradle index 9addf33..db2cf79 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -53,7 +53,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.4.1' - implementation ('es.situm:situm-sdk:3.32.0@aar') { + implementation ('es.situm:situm-sdk-feature-PRO-4089-local-viewer:3.32.0-DEV@aar') { transitive = true } } diff --git a/android/src/main/kotlin/com/situm/situm_flutter/SitumFlutterPlugin.kt b/android/src/main/kotlin/com/situm/situm_flutter/SitumFlutterPlugin.kt index 443bd82..8bebd15 100644 --- a/android/src/main/kotlin/com/situm/situm_flutter/SitumFlutterPlugin.kt +++ b/android/src/main/kotlin/com/situm/situm_flutter/SitumFlutterPlugin.kt @@ -7,7 +7,7 @@ import android.content.Intent import android.net.Uri import android.os.Looper import android.util.Log -import androidx.annotation.NonNull +import com.situm.situm_flutter.webview.WebViewFactory import es.situm.sdk.SitumSdk import es.situm.sdk.communication.CommunicationConfigImpl import es.situm.sdk.configuration.network.NetworkOptionsImpl @@ -53,9 +53,10 @@ class SitumFlutterPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCal companion object { private var initialized = false const val CHANNEL_ID_SDK = "situm.com/flutter_sdk" + const val CHANNEL_ID_MAPVIEW = "situm.com/flutter_mapview" } - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { Log.d("Situm", "Situm> SitumFlutterPlugin> onAttachedToEngine initialized=$initialized") // Firebase remote message issue: if (initialized) { @@ -66,9 +67,13 @@ class SitumFlutterPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCal channel.setMethodCallHandler(this) navigation = Navigation.init(channel, handler) viewerNavigation = ViewerNavigation.init(channel, handler) + // Register SDK MapView UI: + flutterPluginBinding + .platformViewRegistry + .registerViewFactory(CHANNEL_ID_MAPVIEW, WebViewFactory()) } - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { Log.d("Situm", "Situm> SitumFlutterPlugin> onDetachedFromEngine - initialized=$initialized") // onDetachedFromEngine should be called only when the app using this plugin is finalized, // but should not be related to the Firebase issue. diff --git a/android/src/main/kotlin/com/situm/situm_flutter/webview/WebView.kt b/android/src/main/kotlin/com/situm/situm_flutter/webview/WebView.kt new file mode 100644 index 0000000..a6a8b61 --- /dev/null +++ b/android/src/main/kotlin/com/situm/situm_flutter/webview/WebView.kt @@ -0,0 +1,46 @@ +package com.situm.situm_flutter.webview + +import android.content.Context +import android.util.Log +import android.view.View +import android.widget.FrameLayout +import android.widget.Toast +import es.situm.sdk.wayfinding.MapViewConfiguration +import es.situm.sdk.wayfinding.MapViewManager +import io.flutter.plugin.platform.PlatformView + +class WebView(val context: Context, id: Int, creationParams: Map?) : PlatformView { + val view: FrameLayout + + init { + view = FrameLayout(context).apply { + layoutParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + } + // TODO: incluír inicialmente un "loading" e logo facer "load"? + // TODO: pasar parámetros: MapViewConfiguration.fromMap() - creationParams? + val mapViewConfiguration = MapViewConfiguration.Builder() + .setBuildingIdentifier("7033") // Demo account + .setProfile("demo") + .setUseSdkCache(true) + .build() + MapViewManager.loadMapView(context, view, mapViewConfiguration) { loadResult -> + loadResult.onSuccess { controller -> + // TODO: fai falta o controller para postMessage. + }.onFailure { + // TODO: control de erros! + Toast.makeText(context, "Error loading MapView", Toast.LENGTH_LONG).show() + } + } + } + + override fun getView(): View? { + return view + } + + override fun dispose() { + + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/situm/situm_flutter/webview/WebViewFactory.kt b/android/src/main/kotlin/com/situm/situm_flutter/webview/WebViewFactory.kt new file mode 100644 index 0000000..2acc152 --- /dev/null +++ b/android/src/main/kotlin/com/situm/situm_flutter/webview/WebViewFactory.kt @@ -0,0 +1,13 @@ +package com.situm.situm_flutter.webview + +import android.content.Context +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory + +class WebViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + val creationParams = args as Map? + return WebView(context, viewId, creationParams) + } +} \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b36e5f4..8b4e2e7 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -2,22 +2,19 @@ PODS: - Flutter (1.0.0) - flutter_tts (0.0.1): - Flutter - - Protobuf (3.29.4) - - situm_flutter (3.26.8): + - Protobuf (3.29.5) + - situm_flutter (3.26.21): - Flutter - - SitumSDK (~> 3.31.0) - - SitumSDK (3.31.0): + - SitumSDK (~> 3.34.2) + - SitumSDK (3.34.2): - Protobuf (~> 3.18) - SSZipArchive (~> 2.4) - SSZipArchive (2.4.3) - - webview_flutter_wkwebview (0.0.1): - - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - situm_flutter (from `.symlinks/plugins/situm_flutter/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: @@ -32,17 +29,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_tts/ios" situm_flutter: :path: ".symlinks/plugins/situm_flutter/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d - Protobuf: 2e6de032ba12b9efb390ae550d1a243a5b19ddfc - situm_flutter: 0469718d710ee583c99acd73d815be7d978994a3 - SitumSDK: 1f26f3de4297e7834d901d6b2077022710129f4d + Protobuf: 164aea2ae380c3951abdc3e195220c01d17400e0 + situm_flutter: 6be48e773436cfb1ccd63c06d7eadb82513a2501 + SitumSDK: 31a8c53c5949e7add0bbc182fff70349ec1b027f SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef - webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 PODFILE CHECKSUM: b372eb01cab451b27c846ed62cbdd2b859c6b5a0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 1ba35cb..7c2527e 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3A41437728CDF76F55B64F6A /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A24E0C0EF7FBC545DC39E553 /* libPods-Runner.a */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 6F369E33677EEE60BC0D9FD5 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29D3809A246AD6E9C2083485 /* libPods-Runner.a */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -32,13 +32,11 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 29D3809A246AD6E9C2083485 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3C4F34DAEAE9273749973FC4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 778A0C3548409DCD92420B2A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 84C5F028A9FC7C35B5ECB00A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -46,7 +44,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - CE0BE5956251C9291018982A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + A24E0C0EF7FBC545DC39E553 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + D2F284A7E27E06D5252131DA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + DDF540DC4592EDFEFD371B6F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,17 +54,17 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6F369E33677EEE60BC0D9FD5 /* libPods-Runner.a in Frameworks */, + 3A41437728CDF76F55B64F6A /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 3A4C293D9F623C20013E12B8 /* Frameworks */ = { + 5DF4543D869E774A26127270 /* Frameworks */ = { isa = PBXGroup; children = ( - 29D3809A246AD6E9C2083485 /* libPods-Runner.a */, + A24E0C0EF7FBC545DC39E553 /* libPods-Runner.a */, ); name = Frameworks; sourceTree = ""; @@ -72,9 +72,9 @@ 9179D30E401B2A0D38B06047 /* Pods */ = { isa = PBXGroup; children = ( - 778A0C3548409DCD92420B2A /* Pods-Runner.debug.xcconfig */, - CE0BE5956251C9291018982A /* Pods-Runner.release.xcconfig */, - 3C4F34DAEAE9273749973FC4 /* Pods-Runner.profile.xcconfig */, + DDF540DC4592EDFEFD371B6F /* Pods-Runner.debug.xcconfig */, + D2F284A7E27E06D5252131DA /* Pods-Runner.release.xcconfig */, + 84C5F028A9FC7C35B5ECB00A /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -97,7 +97,7 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 9179D30E401B2A0D38B06047 /* Pods */, - 3A4C293D9F623C20013E12B8 /* Frameworks */, + 5DF4543D869E774A26127270 /* Frameworks */, ); sourceTree = ""; }; @@ -131,14 +131,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 0D51A14E7FD7F6F7B09B24F7 /* [CP] Check Pods Manifest.lock */, + 2857DA4F6E8B3F5813C2EB7B /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 424D2BB824AEA1BB016E83B4 /* [CP] Copy Pods Resources */, + FD0656CFD7BBEE6C77B6E225 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -197,7 +197,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0D51A14E7FD7F6F7B09B24F7 /* [CP] Check Pods Manifest.lock */ = { + 2857DA4F6E8B3F5813C2EB7B /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -235,37 +235,37 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 424D2BB824AEA1BB016E83B4 /* [CP] Copy Pods Resources */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + inputPaths = ( ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + name = "Run Script"; + outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + FD0656CFD7BBEE6C77B6E225 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputPaths = ( + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Run Script"; - outputPaths = ( + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/example/pubspec.lock b/example/pubspec.lock index f3a8e98..b8cf6ff 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -92,18 +92,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -124,10 +124,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -140,18 +140,18 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" plugin_platform_interface: dependency: transitive description: @@ -171,55 +171,55 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" vector_math: dependency: transitive description: @@ -232,42 +232,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" - webview_flutter: - dependency: transitive - description: - name: webview_flutter - sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 - url: "https://pub.dev" - source: hosted - version: "4.5.0" - webview_flutter_android: - dependency: transitive - description: - name: webview_flutter_android - sha256: "2282ba2320af34b2bd5320156c664d73f3f022341ed78847bc87723bf88c142f" - url: "https://pub.dev" - source: hosted - version: "3.16.2" - webview_flutter_platform_interface: - dependency: transitive - description: - name: webview_flutter_platform_interface - sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d - url: "https://pub.dev" - source: hosted - version: "2.10.0" - webview_flutter_wkwebview: - dependency: transitive - description: - name: webview_flutter_wkwebview - sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "3.10.2" + version: "15.0.0" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/ios/Classes/SITFSDKPlugin.m b/ios/Classes/SITFSDKPlugin.m index 2c329a6..4975a1c 100644 --- a/ios/Classes/SITFSDKPlugin.m +++ b/ios/Classes/SITFSDKPlugin.m @@ -22,9 +22,86 @@ @interface SITFSDKPlugin() @end +// MARK: NATIVE MAPVIEW - PoC + +// TODO: separar en ficheiros, neste fanse demasiadas cousas xa, require orden. +@interface WebViewFactory : NSObject +- (instancetype)initWithMessenger:(NSObject*)messenger; +@end + +@interface WebView : NSObject + +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args + binaryMessenger:(NSObject*)messenger; + +- (UIView*)view; +@end + +@implementation WebViewFactory { + NSObject* _messenger; +} + +- (instancetype)initWithMessenger:(NSObject*)messenger { + self = [super init]; + if (self) { + _messenger = messenger; + } + return self; +} + +- (NSObject*)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args { + return [[WebView alloc] initWithFrame:frame + viewIdentifier:viewId + arguments:args + binaryMessenger:_messenger]; +} + +/// Implementing this method is only necessary when the `arguments` in `createWithFrame` is not `nil`. +- (NSObject*)createArgsCodec { + return [FlutterStandardMessageCodec sharedInstance]; +} + +@end + +@implementation WebView { + SITMapView *_view; +} + +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args + binaryMessenger:(NSObject*)messenger { + if (self = [super init]) { + _view = [[SITMapView alloc] init]; + // TODO: usar arguments, SITMapViewConfiguration#fromMap(). + SITMapViewConfiguration *config = [[SITMapViewConfiguration alloc] initWithBuildingIdentifier:@"7033" profile:@""]; + [_view loadWithConfiguration:config withCompletion:^(id _Nonnull mapViewController, NSError * _Nullable error) { + if (error) { + NSLog(@"Error loading map: %@", error.localizedDescription); + } else { + NSLog(@"Map loaded properly"); + } + }]; + } + return self; +} + +- (UIView*)view { + return _view; +} + +@end + +// MARK: END NATIVE MAPVIEW + @implementation SITFSDKPlugin const NSString* RESULTS_KEY = @"results"; +NSString *const CHANNEL_ID_WAYFINDING = @"situm.com/flutter_mapview"; +(void)registerWithRegistrar:(NSObject*)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"situm.com/flutter_sdk" binaryMessenger:[registrar messenger]]; @@ -36,6 +113,10 @@ +(void)registerWithRegistrar:(NSObject*)registrar { [SITNavigationManager.sharedManager addDelegate:instance.navigationHandler]; instance.channel = channel; [registrar addMethodCallDelegate:instance channel:channel]; + // MARK: ALSO FOR NATIVE MAPVIEW: + WebViewFactory* factory = + [[WebViewFactory alloc] initWithMessenger:registrar.messenger]; + [registrar registerViewFactory:factory withId:CHANNEL_ID_WAYFINDING]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 30c5b2c..52d25e4 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -14,7 +14,6 @@ class MapViewController { OnMapViewErrorCallback? _onMapViewErrorCallBack; late MapViewCallback _widgetLoadCallback; - late PlatformWebViewController _webViewController; // Internal callback that will receive every MapView message. This callback // has been introduced to enable communication between MapView and the new AR @@ -79,9 +78,10 @@ class MapViewController { void _sendMessage(String type, dynamic payload) { // Do not quote payload keys! var message = "{type: '$type', payload: $payload}"; - _webViewController.runJavaScript(""" - window.postMessage($message) - """); + // TODO: invokeMethod para o channel ID de Wayfinding. + // _webViewController.runJavaScript(""" + // window.postMessage($message) + // """); } Future _validateMapViewProjectSettings() async { @@ -104,7 +104,8 @@ class MapViewController { /// Reloads the [MapView] using the current configuration by reloading the /// underlying platform web view controller. void reload() async { - _webViewController.reload(); + // TODO: implementar en nativo. + // _webViewController.reload(); } /// Selects the given Building in the map. diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index f7eb3e0..c646b6e 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -33,8 +33,6 @@ class MapView extends StatefulWidget { class _MapViewState extends State { static MapViewController? wyfController; - static PlatformWebViewController? webViewController; - static PlatformWebViewWidget? webViewWidget; late MapViewConfiguration mapViewConfiguration; bool _shouldDisplayBlankScreen = @@ -47,132 +45,31 @@ class _MapViewState extends State { // Avoid re-initializations of the underlying WebView (PlatformView) if // persistUnderlyingWidget is set to true. - if (webViewWidget != null && - mapViewConfiguration.persistUnderlyingWidget == true) { - _shouldDisplayBlankScreen = false; - return; - } - - PlatformWebViewControllerCreationParams params = - defaultTargetPlatform == TargetPlatform.android - ? AndroidWebViewControllerCreationParams() - : WebKitWebViewControllerCreationParams( - limitsNavigationsToAppBoundDomains: true, - ); - - webViewController = PlatformWebViewController(params); - webViewController! - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setBackgroundColor(const Color(0x00000000)) - ..setPlatformNavigationDelegate( - PlatformNavigationDelegate( - const PlatformNavigationDelegateCreationParams(), - ) - ..setOnProgress((int progress) { - // Do nothing. - }) - ..setOnPageStarted((String url) { - // Once we have loaded a page, hide the blank screen - _displayBlankScreen(false); - }) - ..setOnPageFinished((String url) { - debugPrint("Situm> WYF> Page loaded."); - }) - ..setOnWebResourceError((WebResourceError error) { - debugPrint(''' - Page resource error: - code: ${error.errorCode} - description: ${error.description} - errorType: ${error.errorType} - isForMainFrame: ${error.isForMainFrame} - url: ${error.url} - '''); - bool shouldDisplayRetryScreen = - error.isForMainFrame != null && error.isForMainFrame!; - - if (shouldDisplayRetryScreen && - ConnectionErrors.values.contains(error.errorCode)) { - webViewController!.loadFlutterAsset(MapView._retryScreenURL); - wyfController?._onMapViewErrorCallBack - ?.call(MapViewError.noNetworkError()); - } - }) - ..setOnNavigationRequest((dynamic request) { - if (request.url.startsWith(mapViewConfiguration.viewerDomain) || - request.url.endsWith(MapView._retryScreenURL) || - request.url == MapView._iframeHTMLURL) { - return NavigationDecision.navigate; - } - wyfController?._onExternalLinkClicked(request.url); - return NavigationDecision.prevent; - }) - ..setOnUrlChange((UrlChange change) { - debugPrint('url change to ${change.url}'); - }), - ) - ..addJavaScriptChannel(JavaScriptChannelParams( - name: WV_CHANNEL, - onMessageReceived: (JavaScriptMessage message) { - Map map = jsonDecode(message.message); - wyfController?.onMapViewerMessage(map["type"], map["payload"] ?? {}); - }, - )) - ..addJavaScriptChannel(JavaScriptChannelParams( - name: OFFLINE_CHANNEL, - onMessageReceived: (JavaScriptMessage message) { - _loadWithConfig(widget.configuration); - // Make sure we hide any native Android error screens before trying to load MapView again. - _displayBlankScreen(true); - }, - )) - ..setOnPlatformPermissionRequest( - (PlatformWebViewPermissionRequest request) { - debugPrint( - 'requesting permissions for ${request.types.map((WebViewPermissionResourceType type) => type.name)}', - ); - request.grant(); - }, - ); + // if (webViewWidget != null && + // TODO: mapViewConfiguration.persistUnderlyingWidget == true) { + // TODO: _shouldDisplayBlankScreen = false;??? Xa se encarga nativo??? + // return; + // } wyfController ??= MapViewController( situmApiKey: mapViewConfiguration.situmApiKey, ); wyfController!._widgetLoadCallback = widget.onLoad; wyfController!._onMapViewErrorCallBack = widget.onError; - wyfController!._webViewController = webViewController!; - PlatformWebViewWidgetCreationParams webViewParams = - defaultTargetPlatform == TargetPlatform.android - ? AndroidWebViewWidgetCreationParams( - controller: webViewController!, - displayWithHybridComposition: - widget.configuration.displayWithHybridComposition, - layoutDirection: widget.configuration.directionality, - ) - : PlatformWebViewWidgetCreationParams( - controller: webViewController!, - layoutDirection: widget.configuration.directionality, - ); - webViewWidget = PlatformWebViewWidget(webViewParams); _loadWithConfig(mapViewConfiguration); } void _loadWithConfig(MapViewConfiguration configuration) async { - if (webViewController is AndroidWebViewController) { - AndroidWebViewController.enableDebugging(configuration.enableDebugging); - } - - if (webViewController is WebKitWebViewController) { - (webViewController as WebKitWebViewController) - .setInspectable(configuration.enableDebugging); - } var sdk = SitumSdk(); + // TODO: sobra esto todo non? final String deviceId = await sdk.getDeviceId(); final String mapViewUrl = mapViewConfiguration._getViewerURL(deviceId); - // Load the composed URL in the WebView. - webViewController - ?.loadRequest(LoadRequestParams(uri: Uri.parse(mapViewUrl))); + // // Load the composed URL in the WebView. + // webViewController + // ?.loadRequest(LoadRequestParams(uri: Uri.parse(mapViewUrl))); } + // TODO: sobraría. void _displayBlankScreen(bool value) { if (mounted) { setState(() { @@ -184,17 +81,13 @@ class _MapViewState extends State { @override Widget build(BuildContext context) { - return _shouldDisplayBlankScreen - // This blank screen hides any error screen that the native Android webview could display - // before we handle it in setOnWebResourceError() callback. - ? Container(color: Colors.white) - // In the example of the plugin (https://pub.dev/packages/webview_flutter_android/example), - // PlatformWebViewWidget is instantiated in each call to the 'build' method. - // However, we avoid doing so because it is causing a native view to be - // generated with each 'build' call, resulting in flashes and even crashes. - // To solve this, we store a reference to the PlatformWebViewWidget and - // invoke its 'build' method. - : webViewWidget!.build(context); + if (defaultTargetPlatform == TargetPlatform.android) { + return buildWebViewHybrid(context); + } + if (defaultTargetPlatform == TargetPlatform.iOS) { + return buildIOS(context); + } + throw UnsupportedError('Unsupported platform view'); } @override diff --git a/lib/src/webview/webview.dart b/lib/src/webview/webview.dart new file mode 100644 index 0000000..8ad295e --- /dev/null +++ b/lib/src/webview/webview.dart @@ -0,0 +1,63 @@ +part of '../../wayfinding.dart'; + +const channelIdMapView = "situm.com/flutter_mapview"; + +// Este non tira tan ben como o hybrid, diría eu, pero hai que probar ben. +Widget buildWebViewTextureLayer(BuildContext context) { + // Pass parameters to the platform side. + final Map creationParams = {}; + + return AndroidView( + viewType: channelIdMapView, + layoutDirection: TextDirection.ltr, + creationParams: creationParams, + creationParamsCodec: const StandardMessageCodec(), + ); +} + +// TODO: crear widget con estado. +Widget buildWebViewHybrid(BuildContext context) { + // Pass parameters to the platform side. + const Map creationParams = {}; + + return PlatformViewLink( + viewType: channelIdMapView, + surfaceFactory: (context, controller) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (params) { + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: channelIdMapView, + // TODO: configurable!!! + layoutDirection: TextDirection.ltr, + creationParams: creationParams, + creationParamsCodec: const StandardMessageCodec(), + onFocus: () { + params.onFocusChanged(true); + }, + ) + // TODO: callback - onLoad aquí? postMessage? + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, + ); +} + +Widget buildIOS(BuildContext context) { + // This is used in the platform side to register the view. + const String viewType = channelIdMapView; + // Pass parameters to the platform side. + final Map creationParams = {}; + + return UiKitView( + viewType: viewType, + layoutDirection: TextDirection.ltr, + creationParams: creationParams, + creationParamsCodec: const StandardMessageCodec(), + ); +} \ No newline at end of file diff --git a/lib/wayfinding.dart b/lib/wayfinding.dart index 1892ac7..83c3e5a 100644 --- a/lib/wayfinding.dart +++ b/lib/wayfinding.dart @@ -6,23 +6,12 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:situm_flutter/sdk.dart'; -// Import for Android features. -import 'package:webview_flutter_android/webview_flutter_android.dart'; - -// WebView: -// Not necessary, also included with webview_flutter_platform_interface: -// import 'package:webview_flutter/webview_flutter.dart' hide NavigationRequest; -// WebView Platform interface: -import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart' - hide NavigationRequest; - -// Import for iOS features. -import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; - part 'src/controller.dart'; part 'src/definitions.dart'; @@ -33,6 +22,9 @@ part 'src/message_handlers.dart'; part 'src/situm_map_view.dart'; +part 'src/webview/webview.dart'; + +// TODO sobra fijo. const WV_CHANNEL = "ReactNativeWebView"; const OFFLINE_CHANNEL = "OfflineChannel"; diff --git a/pubspec.yaml b/pubspec.yaml index 234a379..19424e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,10 +11,6 @@ dependencies: flutter: sdk: flutter plugin_platform_interface: ^2.0.2 - webview_flutter: ^4.2.2 - webview_flutter_platform_interface: ^2.4.0 - webview_flutter_android: ^3.9.2 - webview_flutter_wkwebview: 3.10.2 dev_dependencies: flutter_test: