diff --git a/ln_jq_app/README.md b/ln_jq_app/README.md index 7aec585..b852541 100644 --- a/ln_jq_app/README.md +++ b/ln_jq_app/README.md @@ -10,4 +10,10 @@ Ln123456. 高德key 安卓 92495660f7bc990cb475426c47c03b65 -苹果:3ac08e5e14df9d7a52e98d40e21a0189 \ No newline at end of file +苹果:3ac08e5e14df9d7a52e98d40e21a0189 + +key:2cc1d822e313307fe311c3127a1deeb5 +秘钥:0529b72df6bf0c577ff2182cb8b1d970 + +安卓包名:com.lingniu.driver +iOS包名:com.lnkj.ln_jq_app diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml index c7c3c0b..de6a7dc 100644 --- a/ln_jq_app/android/app/src/main/AndroidManifest.xml +++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml @@ -11,6 +11,10 @@ + + + + + + + + + + + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/ln_jq_app/ios/Podfile b/ln_jq_app/ios/Podfile index 620e46e..467c7f8 100644 --- a/ln_jq_app/ios/Podfile +++ b/ln_jq_app/ios/Podfile @@ -38,6 +38,33 @@ end post_install do |installer| installer.pods_project.targets.each do |target| + # Flutter 默认配置 flutter_additional_ios_build_settings(target) + + # --------------------------------------------------------- + # 1. Geolocator 配置 (你原来的代码) + # --------------------------------------------------------- + if target.name == "geolocator_apple" + target.build_configurations.each do |config| + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BYPASS_PERMISSION_LOCATION_ALWAYS=1'] + end + end + + # --------------------------------------------------------- + # 2. PermissionHandler 配置 (这是缺少的关键部分!!!) + # 必须显式开启 'PERMISSION_LOCATION=1' + # --------------------------------------------------------- + target.build_configurations.each do |config| + # 确保 GCC_PREPROCESSOR_DEFINITIONS 存在 + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)'] + + # 开启定位权限支持 + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'PERMISSION_LOCATION=1' + + # 如果你需要其他权限,也在这里加,比如相机: + # config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'PERMISSION_CAMERA=1' + end + end end + diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index dea1cda..6fec17e 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -4,13 +4,24 @@ PODS: - device_info_plus (0.0.1): - Flutter - Flutter (1.0.0) + - flutter_inappwebview_ios (0.0.1): + - Flutter + - flutter_inappwebview_ios/Core (= 0.0.1) + - OrderedSet (~> 6.0.3) + - flutter_inappwebview_ios/Core (0.0.1): + - Flutter + - OrderedSet (~> 6.0.3) - flutter_native_splash (2.4.3): - Flutter - flutter_pdfview (1.0.2): - Flutter + - geolocator_apple (1.2.0): + - Flutter + - FlutterMacOS - image_picker_ios (0.0.1): - Flutter - MTBBarcodeScanner (5.0.11) + - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -31,8 +42,10 @@ DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) + - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_pdfview (from `.symlinks/plugins/flutter_pdfview/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -44,6 +57,7 @@ DEPENDENCIES: SPEC REPOS: trunk: - MTBBarcodeScanner + - OrderedSet EXTERNAL SOURCES: connectivity_plus: @@ -52,10 +66,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/device_info_plus/ios" Flutter: :path: Flutter + flutter_inappwebview_ios: + :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" flutter_native_splash: :path: ".symlinks/plugins/flutter_native_splash/ios" flutter_pdfview: :path: ".symlinks/plugins/flutter_pdfview/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/darwin" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" package_info_plus: @@ -75,10 +93,13 @@ SPEC CHECKSUMS: connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf flutter_pdfview: 54e283d5851b0b247b3cc57877d35f1a05a204de + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d @@ -86,6 +107,6 @@ SPEC CHECKSUMS: shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b -PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e +PODFILE CHECKSUM: c2b648820a58f7013d9d17db812a119f8affaf6f COCOAPODS: 1.16.2 diff --git a/ln_jq_app/ios/Runner/Info.plist b/ln_jq_app/ios/Runner/Info.plist index 6fb8753..51cc9d6 100644 --- a/ln_jq_app/ios/Runner/Info.plist +++ b/ln_jq_app/ios/Runner/Info.plist @@ -2,8 +2,16 @@ - - + NSLocationWhenInUseUsageDescription + 需要您的位置信息以在地图上展示 + + NSLocationAlwaysAndWhenInUseUsageDescription + 我们需要您的位置来规划路线 + + NSLocationAlwaysUsageDescription + 我们需要您的位置来规划路线 + + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/ln_jq_app/lib/pages/b_page/reservation/controller.dart b/ln_jq_app/lib/pages/b_page/reservation/controller.dart index aefb0f8..9b9a40a 100644 --- a/ln_jq_app/lib/pages/b_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/b_page/reservation/controller.dart @@ -59,7 +59,13 @@ class ReservationController extends GetxController with BaseControllerMixin { } else { costPrice = "暂无价格"; } - customerPrice = result.data["customerPrice"] ?? "暂无价格"; + var customerPriceTemp = result.data["customerPrice"]; + if (customerPriceTemp != null && customerPriceTemp.toString().isNotEmpty) { + customerPrice = "$customerPriceTemp"; + } else { + customerPrice = "暂无价格"; + } + phone = result.data["phone"]; startBusiness = result.data["startBusiness"]; endBusiness = result.data["endBusiness"]; diff --git a/ln_jq_app/lib/pages/c_page/base_widgets/view.dart b/ln_jq_app/lib/pages/c_page/base_widgets/view.dart index 7d828f9..3edc03b 100644 --- a/ln_jq_app/lib/pages/c_page/base_widgets/view.dart +++ b/ln_jq_app/lib/pages/c_page/base_widgets/view.dart @@ -16,6 +16,7 @@ class BaseWidgetsPage extends GetView { Widget _buildView() { return PageView( controller: _pageController, + physics: const NeverScrollableScrollPhysics(), // 禁止滑动 onPageChanged: (index) { jumpTabAndPage(index); }, @@ -31,7 +32,7 @@ class BaseWidgetsPage extends GetView { // 对应的页面 List _buildPages() { return [ - // MapPage(), + MapPage(), ReservationPage(), CarInfoPage(), MinePage(), @@ -46,12 +47,12 @@ class BaseWidgetsPage extends GetView { jumpTabAndPage(index); }, // 切换tab事件 items: [ - /*NavigationItemModel( + NavigationItemModel( label: '地图', icon: AntdIcon.location, selectedIcon: AntdIcon.location_fill, dot: false, - ),*/ + ), NavigationItemModel( label: '加氢预约', icon: AntdIcon.orderedlist, diff --git a/ln_jq_app/lib/pages/c_page/map/controller.dart b/ln_jq_app/lib/pages/c_page/map/controller.dart index 192520a..41a5911 100644 --- a/ln_jq_app/lib/pages/c_page/map/controller.dart +++ b/ln_jq_app/lib/pages/c_page/map/controller.dart @@ -1,18 +1,127 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:permission_handler/permission_handler.dart'; // 确保引用这个做权限请求 class MapController extends GetxController with BaseControllerMixin { @override String get builderId => 'map'; - MapController(); + InAppWebViewController? webViewController; + StreamSubscription? positionStream; + final RxBool isLocationPermissionGranted = false.obs; + + // 缓存最后一次的位置,防止 WebView 加载慢于定位 + Position? _lastKnownPosition; + // 是否已经初始化过地图中心 + bool _hasInitializedMapCenter = false; @override void onInit() { super.onInit(); + requestLocationPermission(); } @override void onClose() { + positionStream?.cancel(); super.onClose(); } -} + + // 请求权限 + void requestLocationPermission() async { + var status = await Permission.locationWhenInUse.request(); + + print("权限状态: $status"); // 在控制台看这个输出 + + if (status.isGranted) { + isLocationPermissionGranted.value = true; + showToast('定位权限已获取'); + _startLocationTracking(); + } + else if (status.isPermanentlyDenied) { + // iOS 特性:如果你之前点过“不允许”,之后再请求都会直接进这里 + isLocationPermissionGranted.value = false; + // 引导用户去设置页面开启 + openAppSettings(); + } + else { + // 第一次被拒绝,或者其他情况 + isLocationPermissionGranted.value = false; + showErrorToast('需要定位权限才能显示您的位置'); + } + + } + + // 开启定位监听 + void _startLocationTracking() async { + // 再次检查服务是否开启 + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + return; + } + + const LocationSettings locationSettings = LocationSettings( + accuracy: LocationAccuracy.high, + distanceFilter: 50, // 移动更新范围 + ); + + // 先获取一次当前位置,用于快速初始化中心 + Geolocator.getCurrentPosition().then((position) { + _lastKnownPosition = position; + _syncLocationToMap(position, isInit: true); + }); + + // 持续监听 + positionStream = Geolocator.getPositionStream(locationSettings: locationSettings) + .listen((Position position) { + _lastKnownPosition = position; + _syncLocationToMap(position, isInit: false); + }); + } + + // 将位置同步给 JS + void _syncLocationToMap(Position position, {required bool isInit}) { + if (webViewController == null) return; + + // 如果是第一次定位,或者 WebView 刚加载完且从未设置过中心 + if (isInit || !_hasInitializedMapCenter) { + webViewController!.evaluateJavascript( + source: "initLocation(${position.latitude}, ${position.longitude})" + ); + _hasInitializedMapCenter = true; + } else { + // 后续只更新图标位置,不强行移动地图中心(防止用户拖动地图看别处时被拉回) + webViewController!.evaluateJavascript( + source: "updateMyLocation(${position.latitude}, ${position.longitude}, ${position.heading})" + ); + } + } + + // WebView 加载完成回调 + void onWebViewLoadStop() { + // 页面加载完了,如果我们已经拿到了定位数据,立刻设置地图中心 + if (_lastKnownPosition != null) { + _syncLocationToMap(_lastKnownPosition!, isInit: true); + } + + // 如果业务需要,可以在这里加载默认的推荐路径 + // loadRecommendedRoute(); + } + + // 模拟:获取你的后台推荐路径 + void loadRecommendedRoute() { + // 示例数据 + List> routePoints = [ + [116.397428, 39.90923], + [116.398000, 39.90950], + [116.400000, 39.91000], + ]; + + String jsonPoints = jsonEncode(routePoints); + webViewController?.evaluateJavascript(source: "drawCustomRoute($jsonPoints)"); + } +} \ No newline at end of file diff --git a/ln_jq_app/lib/pages/c_page/map/view.dart b/ln_jq_app/lib/pages/c_page/map/view.dart index f4b8f8a..3a14a66 100644 --- a/ln_jq_app/lib/pages/c_page/map/view.dart +++ b/ln_jq_app/lib/pages/c_page/map/view.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'controller.dart'; @@ -6,11 +6,32 @@ import 'controller.dart'; class MapPage extends GetView { const MapPage({super.key}); - // 主视图 Widget _buildView() { - return [ - TextX.titleLarge('地图'), - ].toColumn(mainAxisSize: MainAxisSize.min).center(); + return Stack( + children: [ + InAppWebView( + // 确保 pubspec.yaml 中声明了 assets/html/map.html + initialFile: 'assets/html/map.html', + initialSettings: InAppWebViewSettings( + isInspectable: true, + geolocationEnabled: true, + // 允许 JS 弹窗 (Alert) 用于调试 + javaScriptCanOpenWindowsAutomatically: true, + ), + onWebViewCreated: (c) { + controller.webViewController = c; + }, + onLoadStop: (c, url) { + // 通知 Controller 页面加载完毕 + controller.onWebViewLoadStop(); + }, + onConsoleMessage: (controller, consoleMessage) { + // 方便在 Flutter 控制台看 JS 日志 + print("JS Log: ${consoleMessage.message}"); + }, + ), + ], + ); } @override diff --git a/ln_jq_app/pubspec.lock b/ln_jq_app/pubspec.lock index bf7a574..18e7f11 100644 --- a/ln_jq_app/pubspec.lock +++ b/ln_jq_app/pubspec.lock @@ -289,6 +289,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3+4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -302,6 +310,70 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.0.5" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.0" flutter_lints: dependency: "direct dev" description: @@ -373,6 +445,70 @@ packages: description: flutter source: sdk version: "0.0.0" + geoclue: + dependency: transitive + description: + name: geoclue + sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.1" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" + url: "https://pub.flutter-io.cn" + source: hosted + version: "14.0.2" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.13" + geolocator_linux: + dependency: transitive + description: + name: geolocator_linux + sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.3" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.1.3" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.5" get: dependency: transitive description: @@ -397,6 +533,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.8" html: dependency: transitive description: @@ -994,6 +1138,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.1.4" + uuid: + dependency: transitive + description: + name: uuid + sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.5.2" vector_graphics: dependency: transitive description: diff --git a/ln_jq_app/pubspec.yaml b/ln_jq_app/pubspec.yaml index b2f240f..5ae1ee7 100644 --- a/ln_jq_app/pubspec.yaml +++ b/ln_jq_app/pubspec.yaml @@ -49,7 +49,8 @@ dependencies: zxing_lib: ^1.1.4 flutter_pdfview: 1.3.2 #显示pdf photo_view: ^0.15.0 #操作图片 - + flutter_inappwebview: ^6.1.5 # WebView插件 + geolocator: ^14.0.2 # 获取精确定位 dev_dependencies: flutter_test: @@ -67,4 +68,5 @@ flutter: assets: - assets/images/ + - assets/html/