From edbacc502ba41b2e20c9b55bc1f90c4caf6fa4f4 Mon Sep 17 00:00:00 2001 From: userGyl Date: Fri, 16 Jan 2026 17:25:52 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=E7=BA=BF=E4=B8=8A=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/lib/common/styles/theme.dart | 4 ++-- ln_jq_app/lib/main.dart | 7 +++++-- ln_jq_app/lib/pages/login/view.dart | 26 +++++++++++++++----------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ln_jq_app/lib/common/styles/theme.dart b/ln_jq_app/lib/common/styles/theme.dart index 767c678..20992cd 100644 --- a/ln_jq_app/lib/common/styles/theme.dart +++ b/ln_jq_app/lib/common/styles/theme.dart @@ -8,11 +8,11 @@ class AppTheme { static const Color themeColor = Color(0xFF0c83c3); //是否开放域名切换 - static const bool is_show_host = true; + static const bool is_show_host = false; //http://192.168.110.222:8080/ //http://192.168.110.44:8080/ - static String test_service_url = "https://beta-esg.api.lnh2e.com/"; + static String test_service_url = "http://47.101.201.13:8443/api/"; static const String release_service_url = ""; //加氢站相关查询 diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index 1a5f1d1..6237ac5 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -15,7 +15,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); WidgetsBinding widgetsBinding = await init( - isDebug: true, + isDebug: false, logTag: '小羚羚', supportedLocales: [Locale('zh', 'CN')], ); @@ -31,7 +31,7 @@ void main() async { // 设计稿尺寸 单位:dp designSize: const Size(390, 844), // Getx Log - enableLog: true, + enableLog: false, // 默认的跳转动画 defaultTransition: Transition.rightToLeft, // 主题模式 @@ -74,6 +74,9 @@ void initHttpSet() { // 设置全局响应处理器 HttpService.to.setOnResponseHandler((response) async { try { + if (response.data == null) { + return '服务繁忙,稍后重试'; + } final baseModel = BaseModel.fromJson(response.data); if (baseModel.code == 0 || baseModel.code == 200) { diff --git a/ln_jq_app/lib/pages/login/view.dart b/ln_jq_app/lib/pages/login/view.dart index 37d6f8f..55e59a9 100644 --- a/ln_jq_app/lib/pages/login/view.dart +++ b/ln_jq_app/lib/pages/login/view.dart @@ -208,18 +208,22 @@ class _LoginPageState extends State with SingleTickerProviderStateMix addAlias(phone); //登录后查询已绑定车辆信息 - var carInfo = await HttpService.to.get( - "appointment/driver/getTruckInfoByDriver?phone=$phone", - ); - if (carInfo != null) { - var carInforesult = BaseModel.fromJson(carInfo.data); - if (carInforesult.data != null) { - final vehicle = VehicleInfo.fromJson( - carInforesult.data as Map, - ); - //保存使用 - await StorageService.to.saveVehicleInfo(vehicle); + try { + var carInfo = await HttpService.to.get( + "appointment/driver/getTruckInfoByDriver?phone=$phone", + ); + if (carInfo != null) { + var carInforesult = BaseModel.fromJson(carInfo.data); + if (carInforesult.data != null) { + final vehicle = VehicleInfo.fromJson( + carInforesult.data as Map, + ); + //保存使用 + await StorageService.to.saveVehicleInfo(vehicle); + } } + } catch (e) { + Logger.d("暂时不处理 查询车辆信息失败的情况"); } //页面操作 From f7929154292cbf880b3c4781b70effa8be3936a5 Mon Sep 17 00:00:00 2001 From: userGyl Date: Fri, 16 Jan 2026 17:47:53 +0800 Subject: [PATCH 02/19] bugfix --- ln_jq_app/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index 6237ac5..96ae102 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -75,7 +75,7 @@ void initHttpSet() { HttpService.to.setOnResponseHandler((response) async { try { if (response.data == null) { - return '服务繁忙,稍后重试'; + return null; } final baseModel = BaseModel.fromJson(response.data); if (baseModel.code == 0 || baseModel.code == 200) { From 45f5035d1b25978f709f66caf7f868eb97f13cba Mon Sep 17 00:00:00 2001 From: userGyl Date: Mon, 19 Jan 2026 10:13:37 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E6=9B=B4=E6=8D=A2logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/res/mipmap-xhdpi/logo.jpg | Bin 6099 -> 0 bytes .../app/src/main/res/mipmap-xhdpi/logo.png | Bin 0 -> 2765 bytes .../AppIcon.appiconset/Contents.json | 18 +++++++++--------- .../Icon-App-1024x1024@1x.png | Bin 55707 -> 21260 bytes .../AppIcon.appiconset/Icon-App-120x120 1.jpg | Bin 4122 -> 0 bytes .../AppIcon.appiconset/Icon-App-120x120 1.png | Bin 0 -> 1953 bytes .../AppIcon.appiconset/Icon-App-120x120.jpg | Bin 4122 -> 0 bytes .../AppIcon.appiconset/Icon-App-120x120.png | Bin 0 -> 1953 bytes .../AppIcon.appiconset/Icon-App-180.jpg | Bin 6099 -> 0 bytes .../AppIcon.appiconset/Icon-App-180.png | Bin 0 -> 2765 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 509 -> 465 bytes .../Icon-App-20x20@2x 1.png | Bin 0 -> 849 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 848 -> 849 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1513 -> 1115 bytes .../AppIcon.appiconset/Icon-App-29x29 1.png | Bin 0 -> 613 bytes .../AppIcon.appiconset/Icon-App-29x29.png | Bin 0 -> 613 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 707 -> 0 bytes .../Icon-App-29x29@2x 1.png | Bin 0 -> 1109 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1135 -> 1109 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 2683 -> 1501 bytes .../AppIcon.appiconset/Icon-App-76x76.png | Bin 0 -> 1369 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 2333 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 4538 -> 2365 bytes .../AppIcon.appiconset/Icon-App-80x80.jpg | Bin 2663 -> 0 bytes .../AppIcon.appiconset/Icon-App-80x80.png | Bin 0 -> 1391 bytes .../Icon-App-83.5x83.5@2x.png | Bin 5141 -> 2642 bytes 26 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.jpg create mode 100644 ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120 1.jpg create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120 1.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.jpg create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.jpg create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.png create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29 1.png create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x 1.png create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.jpg create mode 100644 ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.png diff --git a/ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.jpg b/ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.jpg deleted file mode 100644 index 0e5324be26e8061149034bd1b79e58a481a3bd65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6099 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 diff --git a/ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.png b/ln_jq_app/android/app/src/main/res/mipmap-xhdpi/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1231afa928477ca3f311a7ad15bb893de547df2c GIT binary patch literal 2765 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 literal 55707 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%0DMJ5VG*KUf3qOo$LWQCX^d{ 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 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120 1.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120 1.png new file mode 100644 index 0000000000000000000000000000000000000000..c92124911ea0141752d556f60b9434b83a62fe65 GIT binary patch literal 1953 zcmb_d`8OMg8clmF!FVEVR5ec}$ixT+ElOJrLZTAOX;oUWD^=P&``&3#i5RVTVhBOd zq9T^*bdXp&mY0epw1!5BN^Na1Xf4t4^naLh?)~n$_k2Hn=X~eVJP0o8syeCw06-mw zb@DpY#BT&D9nNzhR%3^vLdFtf006aP-*^O2QmTCz9*OaCaR4+9LzfSYLKqs41^}8L zs_h3V0szWZI4AU##3P@|@Zr8!j}N$4!zqvI;wybVZaI=e$9~X4mt4UZQ)%2&_Ti7Y zaG%I})Ak6oS9DyeJ^a)=TYO{=xNDi*~y4u*HT|U;pJTF@RKtJ-f>g6J@;Nba><#gj~V~$Z#uO?;)emMBe6c-o9%>7aEtc0bvRb!vc z9v^6a?2~CPKhWe#>*|bl;BP0UODh@(W@Kzn%)kXM7iS_+^5Q`FZCv$Eo29Jf)s-BF z)%|cbn@uoqGV*D0yJJ=eR`4@tLR39f7J@IQq`+aWJxdnCg!4KA#$wvUz~oXm1zZ*& zv}o({C4dY@qRP>8ub239;5=676GaW5&k1jLDmg(8dQ)CA9;(m{Lj zJq~kFBoax>&1nik3mO7mTG{WVMOwWSLl1{1(kn7Hqun)N&C5k3qV z7Hlls)K!F_e)dEBB8|i2o1`Gx>-A9&iXPECRg{$hWbRivZn4CW43*{}(f3p-DAbd> z+ahybkcpHpBf|_rHMd#$EmZl?T3#;bMd#Kge6iu{hJIYvtow;oQA6lg!iWKJjKxQGe|-nU3%ZUvb1BD*`3eI z@~UrEdB@URp4srM?LrWDx2Z_JJvqSrlV_ z)Oalx5xunDlXA?B2Oo|t``?3KYeCXigeXcvq{JD>cXNFSKfYD!s|AZLM!n=DTWCT# zsCQiRaAGDqX5nEgnfNOG1F87Gn9qs+oD&j>%A3O_zRP-$F@018^1XNMG-~iLa32QZmh;@Oq)5mwfT}<-uTM|Ex5&1#cLW~9b||Ubzl)ST z-azbJO0b5J8LdxS3pSh>UtQVdOXp7hTD<|caboDttxrnG!AAw7{GiN91wBH`;pZUv zZjCGHxu9gLwbCdPIJTWM{d9qSmSXem)Yjb%L`sMs{bgZ%heum3wkfuDc4!01~+)hV3ZL(aUgw0JUA#5wap44w}=K)q?57pb~*w#b-uX= zqO<(F773jBws1JEDdb5%wDiK=aCG~?iPlGj0q^Q9V;5c|MQ0U#=6+byS74qYzjJhu zvg()nU(3|OdPbfUZyLMgjRsvB!{(nsIG3l>yr-K=gSwMwU;e6rC&7~J&||+)F{bmV zoe;>WxcBPUb8t$UL_wKe5AnyYI*=V>yLc3>Fy0E2<6|3b)J!Y<>x%T(39=@bpMD*LBzGedE^9S*Tqf+pF)QtSgI3S~ c`G>J-{X?ij?-C>A)nTIoa2SG9qeB4Y|0_qYSO5S3 literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.jpg b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.jpg deleted file mode 100644 index 4b43452a43dee4653936d9fb26ca7c197391aa47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4122 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 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..c92124911ea0141752d556f60b9434b83a62fe65 GIT binary patch literal 1953 zcmb_d`8OMg8clmF!FVEVR5ec}$ixT+ElOJrLZTAOX;oUWD^=P&``&3#i5RVTVhBOd zq9T^*bdXp&mY0epw1!5BN^Na1Xf4t4^naLh?)~n$_k2Hn=X~eVJP0o8syeCw06-mw zb@DpY#BT&D9nNzhR%3^vLdFtf006aP-*^O2QmTCz9*OaCaR4+9LzfSYLKqs41^}8L zs_h3V0szWZI4AU##3P@|@Zr8!j}N$4!zqvI;wybVZaI=e$9~X4mt4UZQ)%2&_Ti7Y zaG%I})Ak6oS9DyeJ^a)=TYO{=xNDi*~y4u*HT|U;pJTF@RKtJ-f>g6J@;Nba><#gj~V~$Z#uO?;)emMBe6c-o9%>7aEtc0bvRb!vc z9v^6a?2~CPKhWe#>*|bl;BP0UODh@(W@Kzn%)kXM7iS_+^5Q`FZCv$Eo29Jf)s-BF z)%|cbn@uoqGV*D0yJJ=eR`4@tLR39f7J@IQq`+aWJxdnCg!4KA#$wvUz~oXm1zZ*& zv}o({C4dY@qRP>8ub239;5=676GaW5&k1jLDmg(8dQ)CA9;(m{Lj zJq~kFBoax>&1nik3mO7mTG{WVMOwWSLl1{1(kn7Hqun)N&C5k3qV z7Hlls)K!F_e)dEBB8|i2o1`Gx>-A9&iXPECRg{$hWbRivZn4CW43*{}(f3p-DAbd> z+ahybkcpHpBf|_rHMd#$EmZl?T3#;bMd#Kge6iu{hJIYvtow;oQA6lg!iWKJjKxQGe|-nU3%ZUvb1BD*`3eI z@~UrEdB@URp4srM?LrWDx2Z_JJvqSrlV_ z)Oalx5xunDlXA?B2Oo|t``?3KYeCXigeXcvq{JD>cXNFSKfYD!s|AZLM!n=DTWCT# zsCQiRaAGDqX5nEgnfNOG1F87Gn9qs+oD&j>%A3O_zRP-$F@018^1XNMG-~iLa32QZmh;@Oq)5mwfT}<-uTM|Ex5&1#cLW~9b||Ubzl)ST z-azbJO0b5J8LdxS3pSh>UtQVdOXp7hTD<|caboDttxrnG!AAw7{GiN91wBH`;pZUv zZjCGHxu9gLwbCdPIJTWM{d9qSmSXem)Yjb%L`sMs{bgZ%heum3wkfuDc4!01~+)hV3ZL(aUgw0JUA#5wap44w}=K)q?57pb~*w#b-uX= zqO<(F773jBws1JEDdb5%wDiK=aCG~?iPlGj0q^Q9V;5c|MQ0U#=6+byS74qYzjJhu zvg()nU(3|OdPbfUZyLMgjRsvB!{(nsIG3l>yr-K=gSwMwU;e6rC&7~J&||+)F{bmV zoe;>WxcBPUb8t$UL_wKe5AnyYI*=V>yLc3>Fy0E2<6|3b)J!Y<>x%T(39=@bpMD*LBzGedE^9S*Tqf+pF)QtSgI3S~ c`G>J-{X?ij?-C>A)nTIoa2SG9qeB4Y|0_qYSO5S3 literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.jpg b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.jpg deleted file mode 100644 index 0e5324be26e8061149034bd1b79e58a481a3bd65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6099 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 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-180.png new file mode 100644 index 0000000000000000000000000000000000000000..1231afa928477ca3f311a7ad15bb893de547df2c GIT binary patch literal 2765 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 Z5CDyJ>&32QgIfRq002ovPDHLkV1l&()<6IN diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x 1.png new file mode 100644 index 0000000000000000000000000000000000000000..a06e41376f15332629d83ca18fb4488935c06fbc GIT binary patch literal 849 zcmV-X1FrmuP)~J6W4flBWyYIc<_q|+v8Uyw)`(Tgb z33Q7m&@G-ow|D~GGL*oH@o_ld^Kq-wZgV+pb}i%`a?Oaz0lxUfL(|A*#~LN2F` zu-o+ONhU+`67e|6vsz53*6nu5K8^&cs;Zr48;KjYSzJ$LW5bcS-G%qL5@=MFk}Q)v z@g>{{^z~KR06jIyyr(C~{PRs!xmZb2;2!goo=cGk1X%7a=(l>UMxN1Pd+GBWd2nua zmb`JZ(cp5-EFgNTR;`k~5|U*2Tw4Mac8qp5v~7W@v)cY62e~Es*pWc7D#!hPvLRN_ zs53?6oh{AxaE4o%cZ%t=2hKq@Ldc9tE-w?WEJ_l&_kFd>UAKS#fb3R@iv^FJgmg3x zrdUF4*gL70viqp^bHLOiz3N(G9A z0vDUQauIIan&)Em*604x6T5J=f5dtslOgWfR3QG|irzDvQv&F-Q`tLQEFQiF^4&*V zO!>GCi8n8}SSm6Pxw$1SX4oV+Y(;S~)&zsZAuHuqBqlb2S+k%(5krAbvswOTCTumG zhCyIeHot!0V)#(;81uDt==}M~#qcG>JVSwN`8=uKxlqVf_3TsytG8A!lRUJ65yXS% zr>Egdvq=&IfdE*67KkSwa4|N3q1NK}%0wm72uDW`fq(Qc*b;~zl1@PjV0Y`QY}70_ z&xE18^bDLpju?;ADUX>yMGMRnS4iH=+bM7g5%^k`!SDBjU9fsF;b#t;MQj2oblI>8 z1~DQAu!5f&4S352aIe>cPN!qJK{7?Fg5sp`buP9VjlnS3{$TxIc>jyt;t6z%C(tdP bK)3t_IyX> literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 494a3cb68c542282a656a44dbc8b83b06e61368e..a06e41376f15332629d83ca18fb4488935c06fbc 100644 GIT binary patch delta 826 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 M07*qoM6N<$f(J7IL;wH) delta 1495 zcmV;|1t|L424#st<8+ z-?jq3bzI{0ebfCV99*?kP&`8?ljpG1!1k&)aBHBS7be2XA8CpR%K-bPuS4~P2Hxb} zZl0)$NTD{cO?w?KvF}p-cKCgWb-qDVzfqaPQUaf7ZiH7_6cwa6EDiyl^QnHL0xYB? z#Vig++<)t#)CLyTeuvP#$yC2zlv$WNP54GeKcLBTSW4jdiUP!!7f^valS&0`VkB2s z>KgpPel>DW9^nO^U~7l&G3H>B!cqfQ{$7h^1xe`a(HaFJd-5~uvn&HFbx9%= zgLekeuI<8A?KQM^cHrXmHl$P)q2r$}7LqJhWPi~TYbGfy6)+hotz8{x>1-e7aGf$0 z%jYd-f0r~IM_}F%WHeKb)J$0tYbF7UElC6{wORuLYIp=BAWJ=7W?{);JiB?!>NixA4fUz|T&bg@0P*7h=U_zY`5Cv?Lj}jwoBF+Re^aeVe;u zHRocc@1yYaLQz=k{RK>RNnAIWjvxC$+xsssjPljD@!8VV?8;3RK`vYCt>C>o6Roh2 z8f@606#tLdvSVoEn%8NQKUKM1%=K*ed_NYLj4*v8F&eI31i2yYN;+UPmf3(w?SCXS zl*`UuZo+eF`tIq_szfYte~~kW{vyhEog^CgUP_X&d8=!=rlAHwdGS<*8#m^_-P!g3 z4@|oNQ2+Q1RLn~Q&3d*U26=tpvZ#^_q*a%IRDe3wm(mXDX66Lrwl$d6KK6g2Zc7aR zt3yO_8ZwWU@y2`D!4Vw^MXV1gUw`Cj$8hInSlhV*iW<`Q0-VddE9p)>#)yR6MbDf5 zBz}%gXBRAT@lW8Qd=z(uBzX+WoncNPaW>;wcoEY}#=)=5IkrS4_O=gBU?O9e7FiAqrw&WPcwL6+Vip(%=;`Z4pWeH$wNRB6yEt)~VP4`RB)7@HqR1@xkqm6X&NoYHSz)tuvjvmL x3R|%A&5~MH*eu;_!6dT67VLbpq<-KO{tqO<7ka`&*<%0z002ovPDHLkV1m(G)R_PP diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29 1.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29 1.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8019b5b64a73a138d6b8ef9493491c01a4a163 GIT binary patch literal 613 zcmV-r0-F7aP)h?nO|Xt&VQtiXiM+~m1UTHKN%Hx00000NkvXXu0mjf%#jO5 literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29.png new file mode 100644 index 0000000000000000000000000000000000000000..ef8019b5b64a73a138d6b8ef9493491c01a4a163 GIT binary patch literal 613 zcmV-r0-F7aP)h?nO|Xt&VQtiXiM+~m1UTHKN%Hx00000NkvXXu0mjf%#jO5 literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index d892c496c8cdf99f533d88d2f86baf5d33fbf500..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 707 zcmV;!0zCbRP)Px#1am@3R0s$N2z&@+hyVZrZAnByR7gu>{0{^SbOwy0meMlBM}rq7bU%Fm0_O{G z@?Z`5AHRPw{P^<=EXTvf$-u(Qj5CG^25-UosSJ}2t%n;>=N`+@;1Q2v;DdKB7?hf0 z;9~ro+zj_?mongTAVEtNnxYsUy?+Ha&`w#8;XqCwilq|{u4O3NFdao~Uv@8pgNi;@ z-x9Qxsn7*QW1d|g!-T+W6tRXK3mKYrE=Cdi*T09n;6)EMkSW-LH(+iZ!=@|8sAK7Y zI~N(8rWT_Zwl1lWAwbs}Ma*GJ5yPRom+(dbvIe}tyWrGLhNR`)1mlXBcqiIYY;pCj zZ39ZGyzul6!^a& z7(N0miZgX%2+_A?IQ!%_L*tG`SmT{&OVQ&Bl>ZE*RTvHeEd>ERDJ6ylQDqDpE*}Lu z0^|S?z?WS>@_6GEJ+6>l3-TSvLQ?Z6K}*r|D9lpi0s>ba1&K2_l10AR!Bms9b zPM>}RmbZdc0T>ya513#c)FFyETzM1}?;rrm0h;1+4CT%dge`se?j?g_b2Nsf^CC+b z63pD;;<)lCs9<^c{w3Jb5PdraZ!HVLmR@{%m%*?n9mP^PK{22&m!XIWRQfY~0%jTH zpf9iwW&i~*s1N}a`e~Nl3|wp+ge?V?Fd$zb19V@4g0+x@}2bavAB-zU~s0N~O-<8oCT_$NYLUjr65fFZWF)la~8)P3UkWf^KF)*HOQ*c-*nbtt*pG zllyZ;=t7}DzVXe?O`)Gv7T8()R2BU{t_h`5FQ3h#epD7XS*2pJ{?CNwxDYCuPW=8m zp;m=tX>k$tZKnWX3oCeS3#AIla5RegLE*ssP6mVKhFcdz3(g_tcRmy%_v%er9?a zooB;b$c<=JXoER;WqDa>)A&X)KjYUr%YS?$_S*B1;5ZMhGxS$S2Q1;InTEOPn+lSP4pD)S&j z^JpL-v_a~>{8zF@>Q* zv2!aWw3nwIcE+HPgo(C+5qma;R@3bDyXg5#%spZ=<$0kEe85+PW$IcL5+@=TR^Fo` zsUic>#6()P8d4|}l7~b)87GDVim~~}sBL~^0=2>5fDsQ3k>{2a3WWsDnTXLuLTVyu zWx6=)sK`L8p#}#KN`VT6Xgk+a)MBk~XtMNycx_wT6n_w<stY3acXu;4q1q6L zJCeF4_Ty>!ZuEiezS)W}b*qw*vIBLiq0$o4xm}TfP^j!T<+4z>8ml5>XP%`H3WYRN zT@*{*YRG7wz0BMKt-4RLS>^^*8?u^bBLiXP7N}52HyH1n^vVWQ8=@}MfStRh3{tah z$7wR>9pNWlV8Q637jx2vG00000NkvXXu0mjf0^R%c literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index a32483e8ce90836b4ce83421232f318e84d848f8..3d206b97c94620912b6055d7877f0bf7e1c962c3 100644 GIT binary patch delta 1088 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 delta 2674 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 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 8f7c86a332dcf661e97dc0d01c34381ce348086b..b3f0ff185502271af64065c7df5d8ce94eed2514 100644 GIT binary patch literal 2365 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 literal 4538 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 M+Dp}PWyt6M0s9=<4gdfE diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.jpg b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.jpg deleted file mode 100644 index a8feb00f0ea7a40b29b39b70c23c2b3ca26e7560..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2663 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 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-80x80.png new file mode 100644 index 0000000000000000000000000000000000000000..c474e2a7f9fe6dc86f970bb1b635186d3e7ee4b6 GIT binary patch literal 1391 zcma)+`#Tc~7{@ovWs{A@R_VyjsN=AXo>R=@S!~uW7|A7z;)aLcz(*z&$0Oq zb*Yp5LQ11o+C6IG!hlwS#ifJ_7qkCJwZF zK4SOLKRA#JJ7nCaIh&gvvnP$KVqp~cES?*P&k^j5bLChYT^Ao2a@*$+qU7>V@Hyx}4--=HW&&`jag%?|C5GEC@&!W<>WIP3`vZt*AV5qp-6nV#tZnmn^l$ z$zt%D?IKq0eEVf1Iu+`OS5^Ci#g!G&*pTHtsBp;o3I@oNeo;Eae%%xxduxTv_c$=o zW|-9}v^hxNr8u6AU(^X;2IG96eS&(a=Jlvo1LR(8PT&ldm9f~$c=ycqr8`lyLrY~$CiZIJyv?|n_u3OVp1ZMlQ4O3#1{T+MSsU%8f zD1*HgMYhS-VaL)5nN6+l6<7zTWma8Ti&(^(i5gj;dqJ8_0KcycQ9P^p4r`9%-Yz{MU(^M4a;Eya z)6}#)KiR9#IDgv@ic7CQetFZ4JnbVpEHl>|pS%#)f$CwTMh&(XAa}N=V^5$CHV3z{ z3m+g$qf#BU-F4?pNTmog%qGyD;U*c#21VKiVZE>2n3%mBt3H#8F4&inhhW2%R%C{*q})YO;&_ zCrD5j7#$A^N(yR$bBT?~kC%J$%eJ@J3pZWE^b_g$I7_}$g38uomxV!3Bl1`iv#6MJ zk{k?S8Z$BHYH02ryrS#t(&-94+nBjEApuK)e^K*Vu5=I|3HDP^gKa0RE2sR}O6jcS z45& literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ln_jq_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index a00bd83e80a3d1f93f4ccf59d8c9c5182f51d208..e4e54babe8b845d3a83b470ad2e92b1e1bcdaa95 100644 GIT binary patch literal 2642 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 Date: Mon, 9 Mar 2026 08:53:34 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=20=E6=8E=A5=E5=85=A5=E5=9C=B0=E5=9B=BESD?= =?UTF-8?q?K?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/ios/Podfile | 6 +- ln_jq_app/ios/Podfile.lock | 70 ++- .../ios/Runner.xcodeproj/project.pbxproj | 57 +-- ln_jq_app/ios/Runner/AppDelegate.swift | 75 +++- ln_jq_app/ios/Runner/Info.plist | 30 +- ln_jq_app/ios/Runner/NativeFirstPage.swift | 66 +++ ln_jq_app/ios/Runner/Runner-Bridging-Header.h | 1 + ln_jq_app/lib/main.dart | 2 +- .../c_page/base_widgets/NativePageIOS.dart | 58 +++ .../lib/pages/c_page/base_widgets/view.dart | 3 +- ln_jq_app/lib/pages/home/controller.dart | 3 +- ln_jq_app/pubspec.lock | 420 ++++++++++-------- 12 files changed, 527 insertions(+), 264 deletions(-) create mode 100644 ln_jq_app/ios/Runner/NativeFirstPage.swift create mode 100644 ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart diff --git a/ln_jq_app/ios/Podfile b/ln_jq_app/ios/Podfile index 456cd48..466cfc9 100644 --- a/ln_jq_app/ios/Podfile +++ b/ln_jq_app/ios/Podfile @@ -31,8 +31,12 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe flutter_ios_podfile_setup target 'Runner' do - use_frameworks! +# use_frameworks! +use_frameworks! :linkage => :static + pod 'AMapNavIOSSDK' , :path => '../../../../demo/ANavDemo/' + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index 27b161b..f002c02 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -1,12 +1,25 @@ PODS: - AlicloudELS (1.0.3) - AlicloudPush (3.2.3): - - AlicloudELS (= 1.0.3) + - AlicloudELS (~> 1.0.3) - AlicloudUTDID (~> 1.0) - AlicloudUTDID (1.6.1) - aliyun_push_flutter (0.0.1): - AlicloudPush (< 4.0, >= 3.2.3) - Flutter + - AMapFoundation-NO-IDFA (1.8.2) + - AMapLocation-NO-IDFA (2.11.0): + - AMapFoundation-NO-IDFA (>= 1.8.0) + - AMapNavi-NO-IDFA (10.1.600): + - AMapFoundation-NO-IDFA (>= 1.8.2) + - AMapNavIOSSDK (0.1.0): + - AMapLocation-NO-IDFA + - AMapNavi-NO-IDFA + - AMapSearch-NO-IDFA + - Masonry + - MJExtension + - AMapSearch-NO-IDFA (9.7.4): + - AMapFoundation-NO-IDFA (>= 1.8.0) - connectivity_plus (0.0.1): - Flutter - device_info_plus (0.0.1): @@ -28,15 +41,14 @@ PODS: - FlutterMacOS - image_picker_ios (0.0.1): - Flutter + - Masonry (1.1.0) + - MJExtension (3.4.2) - mobile_scanner (7.0.0): - Flutter - FlutterMacOS - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - shared_preferences_foundation (0.0.1): @@ -47,6 +59,7 @@ PODS: DEPENDENCIES: - aliyun_push_flutter (from `.symlinks/plugins/aliyun_push_flutter/ios`) + - AMapNavIOSSDK (from `../../../../demo/ANavDemo/`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) @@ -57,7 +70,6 @@ DEPENDENCIES: - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -69,11 +81,19 @@ SPEC REPOS: - AlicloudELS - AlicloudPush trunk: + - AMapFoundation-NO-IDFA + - AMapLocation-NO-IDFA + - AMapNavi-NO-IDFA + - AMapSearch-NO-IDFA + - Masonry + - MJExtension - OrderedSet EXTERNAL SOURCES: aliyun_push_flutter: :path: ".symlinks/plugins/aliyun_push_flutter/ios" + AMapNavIOSSDK: + :path: "../../../../demo/ANavDemo/" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: @@ -94,8 +114,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/mobile_scanner/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" shared_preferences_foundation: @@ -105,25 +123,31 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AlicloudELS: fbf821383330465a5af84a033f36f263ae46ca41 - AlicloudPush: 95150880af380f64cf1741f5586047c17d36c1d9 + AlicloudPush: 52cbf38ffc20c07f039cbc72d5738745fd986215 AlicloudUTDID: 5d2f22d50e11eecd38f30bc7a48c71925ea90976 - aliyun_push_flutter: 0fc2f048a08687ef256c0cfdd72dd7a550ef3347 - connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd - device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 + aliyun_push_flutter: ab0bf7112ef3797f506770a7a9f47f004635a9f6 + AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05 + AMapLocation-NO-IDFA: 590fd42af0c8ea9eac26978348221bbc16be4ef9 + AMapNavi-NO-IDFA: 22edfa7d6a81d75c91756e31b6c26b7746152233 + AMapNavIOSSDK: 0cd6ec22ab6b6aba268028a5b580e18bb8066f7e + AMapSearch-NO-IDFA: 53b2193244be8f07f3be0a4d5161200236960587 + connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d + device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 - flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf - flutter_pdfview: 32bf27bda6fd85b9dd2c09628a824df5081246cf - geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e - image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 - mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29 + flutter_pdfview: 2e4d13ffb774858562ffbdfdb61b40744b191adc + geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd + image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b + Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 + MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8 + mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 - permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 + url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa -PODFILE CHECKSUM: 357c01ff4e7591871e8c4fd6462220a8c7447220 +PODFILE CHECKSUM: aba49f58e1bc68a5558fc761b5370b90e7cb7e2b COCOAPODS: 1.16.2 diff --git a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj index 1a103b2..55acb81 100644 --- a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj +++ b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj @@ -8,11 +8,12 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 307490676CE2A16C8D75B103 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 937F9432963895EF63BCCD38 /* Pods_RunnerTests.framework */; }; + 298D3D45379E4332D4A8A627 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95135D36941D5EF2C00065B2 /* Pods_Runner.framework */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 59E555C098DB12132BCE9F6E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6AF04C5CFFF0B4098EEDA799 /* Pods_Runner.framework */; }; + 3F21125D6B84D3CC58F3C574 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 85810788944AB2417549F45E /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 8420D0082F3D9F7E006DB6CC /* NativeFirstPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8420D0072F3D9F7E006DB6CC /* NativeFirstPage.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -49,13 +50,14 @@ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 4B58A54CFC9A912F2BA04FF2 /* 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 = ""; }; - 6AF04C5CFFF0B4098EEDA799 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6D3F89E22F04C32900A154AD /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; 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 = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8420D0072F3D9F7E006DB6CC /* NativeFirstPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeFirstPage.swift; sourceTree = ""; }; + 85810788944AB2417549F45E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 87773E6EB1B2C64DA1B1FA42 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 937F9432963895EF63BCCD38 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 95135D36941D5EF2C00065B2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 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; }; @@ -73,7 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 59E555C098DB12132BCE9F6E /* Pods_Runner.framework in Frameworks */, + 298D3D45379E4332D4A8A627 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -81,7 +83,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 307490676CE2A16C8D75B103 /* Pods_RunnerTests.framework in Frameworks */, + 3F21125D6B84D3CC58F3C574 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -152,6 +154,7 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 8420D0072F3D9F7E006DB6CC /* NativeFirstPage.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; @@ -160,8 +163,8 @@ E621C70ABD0685462494972D /* Frameworks */ = { isa = PBXGroup; children = ( - 6AF04C5CFFF0B4098EEDA799 /* Pods_Runner.framework */, - 937F9432963895EF63BCCD38 /* Pods_RunnerTests.framework */, + 95135D36941D5EF2C00065B2 /* Pods_Runner.framework */, + 85810788944AB2417549F45E /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -199,7 +202,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 590CF992B35CC61AF9AA4341 /* [CP] Embed Pods Frameworks */, AF570E8AAEEA12D52BD19B4E /* [CP] Copy Pods Resources */, ); buildRules = ( @@ -288,23 +290,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 590CF992B35CC61AF9AA4341 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -396,6 +381,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8420D0082F3D9F7E006DB6CC /* NativeFirstPage.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); @@ -491,7 +477,8 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; @@ -526,8 +513,6 @@ "-framework", "\"package_info_plus\"", "-framework", - "\"path_provider_foundation\"", - "-framework", "\"permission_handler_apple\"", "-framework", "\"shared_preferences_foundation\"", @@ -565,8 +550,6 @@ "-framework", "\"package_info_plus\"", "-framework", - "\"path_provider_foundation\"", - "-framework", "\"permission_handler_apple\"", "-framework", "\"shared_preferences_foundation\"", @@ -759,7 +742,8 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; @@ -794,8 +778,6 @@ "-framework", "\"package_info_plus\"", "-framework", - "\"path_provider_foundation\"", - "-framework", "\"permission_handler_apple\"", "-framework", "\"shared_preferences_foundation\"", @@ -833,8 +815,6 @@ "-framework", "\"package_info_plus\"", "-framework", - "\"path_provider_foundation\"", - "-framework", "\"permission_handler_apple\"", "-framework", "\"shared_preferences_foundation\"", @@ -864,7 +844,8 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; @@ -899,8 +880,6 @@ "-framework", "\"package_info_plus\"", "-framework", - "\"path_provider_foundation\"", - "-framework", "\"permission_handler_apple\"", "-framework", "\"shared_preferences_foundation\"", diff --git a/ln_jq_app/ios/Runner/AppDelegate.swift b/ln_jq_app/ios/Runner/AppDelegate.swift index 6266644..b71be5b 100644 --- a/ln_jq_app/ios/Runner/AppDelegate.swift +++ b/ln_jq_app/ios/Runner/AppDelegate.swift @@ -1,13 +1,86 @@ import Flutter import UIKit +/// +let kAMapKey = "key"; + + @main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - GeneratedPluginRegistrant.register(with: self) + + GeneratedPluginRegistrant.register(with: self) + + AMapNavSDKManager.shared().config(withKey: kAMapKey) + + // 注册平台视图工厂 + let registrar = self.registrar(forPlugin: "NativeFirstPagePlugin") + + let controller = window?.rootViewController as! FlutterViewController + let nativeViewFactory = NativeViewFactory(messenger: controller.binaryMessenger) + + registrar?.register( + nativeViewFactory, + withId: "NativeFirstPage" + ) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + + } + + + + +// 创建视图工厂 +class NativeViewFactory: NSObject, FlutterPlatformViewFactory { + private var messenger: FlutterBinaryMessenger + + init(messenger: FlutterBinaryMessenger) { + self.messenger = messenger + super.init() + } + + func create( + withFrame frame: CGRect, + viewIdentifier viewId: Int64, + arguments args: Any? + ) -> FlutterPlatformView { + return NativeFlutterView(frame: frame, viewId: viewId, args: args) + } + + func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { + return FlutterStandardMessageCodec.sharedInstance() + } +} + +class NativeFlutterView: NSObject, FlutterPlatformView { + private var _view: UIView + private var _nativeVC: UIViewController + + init(frame: CGRect, viewId: Int64, args: Any?) { + // 创建原生的 ViewController 视图 + let nativeVC = AMapNavSDKManager.shared().targetVC; +// let nativeVC = NativeFirstPage(); + + self._nativeVC = nativeVC + + print("---frame: \(frame)"); + + _view = nativeVC.view + _view.isUserInteractionEnabled = true + _view.frame = CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame)) + super.init() + } + + func view() -> UIView { + return _view + } +} + diff --git a/ln_jq_app/ios/Runner/Info.plist b/ln_jq_app/ios/Runner/Info.plist index 0126237..c3b5696 100644 --- a/ln_jq_app/ios/Runner/Info.plist +++ b/ln_jq_app/ios/Runner/Info.plist @@ -2,8 +2,6 @@ - - CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -16,6 +14,11 @@ $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 + CFBundleLocalizations + + zh-Hans + en + CFBundleName ln_jq_app CFBundlePackageType @@ -28,6 +31,10 @@ $(FLUTTER_BUILD_NUMBER) ITSAppUsesNonExemptEncryption + LSApplicationQueriesSchemes + + iosamap + LSRequiresIPhoneOS NSCameraUsageDescription @@ -44,6 +51,12 @@ 需要访问您的相册以选择二维码图片进行识别 UIApplicationSupportsIndirectInputEvents + UIBackgroundModes + + remote-notification + fetch + location + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -63,18 +76,5 @@ uses - - UIBackgroundModes - - remote-notification - fetch - - -CFBundleLocalizations - - zh-Hans - en - - diff --git a/ln_jq_app/ios/Runner/NativeFirstPage.swift b/ln_jq_app/ios/Runner/NativeFirstPage.swift new file mode 100644 index 0000000..04ee6cb --- /dev/null +++ b/ln_jq_app/ios/Runner/NativeFirstPage.swift @@ -0,0 +1,66 @@ +// +// NativeFirstPage.swift +// Runner +// +// Created by admin on 2026/2/9. +// + +import UIKit + +class NativeFirstPage: UIViewController { +var lable:UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + view.backgroundColor = .white + + // 创建原生UI + let label = UILabel() + label.text = "iOS 原生页面." + label.font = UIFont.systemFont(ofSize: 24, weight: .bold) + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + + let button = UIButton(type: .custom) + button.setTitle("点击原生按钮", for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 18) + button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + button.backgroundColor = .blue + + view.addSubview(label) + view.addSubview(button) + + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50), + + button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 30), + button.centerXAnchor.constraint(equalTo: view.centerXAnchor) + ]) + + self.lable = label + + } + + @objc func buttonTapped() { + self.lable.text = "click..."; + + // 原生按钮点击事件 + let alert = UIAlertController( + title: "原生弹窗", + message: "来自 iOS 原生的提示", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "确定", style: .default)) + present(alert, animated: true) + } + + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + view.backgroundColor = .orange + } + +} diff --git a/ln_jq_app/ios/Runner/Runner-Bridging-Header.h b/ln_jq_app/ios/Runner/Runner-Bridging-Header.h index 308a2a5..758fa21 100644 --- a/ln_jq_app/ios/Runner/Runner-Bridging-Header.h +++ b/ln_jq_app/ios/Runner/Runner-Bridging-Header.h @@ -1 +1,2 @@ #import "GeneratedPluginRegistrant.h" +#import diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index b2273f1..8f0a668 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -77,7 +77,7 @@ void initHttpSet() { return null; } else if (baseModel.code == 401) { await StorageService.to.clearLoginInfo(); - Get.offAll(() => const LoginPage()); + // Get.offAll(() => const LoginPage()); return baseModel.message; } else { return (baseModel.error.toString()).isEmpty diff --git a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart new file mode 100644 index 0000000..a21b0cc --- /dev/null +++ b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart @@ -0,0 +1,58 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'dart:io'; + +import 'package:flutter/services.dart'; + +class NativePageIOS extends StatelessWidget { + const NativePageIOS({super.key}); + + @override + Widget build(BuildContext context) { + if (Platform.isIOS) { + return Container( + // onTap: () => _handleTap(context), + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.width - 100, + // padding: EdgeInsetsGeometry.all(15), + color: Colors.red[100], + + child: UiKitView( + viewType: 'NativeFirstPage', // 与原生端注册的标识一致 + gestureRecognizers: >{}.toSet(), + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + creationParamsCodec: const StandardMessageCodec(), + layoutDirection: TextDirection.ltr, + ) + ); + } else { + return const Center(child: Text('not ios')); + } + } + + + void _handleTap(BuildContext context) { + print("页面被点击"); + _showDialog(context, 'Tip', '点击了'); + } + + + void _showDialog(BuildContext context, String title, String content) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(title), + content: Text(content), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('确定'), + ), + ], + ), + ); + } + +} \ No newline at end of file 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 55a3fcb..4e9db82 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 @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:ln_jq_app/common/login_util.dart'; +import 'package:ln_jq_app/pages/c_page/base_widgets/NativePageIOS.dart'; import 'package:ln_jq_app/pages/c_page/car_info/view.dart'; import 'package:ln_jq_app/pages/c_page/map/view.dart'; import 'package:ln_jq_app/pages/c_page/mine/view.dart'; @@ -33,7 +34,7 @@ class BaseWidgetsPage extends GetView { } List _buildPages() { - return [ReservationPage(), MapPage(), CarInfoPage(), MinePage()]; + return [ReservationPage(), NativePageIOS(), CarInfoPage(), MinePage()]; } // 自定义导航栏 (悬浮胶囊样式) diff --git a/ln_jq_app/lib/pages/home/controller.dart b/ln_jq_app/lib/pages/home/controller.dart index 7c339cb..4919c47 100644 --- a/ln_jq_app/lib/pages/home/controller.dart +++ b/ln_jq_app/lib/pages/home/controller.dart @@ -43,7 +43,8 @@ class HomeController extends GetxController with BaseControllerMixin { } } else { // 未登录,直接去登录页 - return LoginPage(); + return BaseWidgetsPage(); + // return LoginPage(); } } diff --git a/ln_jq_app/pubspec.lock b/ln_jq_app/pubspec.lock index d680450..e252a45 100644 --- a/ln_jq_app/pubspec.lock +++ b/ln_jq_app/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: aliyun_push_flutter sha256: fd1a13ab37f30274e1eaa9c0f68001bf268f8f2e1c83730b4520aa4dff46ce70 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.6" ansicolor: @@ -14,7 +14,7 @@ packages: description: name: ansicolor sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.3" archive: @@ -22,7 +22,7 @@ packages: description: name: archive sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.7" args: @@ -30,7 +30,7 @@ packages: description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" asn1lib: @@ -38,7 +38,7 @@ packages: description: name: asn1lib sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.6.5" async: @@ -46,7 +46,7 @@ packages: description: name: async sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.13.0" badges: @@ -54,7 +54,7 @@ packages: description: name: badges sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.2" boolean_selector: @@ -62,7 +62,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" characters: @@ -70,7 +70,7 @@ packages: description: name: characters sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.0" clock: @@ -78,15 +78,23 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" collection: dependency: transitive description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.19.1" connectivity_plus: @@ -94,7 +102,7 @@ packages: description: name: connectivity_plus sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5" connectivity_plus_platform_interface: @@ -102,7 +110,7 @@ packages: description: name: connectivity_plus_platform_interface sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.1" convert: @@ -110,23 +118,23 @@ packages: description: name: convert sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.2" cross_file: dependency: transitive description: name: cross_file - sha256: "701dcfc06da0882883a2657c445103380e53e647060ad8d9dfb710c100996608" - url: "https://pub.flutter-io.cn" + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + url: "https://pub.dev" source: hosted - version: "0.3.5+1" + version: "0.3.5+2" crypto: dependency: transitive description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.7" csslib: @@ -134,7 +142,7 @@ packages: description: name: csslib sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.2" cupertino_icons: @@ -142,23 +150,23 @@ packages: description: name: cupertino_icons sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.8" dbus: dependency: transitive description: name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" - url: "https://pub.flutter-io.cn" + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.12" decimal: dependency: transitive description: name: decimal sha256: fc706a5618b81e5b367b01dd62621def37abc096f2b46a9bd9068b64c1fa36d0 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.4" device_info_plus: @@ -166,7 +174,7 @@ packages: description: name: device_info_plus sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "10.1.2" device_info_plus_platform_interface: @@ -174,23 +182,23 @@ packages: description: name: device_info_plus_platform_interface sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.3" dio: dependency: transitive description: name: dio - sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 - url: "https://pub.flutter-io.cn" + sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25 + url: "https://pub.dev" source: hosted - version: "5.9.0" + version: "5.9.1" dio_web_adapter: dependency: transitive description: name: dio_web_adapter sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.1" dropdown_button2: @@ -198,7 +206,7 @@ packages: description: name: dropdown_button2 sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.9" encrypt: @@ -206,7 +214,7 @@ packages: description: name: encrypt sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.3" event_bus: @@ -214,7 +222,7 @@ packages: description: name: event_bus sha256: "1a55e97923769c286d295240048fc180e7b0768902c3c2e869fe059aafa15304" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.1" extended_image: @@ -222,7 +230,7 @@ packages: description: name: extended_image sha256: "69d4299043334ecece679996e47d0b0891cd8c29d8da0034868443506f1d9a78" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.1" extended_image_library: @@ -230,7 +238,7 @@ packages: description: name: extended_image_library sha256: e61dafd94400fff6ef7ed1523d445ff3af137f198f3228e4a3107bc5b4bec5d1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.6" fake_async: @@ -238,23 +246,23 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.flutter-io.cn" + sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c + url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" file: dependency: transitive description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.1" file_selector_linux: @@ -262,7 +270,7 @@ packages: description: name: file_selector_linux sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.4" file_selector_macos: @@ -270,7 +278,7 @@ packages: description: name: file_selector_macos sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.5" file_selector_platform_interface: @@ -278,7 +286,7 @@ packages: description: name: file_selector_platform_interface sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" file_selector_windows: @@ -286,7 +294,7 @@ packages: description: name: file_selector_windows sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.3+5" fixnum: @@ -294,7 +302,7 @@ packages: description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" flutter: @@ -307,7 +315,7 @@ packages: description: name: flutter_easyloading sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.5" flutter_inappwebview: @@ -315,7 +323,7 @@ packages: description: name: flutter_inappwebview sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5" flutter_inappwebview_android: @@ -323,23 +331,23 @@ packages: description: name: flutter_inappwebview_android sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" 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" + sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" flutter_inappwebview_ios: dependency: transitive description: name: flutter_inappwebview_ios sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_macos: @@ -347,7 +355,7 @@ packages: description: name: flutter_inappwebview_macos sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_platform_interface: @@ -355,7 +363,7 @@ packages: description: name: flutter_inappwebview_platform_interface sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0+1" flutter_inappwebview_web: @@ -363,7 +371,7 @@ packages: description: name: flutter_inappwebview_web sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_windows: @@ -371,7 +379,7 @@ packages: description: name: flutter_inappwebview_windows sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.6.0" flutter_lints: @@ -379,7 +387,7 @@ packages: description: name: flutter_lints sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.0" flutter_localizations: @@ -392,7 +400,7 @@ packages: description: name: flutter_native_splash sha256: "4fb9f4113350d3a80841ce05ebf1976a36de622af7d19aca0ca9a9911c7ff002" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.7" flutter_pdfview: @@ -400,7 +408,7 @@ packages: description: name: flutter_pdfview sha256: c0b2cc4ebf461a5a4bb9312a165222475a7d93845c7a0703f4abb7f442eb6d54 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.3" flutter_plugin_android_lifecycle: @@ -408,7 +416,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.33" flutter_screenutil: @@ -416,7 +424,7 @@ packages: description: name: flutter_screenutil sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.9.3" flutter_spinkit: @@ -424,7 +432,7 @@ packages: description: name: flutter_spinkit sha256: "77850df57c00dc218bfe96071d576a8babec24cf58b2ed121c83cca4a2fdce7f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.2.2" flutter_svg: @@ -432,7 +440,7 @@ packages: description: name: flutter_svg sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.3" flutter_test: @@ -450,7 +458,7 @@ packages: description: name: geoclue sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.1.1" geolocator: @@ -458,7 +466,7 @@ packages: description: name: geolocator sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "14.0.2" geolocator_android: @@ -466,7 +474,7 @@ packages: description: name: geolocator_android sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.2" geolocator_apple: @@ -474,7 +482,7 @@ packages: description: name: geolocator_apple sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.13" geolocator_linux: @@ -482,7 +490,7 @@ packages: description: name: geolocator_linux sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.3" geolocator_platform_interface: @@ -490,7 +498,7 @@ packages: description: name: geolocator_platform_interface sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.2.6" geolocator_web: @@ -498,7 +506,7 @@ packages: description: name: geolocator_web sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.1.3" geolocator_windows: @@ -506,7 +514,7 @@ packages: description: name: geolocator_windows sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.5" get: @@ -514,7 +522,7 @@ packages: description: name: get sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.7.3" get_storage: @@ -522,7 +530,7 @@ packages: description: name: get_storage sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.1" getx_scaffold: @@ -530,23 +538,39 @@ packages: description: name: getx_scaffold sha256: caf11b370c20840352230f50221bcef1454b30ec56cce10ba25741fbbdf0a806 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" gsettings: dependency: transitive description: name: gsettings sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.8" + hooks: + dependency: transitive + description: + name: hooks + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" html: dependency: transitive description: name: html sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.15.6" http: @@ -554,7 +578,7 @@ packages: description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.6.0" http_client_helper: @@ -562,7 +586,7 @@ packages: description: name: http_client_helper sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.0" http_parser: @@ -570,7 +594,7 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.1.2" image: @@ -578,7 +602,7 @@ packages: description: name: image sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.7.2" image_picker: @@ -586,39 +610,39 @@ packages: description: name: image_picker sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "5e9bf126c37c117cf8094215373c6d561117a3cfb50ebc5add1a61dc6e224677" - url: "https://pub.flutter-io.cn" + sha256: "518a16108529fc18657a3e6dde4a043dc465d16596d20ab2abd49a4cac2e703d" + url: "https://pub.dev" source: hosted - version: "0.8.13+10" + version: "0.8.13+13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.1" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" - url: "https://pub.flutter-io.cn" + sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + url: "https://pub.dev" source: hosted - version: "0.8.13+3" + version: "0.8.13+6" image_picker_linux: dependency: transitive description: name: image_picker_linux sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" image_picker_macos: @@ -626,7 +650,7 @@ packages: description: name: image_picker_macos sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2+1" image_picker_platform_interface: @@ -634,7 +658,7 @@ packages: description: name: image_picker_platform_interface sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.11.1" image_picker_windows: @@ -642,7 +666,7 @@ packages: description: name: image_picker_windows sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" intl: @@ -650,7 +674,7 @@ packages: description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.19.0" js: @@ -658,7 +682,7 @@ packages: description: name: js sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.2" leak_tracker: @@ -666,7 +690,7 @@ packages: description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -674,7 +698,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.10" leak_tracker_testing: @@ -682,7 +706,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.2" lints: @@ -690,15 +714,23 @@ packages: description: name: lints sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" lottie: dependency: transitive description: name: lottie sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.3.2" matcher: @@ -706,7 +738,7 @@ packages: description: name: matcher sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.12.17" material_color_utilities: @@ -714,23 +746,23 @@ packages: description: name: material_color_utilities sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.flutter-io.cn" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.0" mobile_scanner: @@ -738,7 +770,7 @@ packages: description: name: mobile_scanner sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.1.4" modal_bottom_sheet: @@ -746,23 +778,39 @@ packages: description: name: modal_bottom_sheet sha256: eac66ef8cb0461bf069a38c5eb0fa728cee525a531a8304bd3f7b2185407c67e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" + url: "https://pub.dev" + source: hosted + version: "0.17.4" nm: dependency: transitive description: name: nm sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.5.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" package_info_plus: dependency: transitive description: name: package_info_plus sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.1" package_info_plus_platform_interface: @@ -770,7 +818,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.1" path: @@ -778,7 +826,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.9.1" path_parsing: @@ -786,7 +834,7 @@ packages: description: name: path_parsing sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.0" path_provider: @@ -794,7 +842,7 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.5" path_provider_android: @@ -802,23 +850,23 @@ packages: description: name: path_provider_android sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.22" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" - url: "https://pub.flutter-io.cn" + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.0" path_provider_linux: dependency: transitive description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -826,7 +874,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" path_provider_windows: @@ -834,7 +882,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.0" permission_handler: @@ -842,7 +890,7 @@ packages: description: name: permission_handler sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.4.0" permission_handler_android: @@ -850,7 +898,7 @@ packages: description: name: permission_handler_android sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "12.1.0" permission_handler_apple: @@ -858,7 +906,7 @@ packages: description: name: permission_handler_apple sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "9.4.7" permission_handler_html: @@ -866,7 +914,7 @@ packages: description: name: permission_handler_html sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.1.3+5" permission_handler_platform_interface: @@ -874,7 +922,7 @@ packages: description: name: permission_handler_platform_interface sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.3.0" permission_handler_windows: @@ -882,7 +930,7 @@ packages: description: name: permission_handler_windows sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.1" petitparser: @@ -890,7 +938,7 @@ packages: description: name: petitparser sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.1" photo_view: @@ -898,7 +946,7 @@ packages: description: name: photo_view sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.15.0" platform: @@ -906,7 +954,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.6" plugin_platform_interface: @@ -914,7 +962,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.8" pointycastle: @@ -922,7 +970,7 @@ packages: description: name: pointycastle sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.9.1" posix: @@ -930,15 +978,23 @@ packages: description: name: posix sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.0.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" pull_to_refresh: dependency: "direct main" description: name: pull_to_refresh sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.0" rational: @@ -946,7 +1002,7 @@ packages: description: name: rational sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.3" shared_preferences: @@ -954,23 +1010,23 @@ packages: description: name: shared_preferences sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.4" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc" - url: "https://pub.flutter-io.cn" + sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f + url: "https://pub.dev" source: hosted - version: "2.4.18" + version: "2.4.20" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.6" shared_preferences_linux: @@ -978,7 +1034,7 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" shared_preferences_platform_interface: @@ -986,7 +1042,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" shared_preferences_web: @@ -994,7 +1050,7 @@ packages: description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.3" shared_preferences_windows: @@ -1002,7 +1058,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" sky_engine: @@ -1015,23 +1071,23 @@ packages: description: name: slider_captcha sha256: "0fc2e0e8af7bf0e7ece23b8213e6becf841dd7839a40ad4b2a5071eaf5135774" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.2" source_span: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.flutter-io.cn" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.2" stack_trace: dependency: transitive description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.12.1" stream_channel: @@ -1039,7 +1095,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.4" string_scanner: @@ -1047,7 +1103,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.1" term_glyph: @@ -1055,23 +1111,23 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" - url: "https://pub.flutter-io.cn" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.7" typed_data: dependency: transitive description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.0" universal_io: @@ -1079,7 +1135,7 @@ packages: description: name: universal_io sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.1" url_launcher: @@ -1087,7 +1143,7 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.2" url_launcher_android: @@ -1095,7 +1151,7 @@ packages: description: name: url_launcher_android sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.28" url_launcher_ios: @@ -1103,7 +1159,7 @@ packages: description: name: url_launcher_ios sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.6" url_launcher_linux: @@ -1111,7 +1167,7 @@ packages: description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.2" url_launcher_macos: @@ -1119,7 +1175,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -1127,23 +1183,23 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.flutter-io.cn" + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" url_launcher_windows: dependency: transitive description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.5" uuid: @@ -1151,7 +1207,7 @@ packages: description: name: uuid sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.5.2" vector_graphics: @@ -1159,7 +1215,7 @@ packages: description: name: vector_graphics sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.19" vector_graphics_codec: @@ -1167,23 +1223,23 @@ packages: description: name: vector_graphics_codec sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc - url: "https://pub.flutter-io.cn" + sha256: "201e876b5d52753626af64b6359cd13ac6011b80728731428fd34bc840f71c9b" + url: "https://pub.dev" source: hosted - version: "1.1.19" + version: "1.1.20" vector_math: dependency: transitive description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" vm_service: @@ -1191,7 +1247,7 @@ packages: description: name: vm_service sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "15.0.2" web: @@ -1199,7 +1255,7 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" win32: @@ -1207,7 +1263,7 @@ packages: description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.15.0" win32_registry: @@ -1215,7 +1271,7 @@ packages: description: name: win32_registry sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.5" xdg_directories: @@ -1223,7 +1279,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.0" xml: @@ -1231,7 +1287,7 @@ packages: description: name: xml sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.6.1" yaml: @@ -1239,9 +1295,9 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.3" sdks: - dart: ">=3.9.0 <4.0.0" - flutter: ">=3.35.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" From a24f41a8d5e88aaf53fc0aa150f2d4922e321395 Mon Sep 17 00:00:00 2001 From: xiaogg Date: Mon, 9 Mar 2026 09:38:22 +0800 Subject: [PATCH 05/19] =?UTF-8?q?fix:=E6=B7=BB=E5=8A=A0=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec | 50 + .../AMapNavIOSSDK.bundle/icon_close@2x.png | Bin 0 -> 1351 bytes .../AMapNavIOSSDK.bundle/icon_dingwei@2x.png | Bin 0 -> 4261 bytes .../AMapNavIOSSDK.bundle/icon_fanhui@2x.png | Bin 0 -> 1956 bytes .../AMapNavIOSSDK.bundle/icon_local@2x.png | Bin 0 -> 840 bytes .../Assets/PrivacyInfo.xcprivacy | 31 + .../Classes/Class/ABaseViewController.h | 24 + .../Classes/Class/ABaseViewController.m | 33 + .../Classes/Class/AMapHyStationModel.h | 79 ++ .../Classes/Class/AMapHyStationModel.m | 21 + .../Classes/Class/AMapNavSDKHeader.h | 12 + .../Classes/Class/AMapNavSDKManager.h | 31 + .../Classes/Class/AMapNavSDKManager.m | 72 ++ .../Classes/Class/ARoutePlaneController.h | 22 + .../Classes/Class/ARoutePlaneController.m | 930 ++++++++++++++++++ .../Classes/Class/ASearchAddressController.h | 22 + .../Classes/Class/ASearchAddressController.m | 232 +++++ .../Classes/Tools/AMapNavCommonUtil.h | 19 + .../Classes/Tools/AMapNavCommonUtil.m | 27 + .../Classes/Tools/AMapNavHttpUtil.h | 19 + .../Classes/Tools/AMapNavHttpUtil.m | 114 +++ .../Classes/Tools/AMapPrivacyUtility.h | 32 + .../Classes/Tools/AMapPrivacyUtility.m | 137 +++ .../Classes/Tools/NaviPointAnnotation.h | 22 + .../Classes/Tools/NaviPointAnnotation.m | 13 + .../Classes/Tools/SelectableOverlay.h | 24 + .../Classes/Tools/SelectableOverlay.m | 41 + ln_jq_app/ios/Podfile | 2 +- ln_jq_app/ios/Podfile.lock | 6 +- 29 files changed, 2011 insertions(+), 4 deletions(-) create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_close@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_dingwei@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_fanhui@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_local@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/PrivacyInfo.xcprivacy create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.m create mode 100755 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h create mode 100755 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec new file mode 100644 index 0000000..60e22d0 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec @@ -0,0 +1,50 @@ +# +# Be sure to run `pod lib lint AMapNavIOSSDK.podspec' to ensure this is a +# valid spec before submitting. +# +# Any lines starting with a # are optional, but their use is encouraged +# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html +# + +Pod::Spec.new do |s| + s.name = 'AMapNavIOSSDK' + s.version = '0.1.0' + s.summary = 'A short description of AMapNavIOSSDK.' + +# This description is used to generate tags and improve search results. +# * Think: What does it do? Why did you write it? What is the focus? +# * Try to keep it short, snappy and to the point. +# * Write the description between the DESC delimiters below. +# * Finally, don't worry about the indent, CocoaPods strips it! + + s.description = <<-DESC +TODO: Add long description of the pod here. + DESC + + s.homepage = 'https://github.com/xiaoshuai/AMapNavIOSSDK' + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { 'xiaoshuai' => 'xiaoshuai@net.cn' } + s.source = { :git => 'https://github.com/xiaoshuai/AMapNavIOSSDK.git', :tag => s.version.to_s } + # s.social_media_url = 'https://twitter.com/' + + s.ios.deployment_target = '12.0' + + s.source_files = 'AMapNavIOSSDK/Classes/**/*' + s.resource = 'AMapNavIOSSDK/**/*.bundle' + s.resource_bundles = { + 'AMapNavIOSSDKPrivacyInfo' => ['AMapNavIOSSDK/**/PrivacyInfo.xcprivacy'] + } + + # s.public_header_files = 'Pod/Classes/**/*.h' + # s.frameworks = 'UIKit', 'MapKit' + # s.dependency 'AFNetworking', '~> 2.3' + + s.dependency 'Masonry' + s.dependency 'MJExtension' + + s.dependency 'AMapNavi-NO-IDFA' + s.dependency 'AMapLocation-NO-IDFA' + s.dependency 'AMapSearch-NO-IDFA' + +end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_close@2x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_close@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc8e7b889e3a281e700cc7a769d25c766392fe3 GIT binary patch literal 1351 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 GFa1BC$`d&N literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_local@2x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/icon_local@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..185c78a856b2b90b0fbe49ed819ad8ea41759d85 GIT binary patch literal 840 zcmV-O1GoH%P)Px&0!c(cR9HvNmrHC8Q547j=YAEWDpbRw-^>+{3ekjkbf!hHkqC)L!k$D>3oJ;y z7PJx;SSTW4uZc%OBsL`;ovBAi2vLu?cfKwvlxP}6zk6hS9&NvAed=qbcR6$JIlucq z=iYlRA?86b$H(9Ykg{?yvpGdXlYpFonVDY_iH%A%HuR-(p9++g&K*-wkZ1-_+|N|C zb#|u9T3YVD?`?jc0JiNOCBjx_T+`ZH3c%zDB5d2eN`xiMIHt9??VkZGt8$_c<|#8J zjKR!Q%6pt+@E>N$q+2co9ujfd7%?pf8ec`t?^OZYcFz%E4S=&sdF%fr_%B;2-7^5z zF{55gunD0t*YI{Q3mI6aZV4^6H|3+qS!mh_?eYJM*9KGt&{Ry(>}nQo7XujstkE z)X?d`jm}?o-2g1BVzUsU4&Y{`zD)-neCz2@N~ac}UD2xWL8biN+5ct@k#firfXa+9 z)j`m7A`76Tq^hW}(7X(#0(iAj{)L{7GAqYr0AHDTpAcV8hc?Cx+dxG70Sslv@+c*w zbXEa$K1^*#hnV#4-JSMu?r#Mw%Q+wfg$38BlvfokrPBb=B4*yHwSTy)jcq$Si0BZ& z*Ol@Y_mYY`04j~)njrA^b_0;oZ4Fn?%=5JNL&K~gr5hGx5z*(-Z{9rm*wtYC_!*;^ zhkpRju9P=2x^|o@BDx)_pp-W*uK>1PKALDmTfYHfPr=V34EO7}0WQMUjt((7s|dq< zSeCO%2s$ya+mJU0fqydc8~|cIh%zd~dK71biS;rH0b;+7Gb%Xeh$v4D3D;}w=iZQH z0Om{}N<7O)OU9g@s`b6sQK#eJZAwGh*xT|DBG!jVbkmXFuY><>nBVngd;1P=U*#|o SFk3YM0000 + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + 0A2A.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + NSPrivacyCollectedDataTypes + + + diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.h new file mode 100644 index 0000000..062a4fe --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.h @@ -0,0 +1,24 @@ +// +// ABaseViewController.h +// ANavDemo +// +// Created by admin on 2026/2/5. +// + +#import +#import +#import "AMapNavCommonUtil.h" + +#define kRoutePlanBarHeight (self.navigationController.navigationBar.frame.size.height + UIApplication.sharedApplication.statusBarFrame.size.height + 0) + +#define kRoutePlanStatusBarHeight (UIApplication.sharedApplication.statusBarFrame.size.height + 0) + + + +NS_ASSUME_NONNULL_BEGIN + +@interface ABaseViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.m new file mode 100644 index 0000000..8aabf2b --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ABaseViewController.m @@ -0,0 +1,33 @@ +// +// ABaseViewController.m +// ANavDemo +// +// Created by admin on 2026/2/5. +// + +#import "ABaseViewController.h" + +@interface ABaseViewController () + +@end + +@implementation ABaseViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + self.view.backgroundColor = [UIColor whiteColor]; +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h new file mode 100644 index 0000000..2c1b0cc --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h @@ -0,0 +1,79 @@ +// +// AMapHyStationModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/2/11. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + { + "name": "嘉兴经开站", + "shortName": null, + "siteNo": null, + "city": null, + "address": "嘉兴市秀洲区岗山路272号", + "contact": "龚明伟", + "phone": "18888888888", + "type": null, + "coOpMode": null, + "booking": null, + "siteStatus": 0, + "startBusiness": "06:00:00", + "endBusiness": "22:00:00", + "billingMethod": null, + "term": null, + "remark": null, + "longitude": "120.75972800", + "latitude": "30.79962800" + } + */ +@interface AMapHyStationModel : NSObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy, nullable) NSString *shortName; +@property (nonatomic, copy, nullable) NSString *siteNo; +@property (nonatomic, copy, nullable) NSString *city; +@property (nonatomic, copy, nullable) NSString *address; +@property (nonatomic, copy, nullable) NSString *contact; +@property (nonatomic, copy, nullable) NSString *phone; +@property (nonatomic, copy, nullable) NSString *type; +@property (nonatomic, copy, nullable) NSString *coOpMode; +@property (nonatomic, strong, nullable) NSString * booking; +@property (nonatomic, assign) NSInteger siteStatus; +@property (nonatomic, copy, nullable) NSString *startBusiness; +@property (nonatomic, copy, nullable) NSString *endBusiness; +@property (nonatomic, copy, nullable) NSString *billingMethod; +@property (nonatomic, copy, nullable) NSString *term; +@property (nonatomic, copy, nullable) NSString *remark; +@property (nonatomic, copy, nullable) NSString *longitude; +@property (nonatomic, copy, nullable) NSString *latitude; + +@end + +/** + { + "code": 0, + "status": true, + "message": "success", + "data": [], + "time": "1770800256408", + "error": null + } + */ + +@interface AMapHyResponse : NSObject +@property (nonatomic, assign) NSInteger code; +@property (nonatomic, assign) NSInteger status; +@property (nonatomic, copy, nullable) NSString *message; +@property (nonatomic, copy, nullable) NSString *time; +@property (nonatomic, copy, nullable) NSString *error; + +@property(nonatomic , strong)NSArray * data; + +@end +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m new file mode 100644 index 0000000..b6c161f --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m @@ -0,0 +1,21 @@ +// +// AMapHyStationModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/2/11. +// + +#import "AMapHyStationModel.h" + +@implementation AMapHyStationModel + +@end + + +@implementation AMapHyResponse + ++ (NSDictionary *)mj_objectClassInArray { + return @{@"data" : AMapHyStationModel.class}; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h new file mode 100644 index 0000000..e2a6a10 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h @@ -0,0 +1,12 @@ +// +// AMapNavSDKHeader.h +// Pods +// +// Created by admin on 2026/2/10. +// + +#ifndef AMapNavSDKHeader_h +#define AMapNavSDKHeader_h + + +#endif /* AMapNavSDKHeader_h */ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h new file mode 100644 index 0000000..638593a --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h @@ -0,0 +1,31 @@ +// +// AMapNavSDKManager.h +// Pods +// +// Created by admin on 2026/2/10. +// + +#import + +#import "ARoutePlaneController.h" + +#define kAMapSDKDebugFlag + +NS_ASSUME_NONNULL_BEGIN + +@interface AMapNavSDKManager : NSObject + +@property (strong, nonatomic) UIWindow *window; + +@property (nonatomic , strong) NSString * localCity; +@property (nonatomic, copy) NSString * locationAddressDetail; + +@property (nonatomic , strong , readonly) UIViewController * targetVC; + ++ (instancetype)sharedManager; +- (void)configWithKey:(NSString*)key; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.m new file mode 100644 index 0000000..9f3378b --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.m @@ -0,0 +1,72 @@ +// +// AMapNavSDKManager.m +// Pods +// +// Created by admin on 2026/2/10. +// + +#import "AMapNavSDKManager.h" +#import "AMapPrivacyUtility.h" + +#import + +@interface AMapNavSDKManager () +@property (nonatomic , strong , readwrite) UIViewController * targetVC; +@end + +@implementation AMapNavSDKManager + ++ (instancetype)sharedManager { + static AMapNavSDKManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[AMapNavSDKManager alloc] init]; + }); + return manager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _targetVC = [ARoutePlaneController new]; + } + + return self; +} + + + +- (void)configWithKey:(NSString*)key { + if (1) { + /* + * 调用隐私合规处理方法 + */ +// [AMapPrivacyUtility handlePrivacyAgreeStatusIn:_targetVC]; +// + // 初始化高德导航SDK + [self configureAPIKey:key]; + + } +} + +- (UIViewController *)targetVC { + return _targetVC; +} + +#pragma mark - private +- (void)configureAPIKey:(NSString*)key { + if ([key length] == 0) + { + NSString *reason = [NSString stringWithFormat:@"apiKey为空,请检查key是否正确设置。"]; + + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:reason delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; + + [alert show]; + } + [AMapServices sharedServices].enableHTTPS = YES; + [AMapServices sharedServices].apiKey = (NSString *)key; +} + + + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h new file mode 100644 index 0000000..66d956a --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h @@ -0,0 +1,22 @@ +// +// ARoutePlaneController.h +// ANavDemo +// +// Created by admin on 2026/2/5. +// + +#import +#import "ABaseViewController.h" + +#import "SelectableOverlay.h" +#import "NaviPointAnnotation.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ARoutePlaneController : ABaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m new file mode 100644 index 0000000..4a09f4a --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m @@ -0,0 +1,930 @@ +// +// ARoutePlaneController.m +// ANavDemo +// +// Created by admin on 2026/2/5. +// + +#import "ARoutePlaneController.h" + +#import +#import +#import +#import + +#import "ASearchAddressController.h" + +#import "AMapNavSDKManager.h" + +#import "AMapPrivacyUtility.h" + +#define kRouteIndicatorViewHeight 64.f + +#import "AMapHyStationModel.h" +#import "AMapNavHttpUtil.h" + +@interface ARoutePlaneController () +@property (nonatomic, strong) UITextField *textField; + +@property (nonatomic, strong) MAMapView *mapView; +@property (nonatomic,strong) AMapLocationManager *locationService; //定位服务 + +/** + * 经纬度 + */ +@property (nonatomic, assign) double latitude; +@property (nonatomic, assign) double longitude; + + +@property (nonatomic, strong) UITextField *startTf; +@property (nonatomic, strong) UITextField *dstTf; +@property (nonatomic, strong) UIButton *navBtn; + +@property (nonatomic, strong) AMapPOI *startPoi; +@property (nonatomic, strong) AMapPOI *dstPoi; + +@property (nonatomic, strong) AMapNaviCompositeManager *compositeManager;//nav +@property (nonatomic, assign) BOOL calRouteSuccess; + +@property (nonatomic, strong) NSDictionary * currentCalRoutePaths;//当前规划的路线 +@property (nonatomic , assign)BOOL isStartNav;//开始导航 +@property (nonatomic, strong) NSArray * lastOverLays; + + +@property (nonatomic , strong)NSArray * hyStationArr;//站点数据 +@property (nonatomic , assign)BOOL startQueryCurrnetNodeFlag;//开始查询当前节点; + +@end + +@implementation ARoutePlaneController + +- (void)viewDidLoad { + [super viewDidLoad]; + _startQueryCurrnetNodeFlag = NO; + + [self observePrivacyStatus]; + [self checkPrivacyStatus]; + + //// +// [self.naviManager independentCalculateDriveRouteWithStartPOIInfo:startPOIInfo +// endPOIInfo:endPOIInfo +// wayPOIInfos:wayPOIInfos +// strategy:AMapNaviDrivingStrategyMultipleDefault +// callback:^(AMapNaviRouteGroup *routeGroup, NSError *error) { +// if (error == nil) { +// // 算路成功,routeGroup 包含路线数据 +// [self startNaviWithRoute:routeGroup]; +// } +// }]; + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + + [AMapPrivacyUtility handlePrivacyAgreeStatusIn:self]; + +} + +#pragma mark - request +-(void)requestHyListWithParms:(NSDictionary*)dic { + NSString * url = @"https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation"; + + /** + //汽车公园有数据 + "longitude": "121.30461400", + "latitude": "31.17321100" + */ +// NSDictionary * dic = @{@"longitude":@"121.16661700" , @"latitude":@"31.27981600"}; + + + [AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) { + AMapHyResponse * resp = [AMapHyResponse mj_objectWithKeyValues:data]; + if (resp.code == 0 && resp.data) { + NSArray * allData = resp.data; + NSArray * dst = allData; + NSInteger len = allData.count; + if (allData.count > len) { + dst = [resp.data subarrayWithRange:NSMakeRange(0, len)]; + } + + [self updateMapAnnotationWithData:dst]; + }else { + NSLog(@">>>>>>>请求站点:%@" ,resp.message); + } + + } failureHandler:^(NSError * _Nonnull error) { + NSLog(@">>>>>>>请求站点err:%@" ,error.debugDescription); + }]; +} + +-(void)requestHyDetailWithParms:(NSDictionary*)dic { + NSString * url = @"https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea"; + + [AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) { + AMapHyResponse * resp = [AMapHyResponse mj_objectWithKeyValues:data]; + if (resp.code == 0) { + NSDictionary * resData = data[@"data"]; + AMapHyStationModel * station = [AMapHyStationModel mj_objectWithKeyValues:resData]; + [self updateHeadAddressWithStation:station]; + }else { + NSLog(@">>>>>>>请求站点detail:%@" ,resp.message); + } + + } failureHandler:^(NSError * _Nonnull error) { + NSLog(@">>>>>>>请求站点err:%@" ,error.debugDescription); + }]; +} + + +-(void)updateHeadAddressWithStation:(AMapHyStationModel*)model { + + AMapPOI * aoi = [[AMapPOI alloc] init]; + + aoi.location = [AMapGeoPoint locationWithLatitude:[model.latitude doubleValue] longitude:[model.longitude doubleValue]]; + + aoi.name = model.name; + + self.dstPoi = aoi; + + ///地址栏 + [self updateUIWithData:aoi textField:self.dstTf]; + + + ///地图显示 + [self updateMapAnnotationWithData:@[model]]; +} + +-(void)updateMapAnnotationWithData:(NSArray *)dataArr { + self.hyStationArr = dataArr; + if (!(dataArr && dataArr.count > 0)) { + return; + } + + ///添加标注 + NSMutableArray * points = [NSMutableArray arrayWithCapacity:dataArr.count]; + for (AMapHyStationModel * model in dataArr) { + MAPointAnnotation *pointAnnotation = [[MAPointAnnotation alloc] init]; + if (!(model.latitude && model.longitude)) { + continue; + } + + pointAnnotation.coordinate = CLLocationCoordinate2DMake([model.latitude doubleValue], [model.longitude doubleValue]); + pointAnnotation.title = model.name; + [points addObject:pointAnnotation]; + } + + // 1. 先获取当前地图区域 +// MACoordinateRegion currentRegion = self.mapView.region; + + // 2. 添加标注但不改变地图显示 + [self.mapView addAnnotations:points]; + + // 保持地图中心点为当前位置 + if (self.latitude && self.longitude) { + [self.mapView setCenterCoordinate: CLLocationCoordinate2DMake(self.latitude, self.longitude) animated:YES]; + } + + // 3. 保持当前区域不变 +// [self.mapView setRegion:currentRegion animated:NO]; + + +} + +#pragma mark - +-(void)initSubview { + UITextField * startTf = [[UITextField alloc] init]; + startTf.borderStyle = UITextBorderStyleRoundedRect; + startTf.placeholder = @"起点"; + startTf.tag = 100; + startTf.delegate = self; + startTf.font = [UIFont systemFontOfSize:13]; + [self.view addSubview:startTf]; + + [startTf mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.mas_equalTo(self.view).offset(kRoutePlanStatusBarHeight + 35); + make.left.mas_equalTo(self.view).offset(5); + make.width.mas_equalTo(@120); + make.height.mas_equalTo(@32); + }]; + + self.startTf = startTf; + + UITextField * dstTf = [[UITextField alloc] init]; + dstTf.borderStyle = UITextBorderStyleRoundedRect; + dstTf.placeholder = @"终点"; + dstTf.tag = 200; + dstTf.delegate = self; + dstTf.font = [UIFont systemFontOfSize:13]; + + [self.view addSubview:dstTf]; + + [dstTf mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.mas_equalTo(startTf); + make.left.mas_equalTo(startTf.mas_right).offset(15); +// make.right.mas_equalTo(self.view).offset(-5); + make.width.height.mas_equalTo(startTf); + }]; + self.dstTf = dstTf; + + UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; + [btn setTitle:@"规划线路" forState:UIControlStateNormal]; + btn.backgroundColor = [UIColor whiteColor]; + btn.titleLabel.font = [UIFont systemFontOfSize:14]; + + btn.layer.borderColor = [UIColor blueColor].CGColor; + btn.layer.borderWidth = 1; + btn.layer.cornerRadius = 5; + + [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [btn addTarget:self action:@selector(calRoutePath) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:btn]; + [btn mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(dstTf.mas_right).offset(12); + make.top.mas_equalTo(startTf); + make.right.mas_equalTo(self.view).offset(-5); + make.height.mas_equalTo(@30); + }]; + + + UIButton * navBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + [navBtn setTitle:@"导航>" forState:UIControlStateNormal]; + navBtn.backgroundColor = [UIColor whiteColor]; + navBtn.titleLabel.font = [UIFont systemFontOfSize:14]; + + navBtn.layer.borderColor = [UIColor blueColor].CGColor; + navBtn.layer.borderWidth = 1; + navBtn.layer.cornerRadius = 6; + + [navBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [navBtn addTarget:self action:@selector(navAction) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:navBtn]; + [navBtn mas_makeConstraints:^(MASConstraintMaker *make) { +// make.left.equalTo(self.view).offset(12); +// make.centerX.equalTo(self.view); + make.right.equalTo(self.view).offset(-15); + make.bottom.equalTo(self.view).offset(-118); + make.height.mas_equalTo(@30); + make.width.mas_equalTo(@60); + }]; + + + [self.mapView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.view); +// make.top.equalTo(startTf.mas_bottom).offset(5); + make.top.equalTo(self.view).offset(0); +// make.bottom.equalTo(navBtn.mas_top).offset(-3); + make.bottom.equalTo(self.view).offset(0); + }]; + + [self.view bringSubviewToFront:navBtn]; +} + +- (void)initDriveManager +{ + //请在 dealloc 函数中执行 [AMapNaviDriveManager destroyInstance] 来销毁单例 + [[AMapNaviDriveManager sharedInstance] setDelegate:self]; +} + + +- (void)initMapView +{ + if (self.mapView == nil) + { + self.mapView = [[MAMapView alloc] initWithFrame:CGRectZero]; + [self.mapView setDelegate:self]; + self.mapView.showsUserLocation = YES; + self.mapView.userTrackingMode = MAUserTrackingModeFollowWithHeading; + self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度 + _mapView.showsScale= YES; + + CGFloat ze = self.mapView.zoomLevel; + self.mapView.zoomLevel = 9; + + // 2. 禁用所有不必要的动画和自动调整 +// self.mapView.autoresizesSubviews = NO; +// [self.mapView setShowsWorldMap:NO]; // 不显示世界地图 + + // 3. 固定缩放级别 +// [self.mapView setMinZoomLevel:6.0]; +// [self.mapView setMaxZoomLevel:20.0]; +// [self.mapView setZoomLevel:10.0 animated:NO]; + + + // 4. 禁用自动调整 +// [self.mapView setAutoCheckMapBoundary:NO]; + + [self.view addSubview:self.mapView]; + + if (@available(iOS 14.0, *)) { + // iOS14+ 需要额外处理 + CLAuthorizationStatus status = [[[CLLocationManager alloc] init] authorizationStatus]; + if (status == kCLAuthorizationStatusNotDetermined) { + [[[CLLocationManager alloc] init] requestWhenInUseAuthorization]; + } + } + + ///TEST +// MAPointAnnotation *pointAnnotation = [[MAPointAnnotation alloc] init]; +// pointAnnotation.coordinate = CLLocationCoordinate2DMake(31.19, 121.32); +// pointAnnotation.title = @"嘉兴经开站"; +// [_mapView addAnnotation:pointAnnotation]; +// +// MAPointAnnotation *pointAnnotation2 = [[MAPointAnnotation alloc] init]; +// pointAnnotation2.coordinate = CLLocationCoordinate2DMake(30.81669400, 120.94291800); +// pointAnnotation2.title = @"测试站点1"; +// [_mapView addAnnotation:pointAnnotation2]; + + + + UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; + [btn setImage:[AMapNavCommonUtil imageWithName:@"icon_local"] forState:UIControlStateNormal]; + btn.backgroundColor = [UIColor lightGrayColor]; + btn.titleLabel.font = [UIFont systemFontOfSize:14]; + btn.layer.cornerRadius = 20; + + [btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside]; + + [self.view addSubview:btn]; + [btn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.view).offset(-10); + make.width.height.equalTo(@40); + make.top.equalTo(self.view).offset(150); + }]; + + } +} + +-(void)updateUserLocalAction { + // 如果已经有位置,直接移动视角 + if (_mapView.userLocation.location) { + CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(self.latitude, self.longitude); + + [_mapView setCenterCoordinate:coord animated:YES]; +// [_mapView setZoomLevel:10 animated:YES]; + } else { + // 如果尚未获取到位置,进入跟踪模式等待回调 + [_mapView setUserTrackingMode:MAUserTrackingModeFollow animated:YES]; + } + +} + +- (void)initAnnotations +{ + NaviPointAnnotation *beginAnnotation = [[NaviPointAnnotation alloc] init]; + [beginAnnotation setCoordinate:CLLocationCoordinate2DMake(self.startPoi.location.latitude, self.startPoi.location.longitude)]; + beginAnnotation.title = @"起始点"; + beginAnnotation.navPointType = NaviPointAnnotationStart; + + [self.mapView addAnnotation:beginAnnotation]; + +// NaviPointAnnotation *endAnnotation = [[NaviPointAnnotation alloc] init]; +// [endAnnotation setCoordinate:CLLocationCoordinate2DMake(self.dstPoi.location.latitude, self.dstPoi.location.longitude)]; +// endAnnotation.title = @"终点"; +// endAnnotation.navPointType = NaviPointAnnotationEnd; +// +// [self.mapView addAnnotation:endAnnotation]; +} + + + + +- (AMapLocationManager *)locationService { + if (!_locationService) { + _locationService = [[AMapLocationManager alloc] init]; + _locationService.delegate = self; + _locationService.desiredAccuracy = kCLLocationAccuracyBest; // 最高精度模式 + _locationService.distanceFilter = 5; + _locationService.locatingWithReGeocode = YES; + } + return _locationService; +} + + + +- (void)dealloc { + [self.locationService stopUpdatingLocation]; + +} + +- (AMapNaviCompositeManager *)compositeManager { + + if (!_compositeManager) { + _compositeManager = [[AMapNaviCompositeManager alloc] init]; // 初始化 + _compositeManager.delegate = self; // 如果需要使用AMapNaviCompositeManagerDelegate的相关回调(如自定义语音、获取实时位置等),需要设置delegate + } + return _compositeManager; +} + +// 监听隐私状态变化 +- (void)observePrivacyStatus { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handlePrivacyUpdate) + name:@"ksAMapPrivacyDidUpdateNotification" // 自定义通知 + object:nil]; +} + +-(void)handlePrivacyUpdate { + [self checkPrivacyStatus]; + +} + +// 检查当前隐私状态 +- (void)checkPrivacyStatus { + BOOL hasAgreed = [[NSUserDefaults standardUserDefaults] boolForKey:@"usragreeStatus"]; + + if (hasAgreed) { + + /// 开启定位 + [self.locationService startUpdatingLocation]; +// [self.mapView reloadMap]; + + [self initMapView]; + [self initSubview]; + + [self initDriveManager]; + + } else { + + } +} + +#pragma mark - Action +///选择方式 +-(void)navAction { + [self showSelectNavType]; +} + +-(void)showSelectNavType { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"选择导航类型" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; + UIAlertAction *sure = [UIAlertAction actionWithTitle:@"SDK导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [self navigationType_sdk]; + }]; + UIAlertAction *sure2 = [UIAlertAction actionWithTitle:@"高德地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + + [self navigationType_app]; + }]; + + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + }]; + + [alert addAction:sure]; + [alert addAction:sure2]; + [alert addAction:cancel]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +-(void)navigationType_app { + + NSURL* scheme = [NSURL URLWithString:@"iosamap://"]; + BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:scheme]; + if (!canOpen) { + [self showAlertWithMessage:@"请先安装高德地图客户端"]; return; + } + + NSString *myLocationScheme = [NSString stringWithFormat:@"iosamap://navi?sourceApplication=ANavDemo&lat=31.2304&lon=121.4737&t=0&dev=1"]; + + NSString *encodedUrlString = [myLocationScheme stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + + NSURL *gaodeUrl = [NSURL URLWithString:encodedUrlString]; + + + [[UIApplication sharedApplication] openURL:gaodeUrl options:@{} completionHandler:^(BOOL res) { + + }]; + +} + +-(void)navigationType_sdk { + id delegate = [AMapNaviDriveManager sharedInstance].delegate; + if (!delegate) { + [AMapNaviDriveManager sharedInstance].delegate = self; + } + + + NSDictionary * routes = [AMapNaviDriveManager sharedInstance].naviRoutes; + if (!routes) { + NSLog(@"暂无路线信息!!!!!!!!!"); + self.isStartNav = YES; + [self calRoutePath]; + + return; + } + + + AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init]; + +// [config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeEnd location:[AMapNaviPoint locationWithLatitude:32.21 longitude:121.34] name:@"故宫22" POIId:nil]; + + [config setStartNaviDirectly:YES]; //直接进入导航界面 + [config setNeedCalculateRouteWhenPresent:NO];//不在算路 + [config setMultipleRouteNaviMode:NO];//直接单线路径导航 +// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; + + self.isStartNav = NO; + + [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; + +} + + +#pragma mark - 计算线路 +///计算线路 +-(void)calRoutePath { +// [self.mapView removeOverlays:self.mapView.overlays]; +// self.startTf.text = @"click calpath"; +// return; + + [self initAnnotations]; + + AMapNaviPoint * startPoint = [AMapNaviPoint locationWithLatitude:self.startPoi.location.latitude longitude:self.startPoi.location.longitude]; + + AMapNaviPoint * endPoint = [AMapNaviPoint locationWithLatitude:self.dstPoi.location.latitude longitude:self.dstPoi.location.longitude]; + + AMapNaviDrivingStrategy strategy = ConvertDrivingPreferenceToDrivingStrategy(0, + 0, + 0, + 0, + 0); + + id delegate = [AMapNaviDriveManager sharedInstance].delegate; + if (!delegate) { + [AMapNaviDriveManager sharedInstance].delegate = self; + } + + [[AMapNaviDriveManager sharedInstance] calculateDriveRouteWithStartPoints:@[startPoint] + endPoints:@[endPoint] + wayPoints:nil + drivingStrategy:strategy]; + +} + + +- (void)driveManagerOnCalculateRouteSuccess:(AMapNaviDriveManager *)driveManager +{ + NSLog(@"onCalculateRouteSuccess"); + //算路成功后显示路径 + [self showNaviRoutes]; +} + +- (void)showNaviRoutes +{ + if ([[AMapNaviDriveManager sharedInstance].naviRoutes count] <= 0) + { + return; + } + + self.lastOverLays = self.mapView.overlays; + [self.mapView removeOverlays:self.mapView.overlays]; +// [self.routeIndicatorInfoArray removeAllObjects]; + + self.currentCalRoutePaths = [AMapNaviDriveManager sharedInstance].naviRoutes; + + + NSInteger routeId = 0; + + //将路径显示到地图上 + for (NSNumber *aRouteID in [[AMapNaviDriveManager sharedInstance].naviRoutes allKeys]) + { + AMapNaviRoute *aRoute = [[[AMapNaviDriveManager sharedInstance] naviRoutes] objectForKey:aRouteID]; + int count = (int)[[aRoute routeCoordinates] count]; + + //添加路径Polyline + CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D)); + for (int i = 0; i < count; i++) + { + AMapNaviPoint *coordinate = [[aRoute routeCoordinates] objectAtIndex:i]; + coords[i].latitude = [coordinate latitude]; + coords[i].longitude = [coordinate longitude]; + } + + MAPolyline *polyline = [MAPolyline polylineWithCoordinates:coords count:count]; + + SelectableOverlay *selectablePolyline = [[SelectableOverlay alloc] initWithOverlay:polyline]; + [selectablePolyline setRouteID:[aRouteID integerValue]]; + + [self.mapView addOverlay:selectablePolyline]; + free(coords); + + routeId = [aRouteID integerValue]; + + } + + // 1. 先获取当前地图区域 + MACoordinateRegion currentRegion = self.mapView.region; + + [self.mapView showAnnotations:self.mapView.annotations animated:NO]; + + // 3. 保持当前区域不变 + [self.mapView setRegion:currentRegion animated:NO]; + + [self selectNaviRouteWithID:routeId]; + + ///如果已开始导航,直接进入导航 + if (self.isStartNav) { + [self navigationType_sdk]; + } + +} + +- (void)selectNaviRouteWithID:(NSInteger)routeID +{ + //在开始导航前进行路径选择 + if ([[AMapNaviDriveManager sharedInstance] selectNaviRouteWithRouteID:routeID]) + { + [self selecteOverlayWithRouteID:routeID]; + } + else + { + NSLog(@"路径选择失败!"); + } +} + +- (void)selecteOverlayWithRouteID:(NSInteger)routeID +{ + [self.mapView.overlays enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id overlay, NSUInteger idx, BOOL *stop) + { + if ([overlay isKindOfClass:[SelectableOverlay class]]) + { + SelectableOverlay *selectableOverlay = overlay; + + /* 获取overlay对应的renderer. */ + MAPolylineRenderer * overlayRenderer = (MAPolylineRenderer *)[self.mapView rendererForOverlay:selectableOverlay]; + + if (selectableOverlay.routeID == routeID) + { + /* 设置选中状态. */ + selectableOverlay.selected = YES; + + /* 修改renderer选中颜色. */ + overlayRenderer.fillColor = selectableOverlay.selectedColor; + overlayRenderer.strokeColor = selectableOverlay.selectedColor; + + /* 修改overlay覆盖的顺序. */ + [self.mapView exchangeOverlayAtIndex:idx withOverlayAtIndex:self.mapView.overlays.count - 1]; + } + else + { + /* 设置选中状态. */ + selectableOverlay.selected = NO; + + /* 修改renderer选中颜色. */ + overlayRenderer.fillColor = selectableOverlay.regularColor; + overlayRenderer.strokeColor = selectableOverlay.regularColor; + } + } + }]; +} + +#pragma mark - AMapLocationManagerDelegate +- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode +{ + if (!location) { + return; + } + self.latitude = location.coordinate.latitude; + self.longitude = location.coordinate.longitude; + + AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager]; + sdk.localCity = reGeocode.city; + sdk.locationAddressDetail = reGeocode.POIName; + + // 设置地图中心为用户位置 +// MACoordinateRegion region = MACoordinateRegionMake(location.coordinate, +// MACoordinateSpanMake(0.1, 0.1)); +// [self.mapView setRegion:region animated:YES]; + + + //更新出发点 + AMapPOI * aoi = [[AMapPOI alloc] init]; +#ifdef kAMapSDKDebugFlag + aoi.location = [AMapGeoPoint locationWithLatitude:31.23 longitude:121.48 ]; + aoi.name =@"人民大道185号"; +#else + aoi.location = [AMapGeoPoint locationWithLatitude:self.latitude longitude:self.longitude ]; + aoi.name = reGeocode.POIName; +#endif + + self.startPoi = aoi; + [self updateUIWithData:aoi textField:self.startTf]; + + //获取附近站点 + if (!self.startQueryCurrnetNodeFlag && reGeocode) { + self.startQueryCurrnetNodeFlag = YES; + NSString * province = reGeocode.province; + NSString * city = reGeocode.city; + NSString * district = reGeocode.district; + NSString * longitude = [NSString stringWithFormat:@"%f",self.longitude]; + NSString * latitude = [NSString stringWithFormat:@"%f",self.latitude]; + + if (province && city && district) { + NSDictionary * dic = @{@"province":province , @"city":city , @"district":district , @"longitude":longitude , @"latitude":latitude}; + + [self requestHyDetailWithParms:dic]; + } + + [self requestHyListWithParms:@{@"longitude":longitude , @"latitude":latitude}]; + } + + +} + +#pragma mark - MAMapView 渲染 + +- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id)annotation +{ + if ([annotation isKindOfClass:[NaviPointAnnotation class]]) + { + static NSString *annotationIdentifier = @"NaviPointAnnotationIdentifier"; + + MAPinAnnotationView *pointAnnotationView = (MAPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier]; + if (pointAnnotationView == nil) + { + pointAnnotationView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation + reuseIdentifier:annotationIdentifier]; + } + + pointAnnotationView.animatesDrop = NO; + pointAnnotationView.canShowCallout = YES; + pointAnnotationView.draggable = NO; + + NaviPointAnnotation *navAnnotation = (NaviPointAnnotation *)annotation; + + if (navAnnotation.navPointType == NaviPointAnnotationStart) + { + [pointAnnotationView setPinColor:MAPinAnnotationColorGreen]; + } + else if (navAnnotation.navPointType == NaviPointAnnotationEnd) + { + [pointAnnotationView setPinColor:MAPinAnnotationColorRed]; + } + + return pointAnnotationView; + } + + if ( [annotation isMemberOfClass:[MAPointAnnotation class]]) + { + MAUserLocation *user = (MAUserLocation *)annotation; + + static NSString *pointReuseIndentifier = @"pointReuseIndentifier"; + MAPinAnnotationView*annotationView = (MAPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier]; + if (annotationView == nil) + { + annotationView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier]; + } + annotationView.canShowCallout= YES; //设置气泡可以弹出,默认为NO + annotationView.animatesDrop = NO; //设置标注动画显示,默认为NO + annotationView.draggable = NO; //设置标注可以拖动,默认为NO + annotationView.pinColor = MAPinAnnotationColorPurple; + + // 设置自定义的气泡背景色 + if (@available(iOS 14.0, *)) { + // iOS 14+ 可以使用 tintColor + annotationView.tintColor = [UIColor systemBlueColor]; + } else { + // iOS 13 及以下 + annotationView.tintColor = [UIColor colorWithRed:0.1 green:0.6 blue:0.9 alpha:1.0]; + } + + return annotationView; + } + + return nil; +} + +- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id)overlay +{ + if ([overlay isKindOfClass:[SelectableOverlay class]]) + { + SelectableOverlay * selectableOverlay = (SelectableOverlay *)overlay; + id actualOverlay = selectableOverlay.overlay; + + MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:actualOverlay]; + + polylineRenderer.lineWidth = 8.f; + polylineRenderer.strokeColor = selectableOverlay.isSelected ? selectableOverlay.selectedColor : selectableOverlay.regularColor; + + return polylineRenderer; + } + + return nil; +} + +// 当地图添加完标注视图后调用 +- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views { + // 遍历所有被添加的标注视图 +# if 0 + for (MAAnnotationView *view in views) { + // 检查是否为需要的标注类型,例如大头针标注 + if ([view.annotation isMemberOfClass:[MAPointAnnotation class]]) { + // 延迟零点几秒执行,以确保视图添加动画完成(可选,但可使效果更平滑) + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + // 选中该标注,从而使其气泡弹出 + [mapView selectAnnotation:view.annotation animated:YES]; + }); + } + } +#endif +} + +- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view { + NSLog(@"didSelectAnnotationView: %s" , __func__); + +} + + +// 当标注被取消选中时调用 +- (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view { + if ([view.annotation isMemberOfClass:[MAPointAnnotation class]]) { + // 可以立即或稍作延迟后重新选中 +// [mapView selectAnnotation:view.annotation animated:NO]; + } +} + +//选中一个点 +- (void)mapView:(MAMapView *)mapView didAnnotationViewCalloutTapped:(MAAnnotationView *)view { + id pointAnnotation = view.annotation; + if ([pointAnnotation isMemberOfClass:MAPointAnnotation.class]) { + MAPointAnnotation *point = (MAPointAnnotation *)view.annotation; + + + NSLog(@"point: %@" , point.title); + + AMapPOI * aoi = [[AMapPOI alloc] init]; + + aoi.location = [AMapGeoPoint locationWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude]; + + aoi.name = point.title; + + self.dstPoi = aoi; + + [self updateUIWithData:aoi textField:self.dstTf]; + + } + + NSLog(@"didSelectAnnotationView: %s" , __func__); + + +} + +#pragma mark - AMapNaviCompositeManagerDelegate +- (void)compositeManager:(AMapNaviCompositeManager *)compositeManager didStartNavi:(AMapNaviMode)naviMode { + + +} + +- (void)compositeManager:(AMapNaviCompositeManager *)compositeManager onDriveStrategyChanged:(AMapNaviDrivingStrategy)driveStrategy { + NSLog(@"%s" , __func__ ); + +} + +#pragma mark - UITextFieldDelegate +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + ASearchAddressController * vc = [[ASearchAddressController alloc] init]; + + UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:vc]; + //UIModalPresentationOverFullScreen/UIModalPresentationFullScreen触发离开 + nav.modalPresentationStyle = UIModalPresentationOverFullScreen; + nav.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + + __weak typeof(self)weakSelf = self; + vc.selectAddressBlk = ^(AMapPOI * _Nonnull poi) { + [weakSelf updateUIWithData:poi textField:textField]; + }; + + [self presentViewController:nav animated:YES completion:^{ + + }]; + + return NO; +} + +-(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf { + BOOL isStart = tf.tag == 100; + tf.text = poi.name; + + if (isStart) { + self.startPoi = poi; + }else { + self.dstPoi = poi; + } + +} + +#pragma mark - tool + +-(void)showAlertWithMessage:(NSString *)msg { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:msg preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *sure = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + }]; + + [alert addAction:sure]; + + [self.navigationController presentViewController:alert animated:YES completion:nil]; + +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.h new file mode 100644 index 0000000..0f682c9 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.h @@ -0,0 +1,22 @@ +// +// ASearchAddressController.h +// ANavDemo +// +// Created by admin on 2026/2/6. +// + +#import "ABaseViewController.h" + +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@interface ASearchAddressController : ABaseViewController + +@property (nonatomic , copy) void(^selectAddressBlk)(AMapPOI * poi); + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m new file mode 100644 index 0000000..eb87923 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m @@ -0,0 +1,232 @@ +// +// ASearchAddressController.m +// ANavDemo +// +// Created by admin on 2026/2/6. +// + +#import "ASearchAddressController.h" +#import "AMapNavSDKManager.h" + +#import + +#import "AMapNavCommonUtil.h" + +@interface ASearchAddressController () + +@property (nonatomic , strong) UITableView *tableView; +@property (nonatomic , strong) UIBarButtonItem *rightItem; +@property (nonatomic ,strong)UIButton * backBtn; + +@property (nonatomic , strong) NSArray *dataArr; + +@property (nonatomic, strong) UITextField *inputAddressTf; +@property (nonatomic, strong) AMapSearchAPI *search; +@end + +@implementation ASearchAddressController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"选择地点"; + + [self initSubview]; + + self.search = [[AMapSearchAPI alloc] init]; + self.search.delegate = self; + +#ifdef kAMapSDKDebugFlag + self.inputAddressTf.text = @"人民广场"; +#endif + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + [self.inputAddressTf becomeFirstResponder]; +} + +-(void)initSubview { + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.backBtn]; + + UITextField * inputAddressTf = [[UITextField alloc] init]; + inputAddressTf.borderStyle = UITextBorderStyleRoundedRect; + inputAddressTf.placeholder = @"输入地址"; + inputAddressTf.returnKeyType = UIReturnKeySearch; + inputAddressTf.tag = 100; + inputAddressTf.delegate = self; + + [self.view addSubview:inputAddressTf]; + + [inputAddressTf mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.mas_equalTo(self.view).offset(10); + make.top.mas_equalTo(self.view).offset(kRoutePlanBarHeight + 10); + make.height.mas_equalTo(@30); + }]; + + self.inputAddressTf = inputAddressTf; + + + + UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; + [btn setTitle:@"当前位置" forState:UIControlStateNormal]; + btn.backgroundColor = [UIColor whiteColor]; + btn.layer.borderColor = [UIColor blueColor].CGColor; + btn.layer.borderWidth = 1; + btn.layer.cornerRadius = 5; + btn.titleLabel.font = [UIFont systemFontOfSize:12]; + + [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [btn addTarget:self action:@selector(searchBtnAction) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:btn]; + [btn mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(inputAddressTf.mas_right).offset(12); + make.top.mas_equalTo(inputAddressTf); + make.right.mas_equalTo(self.view).offset(-10); + make.height.mas_equalTo(@30); + make.width.mas_equalTo(70); + }]; + + + [self.view addSubview:self.tableView]; + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.mas_equalTo(inputAddressTf.mas_bottom).offset(5); + make.left.equalTo(self.view); + make.bottom.equalTo(self.view); + make.centerX.equalTo(self.view); + + }]; + + [self.tableView reloadData]; +} + +#pragma mark - +- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; + if (!cell) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + AMapPOI * m = self.dataArr[indexPath.row]; + cell.textLabel.text = [NSString stringWithFormat:@"%@" , m.name ]; + + return cell; +} + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.dataArr.count; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + AMapPOI * m = self.dataArr[indexPath.row]; + + if (self.selectAddressBlk) { + self.selectAddressBlk(m); + } + + [self backBtnAction]; +// [self.navigationController popViewControllerAnimated:YES]; +} + +#pragma mark - +- (UITableView *)tableView { + if (!_tableView) { + _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; + _tableView.delegate = self; + _tableView.dataSource = self; + } + + return _tableView; +} + +-(UIButton *)backBtn{ + if (!_backBtn) { + _backBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + _backBtn.frame = CGRectMake(0, 0, 40, 30); + _backBtn.imageEdgeInsets = UIEdgeInsetsMake(2, -5, 2, 5); + +// _backBtn.backgroundColor = UIColor.redColor; + [_backBtn setImage:[AMapNavCommonUtil imageWithName:@"icon_fanhui"] forState:UIControlStateNormal]; + [_backBtn addTarget:self action:@selector(backBtnAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _backBtn; +} + +-(void)backBtnAction { + [self dismissViewControllerAnimated:YES completion:^{ + + }]; + +} + +#pragma mark - Action +-(void)searchBtnAction { + AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager]; + self.inputAddressTf.text = sdk.locationAddressDetail; + + [self startSearchWithAddress:self.inputAddressTf.text]; +} + +-(void)startSearchWithAddress:(NSString *)addr { + if (!addr) { + return; + } + + AMapPOIKeywordsSearchRequest *request = [[AMapPOIKeywordsSearchRequest alloc] init]; + + request.keywords = addr; + + AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager]; + request.city = sdk.localCity; + + +// request.types = @"高等院校"; +// request.requireExtension = YES; + request.offset =20; + + /* 搜索SDK 3.2.0 中新增加的功能,只搜索本城市的POI。*/ + request.cityLimit = YES; +// request.requireSubPOIs = YES; + + + [self.search AMapPOIKeywordsSearch:request]; + +} + + +#pragma mark - +/* POI 搜索回调. */ +- (void)onPOISearchDone:(AMapPOISearchBaseRequest *)request response:(AMapPOISearchResponse *)response +{ + NSArray * pois = response.pois; + if (pois.count == 0) + { + return; + } + + //解析response获取POI信息,具体解析见 Demo + + self.dataArr = [NSArray arrayWithArray:pois]; + [self.tableView reloadData]; + +} + + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + + [self startSearchWithAddress:textField.text]; + + return YES; +} + + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [self.inputAddressTf resignFirstResponder]; +} +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h new file mode 100644 index 0000000..fb0e2ca --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h @@ -0,0 +1,19 @@ +// +// AMapNavCommonUtil.h +// Pods +// +// Created by admin on 2026/2/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AMapNavCommonUtil : NSObject + ++(UIImage *)imageWithName:(NSString *)name; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m new file mode 100644 index 0000000..585f05b --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m @@ -0,0 +1,27 @@ +// +// AMapNavCommonUtil.m +// Pods +// +// Created by admin on 2026/2/11. +// + +#import "AMapNavCommonUtil.h" + +@implementation AMapNavCommonUtil + + +#pragma mark - 获取图片 ++(UIImage *)imageWithName:(NSString *)name { + NSURL * url = [[NSBundle mainBundle] URLForResource:@"AMapNavIOSSDK" withExtension:@"bundle"]; + NSBundle *containnerBundle = [NSBundle bundleWithURL:url]; + + NSString * path = [containnerBundle pathForResource:[NSString stringWithFormat:@"%@@2x.png" , name] ofType:nil]; + + UIImage * arrowImage = [[UIImage imageWithContentsOfFile:path] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + return arrowImage; +} + + + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.h new file mode 100644 index 0000000..4aef2b2 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.h @@ -0,0 +1,19 @@ +// +// AMapNavHttpUtil.h +// AMapNavIOSSDK +// +// Created by admin on 2026/2/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AMapNavHttpUtil : NSObject + ++ (void)postRequestWithURL:(NSString *)urlString parameters:(id)parameters requestHeader:(NSDictionary *)headParam successHandler:(void (^)(NSDictionary *data, NSURLResponse *response))successHandler failureHandler:(void ( ^)(NSError *error))failureHandler; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.m new file mode 100644 index 0000000..dd80c43 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavHttpUtil.m @@ -0,0 +1,114 @@ +// +// AMapNavHttpUtil.m +// AMapNavIOSSDK +// +// Created by admin on 2026/2/11. +// + +#import "AMapNavHttpUtil.h" + +#define AMapRequestMethod_POST @"POST" + +@interface AMapNavHttpUtil () +@property (nonatomic , copy) NSString * baseURL; +@end + +@implementation AMapNavHttpUtil + ++ (instancetype)sharedInstance { + static AMapNavHttpUtil *sharedInstance = nil; + static dispatch_once_t onceToken; + + // dispatch_once确保下面的代码块只被执行一次 + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + // 可以在这里进行一些初始化操作 + + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + +// if (sdk.config.developmentModel) { +// _baseURL = kYTOTPAnalyticsSDKTestHost; +// }else { +// _baseURL = kYTOTPAnalyticsSDKProductionHost; +// } + } + + return self; +} + + ++ (void)postRequestWithURL:(NSString *)urlString parameters:(id)parameters requestHeader:(NSDictionary *)headParam successHandler:(void (^)(NSDictionary *data, NSURLResponse *response))successHandler failureHandler:(void ( ^)(NSError *error))failureHandler { + [self requestWithMethod:AMapRequestMethod_POST URL:urlString parameters:parameters requestHeader:headParam successHandler:successHandler failureHandler:failureHandler]; +} + + +// 使用NSURLSession发起网络请求 ++ (void)requestWithMethod:(NSString *)method URL:(NSString *)urlString parameters:(id)parameters requestHeader:(NSDictionary *)headParam successHandler:(void (^)(NSDictionary *data, NSURLResponse *response))successHandler failureHandler:(void (^)(NSError *error))failureHandler { + if (!urlString) { + return; + } + + // 创建URL + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@" , urlString]]; + + // 创建请求 + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.HTTPMethod = method; + request.timeoutInterval = 30.0; + + // 设置请求头,指定数据通讯格式为json + if (headParam) { + for (NSString *key in headParam.allKeys) { + if (headParam[key]) { + [request setValue:[NSString stringWithFormat:@"%@",headParam[key]] forHTTPHeaderField:key]; + } + } + } + + // 将参数转换为JSON数据 + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error]; + if (!jsonData) {} + + if ([method isEqualToString: AMapRequestMethod_POST]) { + // 设置请求体 + request.HTTPBody = jsonData; + } + + __block NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (error) { + NSLog(@"request error:%@" , error); + if (failureHandler) { + failureHandler(error); + } + } else { + if (successHandler) { + NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; + if(dic){ + NSLog(@"url: %@ , response data:%@", url , dic); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + successHandler(dic, response); + }); +// successHandler(dic, response); + } + } + + [session finishTasksAndInvalidate]; + session = nil; + }]; + + // 开始任务 + [task resume]; +} + + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.h new file mode 100644 index 0000000..c9f7472 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.h @@ -0,0 +1,32 @@ +// +// AMapPrivacyUtility.h +// officialDemoNavi +// +// Created by menglong on 2021/10/29. +// Copyright © 2021 AutoNavi. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/* + * 隐私合规使用demo 工具类 + */ +@interface AMapPrivacyUtility : NSObject + +/** + * @brief 通过这个方法来判断是否同意隐私合规 + * 1.如果没有同意隐私合规,则创建的SDK manager 实例返回 为nil, 无法使用SDK提供的功能 + * 2.如果同意了下次启动不提示 的授权,则不会弹框给用户 + * 3.如果只同意了,则下次启动还要给用户弹框提示 + */ + ++ (void)handlePrivacyAgreeStatus; + ++ (void)handlePrivacyAgreeStatusIn:(UIViewController*)targetVC; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.m new file mode 100644 index 0000000..3e96c97 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapPrivacyUtility.m @@ -0,0 +1,137 @@ +// +// AMapPrivacyUtility.m +// officialDemoNavi +// +// Created by menglong on 2021/10/29. +// Copyright © 2021 AutoNavi. All rights reserved. +// + +#import "AMapPrivacyUtility.h" +#import +#import +@implementation AMapPrivacyUtility + ++ (void)showPrivacyInfoInWindow:(UIWindow *)window { + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + + paragraphStyle.alignment = NSTextAlignmentLeft; + + NSMutableAttributedString *privacyInfo = [[NSMutableAttributedString alloc] initWithString:@"\n亲,感谢您对XXX一直以来的信任!我们依据最新的监管要求更新了XXX《隐私权政策》,特向您说明如下\n1.为向您提供交易相关基本功能,我们会收集、使用必要的信息;\n2.基于您的明示授权,我们可能会获取您的位置(为您提供附近的商品、店铺及优惠资讯等)等信息,您有权拒绝或取消授权;\n3.我们会采取业界先进的安全措施保护您的信息安全;\n4.未经您同意,我们不会从第三方处获取、共享或向提供您的信息;" attributes:@{ + NSParagraphStyleAttributeName:paragraphStyle, + }]; + + [privacyInfo addAttribute:NSLinkAttributeName + value:@"《隐私权政策》" + range:[[privacyInfo string] rangeOfString:@"《隐私权政策》"]]; + + UIAlertController *privacyInfoController = [UIAlertController alertControllerWithTitle:@"温馨提示(隐私合规示例)" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + + [privacyInfoController setValue:privacyInfo forKey:@"attributedMessage"]; + + + UIAlertAction *agreeAllAction = [UIAlertAction actionWithTitle:@"同意(下次不提示)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"agreeStatus"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree]; + }]; + + + UIAlertAction *agreeAction = [UIAlertAction actionWithTitle:@"同意" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree]; + }]; + + UIAlertAction *notAgreeAction = [UIAlertAction actionWithTitle:@"不同意" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"agreeStatus"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusNotAgree]; + }]; + + [privacyInfoController addAction:agreeAllAction]; + [privacyInfoController addAction:agreeAction]; + [privacyInfoController addAction:notAgreeAction]; + + [window.rootViewController presentViewController:privacyInfoController animated:YES completion:^{ + //更新App是否显示隐私弹窗的状态,隐私弹窗是否包含高德SDK隐私协议内容的状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyShow:AMapPrivacyShowStatusDidShow privacyInfo:AMapPrivacyInfoStatusDidContain]; + }]; + +} + ++ (void)handlePrivacyAgreeStatus { + //判断是否同意了隐私协议下次不提示 +// if(![[NSUserDefaults standardUserDefaults] boolForKey:@"agreeStatus"]){ + //添加隐私合规弹窗 + [self showPrivacyInfoInWindow:[UIApplication sharedApplication].delegate.window]; + +// [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree]; +// } +} + ++ (void)handlePrivacyAgreeStatusIn:(UIViewController*)targetVC { + if(![[NSUserDefaults standardUserDefaults] boolForKey:@"agreeStatus"]){ + [self showPrivacyInfoInWindowWithVC:targetVC]; + } +} + ++ (void)showPrivacyInfoInWindowWithVC:(UIViewController *)window { + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + + paragraphStyle.alignment = NSTextAlignmentLeft; + + NSMutableAttributedString *privacyInfo = [[NSMutableAttributedString alloc] initWithString:@"\n感谢您一直以来的信任!我们依据最新的监管要求更新了《隐私权政策》,特向您说明如下\n1.为向您提供交易相关基本功能,我们会收集、使用必要的信息;\n2.基于您的明示授权,我们可能会获取您的位置(为您提供附近的店铺及优惠资讯等)等信息,您有权拒绝或取消授权;\n3.我们会采取业界先进的安全措施保护您的信息安全;\n4.未经您同意,我们不会从第三方处获取、共享或向提供您的信息;" attributes:@{ + NSParagraphStyleAttributeName:paragraphStyle, + }]; + + [privacyInfo addAttribute:NSLinkAttributeName + value:@"《隐私权政策》" + range:[[privacyInfo string] rangeOfString:@"《隐私权政策》"]]; + + UIAlertController *privacyInfoController = [UIAlertController alertControllerWithTitle:@"温馨提示(隐私合规示例)" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + + [privacyInfoController setValue:privacyInfo forKey:@"attributedMessage"]; + + + UIAlertAction *agreeAllAction = [UIAlertAction actionWithTitle:@"同意(下次不提示)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"agreeStatus"]; + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"usragreeStatus"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree]; + + [NSNotificationCenter.defaultCenter postNotificationName:@"ksAMapPrivacyDidUpdateNotification" object:nil]; + }]; + + + UIAlertAction *agreeAction = [UIAlertAction actionWithTitle:@"同意" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"usragreeStatus"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree]; + [NSNotificationCenter.defaultCenter postNotificationName:@"ksAMapPrivacyDidUpdateNotification" object:nil]; + }]; + + UIAlertAction *notAgreeAction = [UIAlertAction actionWithTitle:@"不同意" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"agreeStatus"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + //更新用户授权高德SDK隐私协议状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyAgree:AMapPrivacyAgreeStatusNotAgree]; + }]; + + [privacyInfoController addAction:agreeAllAction]; + [privacyInfoController addAction:agreeAction]; + [privacyInfoController addAction:notAgreeAction]; + + [window presentViewController:privacyInfoController animated:YES completion:^{ + //更新App是否显示隐私弹窗的状态,隐私弹窗是否包含高德SDK隐私协议内容的状态. since 8.1.0 + [[AMapNaviManagerConfig sharedConfig] updatePrivacyShow:AMapPrivacyShowStatusDidShow privacyInfo:AMapPrivacyInfoStatusDidContain]; + }]; + +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.h new file mode 100644 index 0000000..a488be4 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.h @@ -0,0 +1,22 @@ +// +// NaviPointAnnotation.h +// AMapNaviKit +// +// Created by 刘博 on 16/3/8. +// Copyright © 2016年 AutoNavi. All rights reserved. +// + +#import + +typedef NS_ENUM(NSInteger, NaviPointAnnotationType) +{ + NaviPointAnnotationStart, + NaviPointAnnotationWay, + NaviPointAnnotationEnd +}; + +@interface NaviPointAnnotation : MAPointAnnotation + +@property (nonatomic, assign) NaviPointAnnotationType navPointType; + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.m new file mode 100644 index 0000000..81808f5 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/NaviPointAnnotation.m @@ -0,0 +1,13 @@ +// +// NaviPointAnnotation.m +// AMapNaviKit +// +// Created by 刘博 on 16/3/8. +// Copyright © 2016年 AutoNavi. All rights reserved. +// + +#import "NaviPointAnnotation.h" + +@implementation NaviPointAnnotation + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h new file mode 100755 index 0000000..37c4b10 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h @@ -0,0 +1,24 @@ +// +// SelectableOverlay.h +// officialDemo2D +// +// Created by yi chen on 14-5-8. +// Copyright (c) 2014年 AutoNavi. All rights reserved. +// + +#import +#import + +@interface SelectableOverlay : MABaseOverlay + +@property (nonatomic, assign) NSInteger routeID; + +@property (nonatomic, assign, getter = isSelected) BOOL selected; +@property (nonatomic, strong) UIColor * selectedColor; +@property (nonatomic, strong) UIColor * regularColor; + +@property (nonatomic, strong) id overlay; + +- (id)initWithOverlay:(id) overlay; + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m new file mode 100755 index 0000000..9c2aea9 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m @@ -0,0 +1,41 @@ +// +// SelectableOverlay.m +// officialDemo2D +// +// Created by yi chen on 14-5-8. +// Copyright (c) 2014年 AutoNavi. All rights reserved. +// + +#import "SelectableOverlay.h" + +@implementation SelectableOverlay + +#pragma mark - MAOverlay Protocol + +- (CLLocationCoordinate2D)coordinate +{ + return [self.overlay coordinate]; +} + +- (MAMapRect)boundingMapRect +{ + return [self.overlay boundingMapRect]; +} + +#pragma mark - Life Cycle + +- (id)initWithOverlay:(id)overlay +{ + self = [super init]; + if (self) + { + self.overlay = overlay; + self.selected = NO; + self.selectedColor = [UIColor colorWithRed:0.05 green:0.39 blue:0.9 alpha:0.8]; + self.regularColor = [UIColor colorWithRed:0.5 green:0.6 blue:0.9 alpha:0.8]; + } + + return self; +} + +@end diff --git a/ln_jq_app/ios/Podfile b/ln_jq_app/ios/Podfile index 466cfc9..42199c1 100644 --- a/ln_jq_app/ios/Podfile +++ b/ln_jq_app/ios/Podfile @@ -34,7 +34,7 @@ target 'Runner' do # use_frameworks! use_frameworks! :linkage => :static - pod 'AMapNavIOSSDK' , :path => '../../../../demo/ANavDemo/' + pod 'AMapNavIOSSDK' , :path => './AMapNavIOSSDK' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index f002c02..8b5621d 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -59,7 +59,7 @@ PODS: DEPENDENCIES: - aliyun_push_flutter (from `.symlinks/plugins/aliyun_push_flutter/ios`) - - AMapNavIOSSDK (from `../../../../demo/ANavDemo/`) + - AMapNavIOSSDK (from `./AMapNavIOSSDK`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) @@ -93,7 +93,7 @@ EXTERNAL SOURCES: aliyun_push_flutter: :path: ".symlinks/plugins/aliyun_push_flutter/ios" AMapNavIOSSDK: - :path: "../../../../demo/ANavDemo/" + :path: "./AMapNavIOSSDK" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: @@ -148,6 +148,6 @@ SPEC CHECKSUMS: shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa -PODFILE CHECKSUM: aba49f58e1bc68a5558fc761b5370b90e7cb7e2b +PODFILE CHECKSUM: 97188da9dab9d4b3372eb4c16e872fbd555fdbea COCOAPODS: 1.16.2 From b846d352a239842660a0bd3efde80fbb381086ff Mon Sep 17 00:00:00 2001 From: userGyl Date: Tue, 10 Mar 2026 17:31:27 +0800 Subject: [PATCH 06/19] =?UTF-8?q?android=20=E5=9C=B0=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/android/app/build.gradle.kts | 5 + .../android/app/src/main/AndroidManifest.xml | 8 + .../java/com/lnkj/ln_jq_app/MainActivity.java | 189 ++++++++++++++++++ .../com/lnkj/ln_jq_app/NativeMapFactory.java | 37 ++++ .../com/lnkj/ln_jq_app/NativeMapView.java | 143 +++++++++++++ .../app/src/main/res/drawable/amap_loc.xml | 10 + .../src/main/res/drawable/ic_end_marker.xml | 10 + .../app/src/main/res/drawable/ic_location.xml | 10 + .../app/src/main/res/drawable/ic_route.xml | 13 ++ .../src/main/res/drawable/ic_start_marker.xml | 10 + .../main/res/drawable/ic_station_marker.xml | 10 + .../c_page/base_widgets/NativePageIOS.dart | 116 ++++++----- 12 files changed, 515 insertions(+), 46 deletions(-) create mode 100644 ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java create mode 100644 ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java create mode 100644 ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_location.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_route.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml diff --git a/ln_jq_app/android/app/build.gradle.kts b/ln_jq_app/android/app/build.gradle.kts index 2539bdf..24d95b7 100644 --- a/ln_jq_app/android/app/build.gradle.kts +++ b/ln_jq_app/android/app/build.gradle.kts @@ -68,3 +68,8 @@ android { flutter { source = "../.." } + +dependencies { + implementation("com.amap.api:navi-3dmap-location-search:10.0.700_3dmap10.0.700_loc6.4.5_sea9.7.2") + implementation("com.squareup.okhttp3:okhttp:4.12.0") +} diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml index 5392736..7a6ef64 100644 --- a/ln_jq_app/android/app/src/main/AndroidManifest.xml +++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml @@ -22,6 +22,14 @@ android:label="小羚羚" android:name="${applicationName}" android:icon="@mipmap/logo"> + + + + + + { + switch (call.method) { + case "requestPermissions": + requestPermissions(); + result.success(null); + break; + case "onResume": + if (mapView != null) { + mapView.onResume(); + } + result.success(null); + break; + case "onPause": + if (mapView != null) { + mapView.onPause(); + } + result.success(null); + break; + case "onDestroy": + if (mapView != null) { + mapView.dispose(); + mapView = null; + } + result.success(null); + break; + default: + result.notImplemented(); + break; + } + }); + } + + /** + * 获取当前系统版本需要申请的权限列表 + */ + private String[] getRequiredPermissions() { + List permissions = new ArrayList<>(); + // 定位权限是必须的 + permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); + permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); + + // 存储权限处理:Android 13 (API 33) 以下才需要申请 legacy 存储权限 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } + + return permissions.toArray(new String[0]); + } + + /** + * 检查并申请权限 + */ + private void checkAndRequestPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + String[] requiredPermissions = getRequiredPermissions(); + List deniedPermissions = new ArrayList<>(); + + for (String permission : requiredPermissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + deniedPermissions.add(permission); + } + } + + if (!deniedPermissions.isEmpty()) { + ActivityCompat.requestPermissions( + this, + deniedPermissions.toArray(new String[0]), + PERMISSION_REQUEST_CODE + ); + } else { + Log.d(TAG, "所有必要权限已授予"); + if (mapView != null) { + mapView.startLocation(); + } + } + } else { + if (mapView != null) { + mapView.startLocation(); + } + } + } + + private void requestPermissions() { + checkAndRequestPermissions(); + } + + public void setMapView(NativeMapView mapView) { + this.mapView = mapView; + } + + @Override + protected void onResume() { + super.onResume(); + // 注意:高德SDK合规检查通过后再进行定位相关操作 + // 这里仅保留地图生命周期调用,权限建议在Flutter端或按需触发 + if (mapView != null) { + mapView.onResume(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mapView != null) { + mapView.onPause(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mapView != null) { + mapView.dispose(); + mapView = null; + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + if (mapView != null) { + mapView.onSaveInstanceState(outState); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if (requestCode == PERMISSION_REQUEST_CODE) { + boolean locationGranted = false; + for (int i = 0; i < permissions.length; i++) { + if (Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[i]) + && grantResults[i] == PackageManager.PERMISSION_GRANTED) { + locationGranted = true; + break; + } + } + + if (locationGranted) { + if (mapView != null) { + mapView.startLocation(); + } + } else { + // 只有在定位权限确实被拒绝时才弹出提示 + Toast.makeText(this, "请授予应用定位权限以正常使用地图功能", Toast.LENGTH_LONG).show(); + } + } + } } diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java new file mode 100644 index 0000000..9e8ff31 --- /dev/null +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapFactory.java @@ -0,0 +1,37 @@ +package com.lnkj.ln_jq_app; + +import android.content.Context; + +import io.flutter.plugin.common.MessageCodec; +import io.flutter.plugin.common.StandardMessageCodec; +import io.flutter.plugin.platform.PlatformView; +import io.flutter.plugin.platform.PlatformViewFactory; + +/** + * 高德地图导航 Platform View Factory + * 对应iOS的NativeViewFactory + */ +public class NativeMapFactory extends PlatformViewFactory { + + private static final String VIEW_TYPE_ID = "NativeFirstPage"; + private static NativeMapView mapViewInstance = null; + private final Context context; + + public NativeMapFactory(Context context) { + super(StandardMessageCodec.INSTANCE); + this.context = context; + } + + @Override + public PlatformView create(Context context, int viewId, Object args) { + mapViewInstance = new NativeMapView(context, viewId, args); + return mapViewInstance; + } + + /** + * 获取地图实例,供MainActivity使用 + */ + public static NativeMapView getMapView() { + return mapViewInstance; + } +} diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java new file mode 100644 index 0000000..63cece6 --- /dev/null +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -0,0 +1,143 @@ +package com.lnkj.ln_jq_app; + +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.util.Log; +import android.view.View; + +import com.amap.api.location.AMapLocation; +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationListener; +import com.amap.api.maps.AMap; +import com.amap.api.maps.LocationSource; +import com.amap.api.maps.MapView; +import com.amap.api.maps.MapsInitializer; +import com.amap.api.maps.model.MyLocationStyle; + +import io.flutter.plugin.platform.PlatformView; + +public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener { + private static final String TAG = "NativeMapView"; + private final MapView mapView; + private final AMap aMap; + private OnLocationChangedListener mListener; + private AMapLocationClient mlocationClient; + private final Context mContext; + + public NativeMapView(Context context, int id, Object args) { + this.mContext = context; + + // 隐私合规接口,必须在创建MapView之前设置 + MapsInitializer.updatePrivacyShow(context, true, true); + MapsInitializer.updatePrivacyAgree(context, true); + + mapView = new MapView(context); + // 在 Flutter PlatformView 中,savedInstanceState 通常为 null + mapView.onCreate(null); + aMap = mapView.getMap(); + + // 设置地图的 UI 选项 + setupMapUi(); + + // 注册到 MainActivity 以便同步生命周期 + if (context instanceof MainActivity) { + ((MainActivity) context).setMapView(this); + } + } + + private void setupMapUi() { + aMap.setLocationSource(this); + aMap.setMyLocationEnabled(true); + + MyLocationStyle myLocationStyle = new MyLocationStyle(); + myLocationStyle.interval(2000); + // 连续定位并将视角移动到地图中心点,定位蓝点跟随设备移动 + myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE); + myLocationStyle.showMyLocation(true); + myLocationStyle.strokeColor(Color.TRANSPARENT); + myLocationStyle.radiusFillColor(Color.TRANSPARENT); + aMap.setMyLocationStyle(myLocationStyle); + + // 显示缩放按钮 + aMap.getUiSettings().setZoomControlsEnabled(true); + } + + @Override + public View getView() { + return mapView; + } + + @Override + public void activate(OnLocationChangedListener listener) { + mListener = listener; + startLocation(); + } + + @Override + public void deactivate() { + mListener = null; + if (mlocationClient != null) { + mlocationClient.stopLocation(); + mlocationClient.onDestroy(); + } + mlocationClient = null; + } + + public void startLocation() { + if (mlocationClient == null) { + try { + AMapLocationClient.updatePrivacyShow(mContext, true, true); + AMapLocationClient.updatePrivacyAgree(mContext, true); + mlocationClient = new AMapLocationClient(mContext); + AMapLocationClientOption mLocationOption = new AMapLocationClientOption(); + mlocationClient.setLocationListener(this); + mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); + mlocationClient.setLocationOption(mLocationOption); + mlocationClient.startLocation(); + } catch (Exception e) { + Log.e(TAG, "startLocation error", e); + } + } + } + + @Override + public void onLocationChanged(AMapLocation amapLocation) { + if (mListener != null && amapLocation != null) { + if (amapLocation.getErrorCode() == 0) { + mListener.onLocationChanged(amapLocation); + // 首次定位成功后缩放地图 + // aMap.moveCamera(CameraUpdateFactory.zoomTo(15)); + } else { + Log.e(TAG, "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo()); + } + } + } + + public void onResume() { + if (mapView != null) { + mapView.onResume(); + } + } + + public void onPause() { + if (mapView != null) { + mapView.onPause(); + } + } + + public void onSaveInstanceState(Bundle outState) { + if (mapView != null) { + mapView.onSaveInstanceState(outState); + } + } + + @Override + public void dispose() { + if (mapView != null) { + mapView.onDestroy(); + } + deactivate(); + } +} diff --git a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml b/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml new file mode 100644 index 0000000..a58e47e --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml @@ -0,0 +1,10 @@ + + + + diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml new file mode 100644 index 0000000..58bb442 --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml @@ -0,0 +1,10 @@ + + + + diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml new file mode 100644 index 0000000..4e99139 --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml @@ -0,0 +1,10 @@ + + + + diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml new file mode 100644 index 0000000..e16e2fe --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml new file mode 100644 index 0000000..0af42cf --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml @@ -0,0 +1,10 @@ + + + + diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml new file mode 100644 index 0000000..ef73731 --- /dev/null +++ b/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml @@ -0,0 +1,10 @@ + + + + diff --git a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart index a21b0cc..150ab11 100644 --- a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart +++ b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart @@ -1,58 +1,82 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'dart:io'; - import 'package:flutter/services.dart'; +/// 原生地图页面 class NativePageIOS extends StatelessWidget { - const NativePageIOS({super.key}); + const NativePageIOS({super.key}); - @override - Widget build(BuildContext context) { - if (Platform.isIOS) { - return Container( - // onTap: () => _handleTap(context), - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.width - 100, - // padding: EdgeInsetsGeometry.all(15), - color: Colors.red[100], - - child: UiKitView( - viewType: 'NativeFirstPage', // 与原生端注册的标识一致 - gestureRecognizers: >{}.toSet(), - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - creationParamsCodec: const StandardMessageCodec(), - layoutDirection: TextDirection.ltr, - ) - ); - } else { - return const Center(child: Text('not ios')); - } - } - - - void _handleTap(BuildContext context) { - print("页面被点击"); - _showDialog(context, 'Tip', '点击了'); - } - - - void _showDialog(BuildContext context, String title, String content) { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('确定'), - ), - ], - ), + @override + Widget build(BuildContext context) { + if (Platform.isIOS) { + return _buildIOSView(context); + } else if (Platform.isAndroid) { + return _buildAndroidView(context); + } else { + return const Center( + child: Text('不支持的平台', style: TextStyle(fontSize: 16)), ); } + } + /// 构建iOS Platform View + Widget _buildIOSView(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 100, + color: Colors.white, + child: UiKitView( + viewType: 'NativeFirstPage', // 与iOS原生端注册的标识一致 + gestureRecognizers: >{}.toSet(), + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + creationParamsCodec: const StandardMessageCodec(), + layoutDirection: TextDirection.ltr, + ), + ); + } + + /// 构建Android Platform View + Widget _buildAndroidView(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 100, + color: Colors.white, + child: AndroidView( + viewType: 'NativeFirstPage', // 与Android原生端注册的标识一致 + gestureRecognizers: >{}.toSet(), + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + creationParamsCodec: const StandardMessageCodec(), + layoutDirection: TextDirection.ltr, + ), + ); + } + + /// 处理点击事件(如需要) + void _handleTap(BuildContext context) { + if (kDebugMode) { + print("NativePage被点击"); + } + _showDialog(context, '提示', '点击了原生地图页面'); + } + + /// 显示对话框 + void _showDialog(BuildContext context, String title, String content) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(title), + content: Text(content), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('确定'), + ), + ], + ), + ); + } } \ No newline at end of file From cd14469d7910c637ae2c42d9c6bbb4c0962f0571 Mon Sep 17 00:00:00 2001 From: userGyl Date: Thu, 12 Mar 2026 13:27:08 +0800 Subject: [PATCH 07/19] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AE=9A=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/main/AndroidManifest.xml | 12 +- .../com/lnkj/ln_jq_app/NativeMapView.java | 642 ++++++++++++++++-- .../app/src/main/res/drawable/amap_loc.xml | 10 - .../android/app/src/main/res/drawable/car.png | Bin 0 -> 6754 bytes .../src/main/res/drawable/ic_end_marker.xml | 10 - .../app/src/main/res/drawable/ic_location.xml | 10 - .../app/src/main/res/drawable/ic_route.xml | 13 - .../src/main/res/drawable/ic_start_marker.xml | 10 - .../main/res/drawable/ic_station_marker.xml | 10 - .../app/src/main/res/drawable/ic_tag.png | Bin 0 -> 3468 bytes 10 files changed, 608 insertions(+), 109 deletions(-) delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/car.png delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_location.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_route.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_tag.png diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml index 7a6ef64..c7cf8d3 100644 --- a/ln_jq_app/android/app/src/main/AndroidManifest.xml +++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml @@ -14,7 +14,12 @@ - + + + + + + @@ -30,6 +35,11 @@ + + stationMarkers = new ArrayList<>(); public NativeMapView(Context context, int id, Object args) { this.mContext = context; - // 隐私合规接口,必须在创建MapView之前设置 + // 尝试获取Activity引用 + mActivity = getActivityFromContext(context); + MapsInitializer.updatePrivacyShow(context, true, true); MapsInitializer.updatePrivacyAgree(context, true); + container = new FrameLayout(context); + container.setClickable(true); + container.setFocusable(true); + mapView = new MapView(context); - // 在 Flutter PlatformView 中,savedInstanceState 通常为 null - mapView.onCreate(null); + mapView.onCreate(null); aMap = mapView.getMap(); - // 设置地图的 UI 选项 + container.addView(mapView, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + initServices(context); + initOverlays(context); setupMapUi(); - // 注册到 MainActivity 以便同步生命周期 + // 通知MainActivity if (context instanceof MainActivity) { ((MainActivity) context).setMapView(this); } + + Log.d(TAG, "NativeMapView初始化完成"); + } + + /** + * 初始化服务 + */ + private void initServices(Context context) { + try { + geocoderSearch = new GeocodeSearch(context); + geocoderSearch.setOnGeocodeSearchListener(this); + routeSearch = new RouteSearch(context); + routeSearch.setRouteSearchListener(this); + } catch (AMapException e) { + Log.e(TAG, "服务初始化失败", e); + } + } + + /** + * 初始化覆盖层UI + */ + private void initOverlays(Context context) { + LinearLayout searchBox = new LinearLayout(context); + searchBox.setOrientation(LinearLayout.VERTICAL); + searchBox.setBackground(getRoundedDrawable(Color.WHITE, 12)); + searchBox.setElevation(dp2px(8)); + int p = dp2px(15); + searchBox.setPadding(p, p, p, p); + searchBox.setClickable(true); + searchBox.setFocusable(true); + + startInput = createInput(context, "起点: 正在定位..."); + searchBox.addView(startInput); + + View vSpace = new View(context); + searchBox.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(10))); + + LinearLayout endRow = new LinearLayout(context); + endRow.setOrientation(LinearLayout.HORIZONTAL); + endRow.setGravity(Gravity.CENTER_VERTICAL); + + endInput = createInput(context, "终点: 请输入目的地"); + endRow.addView(endInput, new LinearLayout.LayoutParams(0, dp2px(42), 1f)); + + Button routeBtn = new Button(context); + routeBtn.setText("路径规划"); + routeBtn.setTextColor(Color.WHITE); + routeBtn.setAllCaps(false); + routeBtn.setTextSize(14); + routeBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 6)); + routeBtn.setOnClickListener(v -> startRouteSearch()); + endRow.addView(routeBtn, new LinearLayout.LayoutParams(dp2px(90), dp2px(42))); + + searchBox.addView(endRow); + + FrameLayout.LayoutParams searchParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + searchParams.setMargins(dp2px(15), dp2px(50), dp2px(15), 0); + container.addView(searchBox, searchParams); + + ImageButton locBtn = new ImageButton(context); + locBtn.setImageResource(android.R.drawable.ic_menu_mylocation); + locBtn.setBackground(getRoundedDrawable(Color.WHITE, 30)); + locBtn.setElevation(dp2px(4)); + locBtn.setOnClickListener(v -> { + if (currentLatLng != null) { + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); + } + }); + FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(50), dp2px(50)); + locParams.setMargins(0, 0, dp2px(20), dp2px(120)); + locParams.gravity = Gravity.BOTTOM | Gravity.END; + container.addView(locBtn, locParams); + } + + private EditText createInput(Context context, String hint) { + EditText et = new EditText(context); + et.setHint(hint); + et.setTextSize(14f); + et.setTextColor(Color.BLACK); + et.setPadding(dp2px(12), dp2px(10), dp2px(12), dp2px(10)); + et.setBackground(getRoundedDrawable(Color.parseColor("#F5F5F5"), 6)); + et.setSingleLine(true); + et.setImeOptions(EditorInfo.IME_ACTION_DONE); + et.setFocusable(true); + et.setFocusableInTouchMode(true); + return et; + } + + private GradientDrawable getRoundedDrawable(int color, int radiusDp) { + GradientDrawable shape = new GradientDrawable(); + shape.setShape(GradientDrawable.RECTANGLE); + shape.setCornerRadius(dp2px(radiusDp)); + shape.setColor(color); + return shape; + } + + private int dp2px(float dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics()); } private void setupMapUi() { aMap.setLocationSource(this); aMap.setMyLocationEnabled(true); + aMap.setOnMarkerClickListener(this); MyLocationStyle myLocationStyle = new MyLocationStyle(); - myLocationStyle.interval(2000); - // 连续定位并将视角移动到地图中心点,定位蓝点跟随设备移动 - myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE); + + // --- 放大定位图标 --- + try { + Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car); + if (carBitmap != null) { + // 放大到 80dp + int iconSize = dp2px(25); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, iconSize, iconSize, true); + myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap)); + } + } catch (Exception e) { + Log.e(TAG, "设置大图标失败", e); + } + + myLocationStyle.anchor(0.5f, 0.5f); + myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); myLocationStyle.showMyLocation(true); myLocationStyle.strokeColor(Color.TRANSPARENT); myLocationStyle.radiusFillColor(Color.TRANSPARENT); aMap.setMyLocationStyle(myLocationStyle); - - // 显示缩放按钮 + aMap.getUiSettings().setZoomControlsEnabled(true); + aMap.getUiSettings().setScaleControlsEnabled(true); + aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT); } - @Override - public View getView() { - return mapView; - } - + // ==================== LocationSource 接口实现 ==================== @Override public void activate(OnLocationChangedListener listener) { mListener = listener; @@ -88,56 +291,405 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public void startLocation() { if (mlocationClient == null) { try { - AMapLocationClient.updatePrivacyShow(mContext, true, true); - AMapLocationClient.updatePrivacyAgree(mContext, true); mlocationClient = new AMapLocationClient(mContext); - AMapLocationClientOption mLocationOption = new AMapLocationClientOption(); + AMapLocationClientOption option = new AMapLocationClientOption(); mlocationClient.setLocationListener(this); - mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); - mlocationClient.setLocationOption(mLocationOption); + option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); + mlocationClient.setLocationOption(option); mlocationClient.startLocation(); + Log.d(TAG, "定位启动成功"); } catch (Exception e) { - Log.e(TAG, "startLocation error", e); + Log.e(TAG, "定位启动失败", e); } } } @Override - public void onLocationChanged(AMapLocation amapLocation) { - if (mListener != null && amapLocation != null) { - if (amapLocation.getErrorCode() == 0) { - mListener.onLocationChanged(amapLocation); - // 首次定位成功后缩放地图 - // aMap.moveCamera(CameraUpdateFactory.zoomTo(15)); - } else { - Log.e(TAG, "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo()); + public void onLocationChanged(AMapLocation loc) { + if (loc != null) { + if (mListener != null) { + mListener.onLocationChanged(loc); + } + currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude()); + + if (loc.getErrorCode() == 0) { + if (isFirstLocation) { + isFirstLocation = false; + startPoint = currentLatLng; + aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f)); + getAddressByLatlng(currentLatLng); + fetchRecommendStation(loc); + fetchNearbyStations(loc); + } } } } - public void onResume() { - if (mapView != null) { - mapView.onResume(); + // ==================== 逆地理编码 ==================== + private void getAddressByLatlng(LatLng latLng) { + LatLonPoint point = new LatLonPoint(latLng.latitude, latLng.longitude); + RegeocodeQuery query = new RegeocodeQuery(point, 200, GeocodeSearch.AMAP); + geocoderSearch.getFromLocationAsyn(query); + } + + @Override + public void onRegeocodeSearched(RegeocodeResult result, int rCode) { + if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && result.getRegeocodeAddress() != null) { + RegeocodeAddress addr = result.getRegeocodeAddress(); + String fullAddr = addr.getFormatAddress(); + + // 优化地址显示逻辑 + startName = formatAddress(fullAddr,result); + + new Handler(Looper.getMainLooper()).post(() -> { + startInput.setText(startName); + startInput.setSelection(startName.length()); // 光标移到末尾 + }); + + Log.d(TAG, "逆地理编码成功: " + startName); + } else { + Log.e(TAG, "逆地理编码失败: code=" + rCode + ", result=" + (result != null ? "null" : "has data")); } } + /** + * 格式化地址显示,移除重复的前缀并限制长度 + */ + private String formatAddress(String fullAddress,RegeocodeResult result) { + if (fullAddress == null || fullAddress.isEmpty()) { + return "未知地点"; + } + + // 获取各级地址信息 + String province = null; + String city = null; + String district = null; + String township = null; + + try { + if (result.getRegeocodeAddress() != null) { + RegeocodeAddress addr = result.getRegeocodeAddress(); + province = addr.getProvince(); + city = addr.getCity(); + district = addr.getDistrict(); + township = addr.getTownship(); + } + } catch (Exception e) { + Log.e(TAG, "获取地址信息失败", e); + } + + String formattedAddr = fullAddress; + + // 按优先级移除重复前缀(省、市、区、乡) + String[] prefixes = {province, city, district, township}; + for (String prefix : prefixes) { + if (prefix != null && !prefix.isEmpty() && formattedAddr.startsWith(prefix)) { + formattedAddr = formattedAddr.substring(prefix.length()); + Log.d(TAG, "移除前缀: " + prefix + " -> " + formattedAddr); + } + } + + // 限制地址长度并添加省略号 + if (formattedAddr.length() > 25) { + formattedAddr = formattedAddr.substring(0, 25) + "..."; + Log.d(TAG, "地址长度截断: " + formattedAddr); + } + + return formattedAddr; + } + + @Override + public void onGeocodeSearched(GeocodeResult result, int rCode) { + } + + // ==================== API请求 ==================== + + private void fetchRecommendStation(AMapLocation loc) { + try { + JSONObject json = new JSONObject(); + json.put("province", loc.getProvince() != null ? loc.getProvince() : ""); + json.put("city", loc.getCity() != null && !loc.getCity().isEmpty() ? loc.getCity() : ""); + json.put("district", loc.getDistrict() != null ? loc.getDistrict() : ""); + json.put("longitude", String.valueOf(loc.getLongitude())); + json.put("latitude", String.valueOf(loc.getLatitude())); + + RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); + Request request = new Request.Builder() + .url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea") + .post(body) + .build(); + + httpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + try { + JSONObject res = new JSONObject(response.body().string()); + if (res.getInt("code") == 0 && !res.isNull("data")) { + JSONObject data = res.getJSONObject("data"); + endPoint = new LatLng(data.getDouble("latitude"), data.getDouble("longitude")); + endName = data.getString("name"); + String addr = data.optString("address", ""); + new Handler(Looper.getMainLooper()).post(() -> { + endInput.setText(addr); + markStation(endPoint, endName, true); + }); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void fetchNearbyStations(AMapLocation loc) { + try { + JSONObject json = new JSONObject(); + json.put("longitude", String.valueOf(loc.getLongitude())); + json.put("latitude", String.valueOf(loc.getLatitude())); + + RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); + Request request = new Request.Builder() + .url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation") + .post(body) + .build(); + + httpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + try { + JSONObject res = new JSONObject(response.body().string()); + if (res.getInt("code") == 0 && !res.isNull("data")) { + JSONArray array = res.getJSONArray("data"); + new Handler(Looper.getMainLooper()).post(() -> { + for (int i = 0; i < array.length(); i++) { + try { + JSONObject item = array.getJSONObject(i); + markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), + item.getString("name"), false); + } catch (Exception ignored) { + } + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void markStation(LatLng latLng, String name, boolean isRecommend) { + MarkerOptions opt = new MarkerOptions() + .position(latLng).title(name) + .icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN)); + Marker m = aMap.addMarker(opt); + m.setObject(latLng); + stationMarkers.add(m); + } + + @Override + public boolean onMarkerClick(Marker marker) { + if (marker.getObject() instanceof LatLng) { + endPoint = (LatLng) marker.getObject(); + endName = marker.getTitle(); + endInput.setText(endName); + startRouteSearch(); + } + return true; + } + + // ==================== 路径规划 ==================== + + private void startRouteSearch() { + if (startPoint == null || endPoint == null) { + Toast.makeText(mContext, "正在定位中,请稍后...", Toast.LENGTH_SHORT).show(); + return; + } + + Poi start = new Poi(startName, startPoint, ""); + Poi end = new Poi(endName, endPoint, ""); + + AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); + + try { + AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber("沪AGK2267"); + carInfo.setCarType("1"); + carInfo.setVehicleAxis("6"); + carInfo.setVehicleHeight("3.32"); + carInfo.setVehicleLength("6.9"); + carInfo.setVehicleWidth("2.26"); + carInfo.setVehicleSize("2"); + carInfo.setVehicleLoad("4.5"); + carInfo.setVehicleWeight("4.5"); + carInfo.setRestriction(true); + carInfo.setVehicleLoadSwitch(true); + mAMapNavi.setCarInfo(carInfo); + } catch (com.amap.api.maps.AMapException e) { + Log.e(TAG, "设置车辆信息失败", e); + } + + params.setRouteStrategy(PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + + if (mActivity != null) { + AmapNaviPage.getInstance().showRouteActivity(mActivity, params, new INaviInfoCallback() { + @Override + public void onInitNaviFailure() { + Log.e(TAG, "导航初始化失败"); + } + + @Override + public void onGetNavigationText(String s) { + } + + @Override + public void onLocationChange(AMapNaviLocation location) { + } + + @Override + public void onArriveDestination(boolean b) { + } + + @Override + public void onStartNavi(int i) { + } + + @Override + public void onCalculateRouteSuccess(int[] ints) { + } + + @Override + public void onCalculateRouteFailure(int i) { + } + + @Override + public void onStopSpeaking() { + } + + @Override + public void onReCalculateRoute(int i) { + + } + + @Override + public void onArrivedWayPoint(int i) { + } + + @Override + public void onExitPage(int i) { + } + + @Override + public void onStrategyChanged(int i) { + } + + @Override + public void onMapTypeChanged(int i) { + } + + @Override + public void onNaviDirectionChanged(int i) { + } + + @Override + public void onDayAndNightModeChanged(int i) { + } + + @Override + public void onBroadcastModeChanged(int i) { + } + + @Override + public void onScaleAutoChanged(boolean b) { + } + + @Override + public View getCustomNaviBottomView() { + return null; + } + + @Override + public View getCustomNaviView() { + return null; + } + + @Override + public View getCustomMiddleView() { + return null; + } + }); + } + } + + @Override + public void onDriveRouteSearched(DriveRouteResult result, int rCode) { + } + + @Override + public void onBusRouteSearched(BusRouteResult r, int c) { + } + + @Override + public void onWalkRouteSearched(WalkRouteResult r, int c) { + } + + @Override + public void onRideRouteSearched(RideRouteResult r, int c) { + } + + private Activity getActivityFromContext(Context context) { + if (context instanceof Activity) + return (Activity) context; + if (context instanceof android.content.ContextWrapper) { + Context base = ((android.content.ContextWrapper) context).getBaseContext(); + if (base instanceof Activity) + return (Activity) base; + } + return null; + } + + public void onResume() { + mapView.onResume(); + } + public void onPause() { - if (mapView != null) { - mapView.onPause(); - } + mapView.onPause(); } - public void onSaveInstanceState(Bundle outState) { - if (mapView != null) { - mapView.onSaveInstanceState(outState); - } + public void onSaveInstanceState(Bundle out) { + mapView.onSaveInstanceState(out); + } + + @Override + public View getView() { + return container; } @Override public void dispose() { - if (mapView != null) { - mapView.onDestroy(); + if (mlocationClient != null) { + mlocationClient.stopLocation(); + mlocationClient.onDestroy(); } - deactivate(); + mapView.onDestroy(); } } diff --git a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml b/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml deleted file mode 100644 index a58e47e..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/car.png b/ln_jq_app/android/app/src/main/res/drawable/car.png new file mode 100644 index 0000000000000000000000000000000000000000..5f5ba0a947ed485e890db49386838b4bad502d0c GIT binary patch literal 6754 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 UCptFqe;w2Hv~OuuYS>5o7klGh?EnA( literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml deleted file mode 100644 index 58bb442..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml deleted file mode 100644 index 4e99139..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml deleted file mode 100644 index e16e2fe..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml deleted file mode 100644 index 0af42cf..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml deleted file mode 100644 index ef73731..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png b/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png new file mode 100644 index 0000000000000000000000000000000000000000..dcae650ed00ba1898bc26a07ed2e1943fef0ec8c GIT binary patch literal 3468 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 Date: Fri, 20 Mar 2026 10:23:45 +0800 Subject: [PATCH 08/19] =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lnkj/ln_jq_app/NativeMapView.java | 700 +++++++----------- ln_jq_app/ios/Podfile.lock | 35 +- .../ios/Runner.xcodeproj/project.pbxproj | 9 +- .../xcshareddata/xcschemes/Runner.xcscheme | 1 + ln_jq_app/ios/Runner/AppDelegate.swift | 2 +- ln_jq_app/ios/Runner/Runner.entitlements | 4 + ln_jq_app/lib/common/styles/theme.dart | 2 +- ln_jq_app/lib/main.dart | 6 +- .../lib/pages/c_page/base_widgets/view.dart | 2 - ln_jq_app/lib/pages/home/controller.dart | 3 +- 10 files changed, 293 insertions(+), 471 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index ed377cc..6932c81 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -5,10 +5,13 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; +import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.text.Editable; +import android.text.TextWatcher; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; @@ -20,6 +23,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; import com.amap.api.location.AMapLocation; @@ -43,10 +47,7 @@ import com.amap.api.navi.AmapNaviPage; import com.amap.api.navi.AmapNaviParams; import com.amap.api.navi.AmapNaviType; import com.amap.api.navi.AmapPageType; -import com.amap.api.navi.INaviInfoCallback; -import com.amap.api.navi.enums.PathPlanningStrategy; import com.amap.api.navi.model.AMapCarInfo; -import com.amap.api.navi.model.AMapNaviLocation; import com.amap.api.services.core.AMapException; import com.amap.api.services.core.LatLonPoint; import com.amap.api.services.geocoder.GeocodeResult; @@ -54,7 +55,11 @@ import com.amap.api.services.geocoder.GeocodeSearch; import com.amap.api.services.geocoder.RegeocodeAddress; import com.amap.api.services.geocoder.RegeocodeQuery; import com.amap.api.services.geocoder.RegeocodeResult; +import com.amap.api.services.help.Inputtips; +import com.amap.api.services.help.InputtipsQuery; +import com.amap.api.services.help.Tip; import com.amap.api.services.route.BusRouteResult; +import com.amap.api.services.route.DrivePath; import com.amap.api.services.route.DriveRouteResult; import com.amap.api.services.route.RideRouteResult; import com.amap.api.services.route.RouteSearch; @@ -78,33 +83,33 @@ import okhttp3.RequestBody; import okhttp3.Response; /** - * 高德地图导航 + * 高德地图导航 Native View - 底部精简交互优化版 */ public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, - GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener { + GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener { private static final String TAG = "NativeMapView"; private final FrameLayout container; - - // 地图相关 private MapView mapView; private AMap aMap; private OnLocationChangedListener mListener; - // 定位相关 private AMapLocationClient mlocationClient; private final Context mContext; - private Activity mActivity; // 保存Activity引用用于导航 + private Activity mActivity; private GeocodeSearch geocoderSearch; private RouteSearch routeSearch; private final OkHttpClient httpClient = new OkHttpClient(); // UI组件 - private EditText startInput; private EditText endInput; + private LinearLayout searchArea; // 规划路线面板 + private LinearLayout detailPanel; // 详情面板 + private TextView tvStationName, tvStationAddr, tvRouteInfo; + private LatLng currentLatLng; private String startName = "我的位置"; - private String endName = "目的地"; + private String endName = ""; private LatLng startPoint; private LatLng endPoint; private boolean isFirstLocation = true; @@ -112,8 +117,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public NativeMapView(Context context, int id, Object args) { this.mContext = context; - - // 尝试获取Activity引用 mActivity = getActivityFromContext(context); MapsInitializer.updatePrivacyShow(context, true, true); @@ -127,24 +130,17 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation mapView.onCreate(null); aMap = mapView.getMap(); - container.addView(mapView, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + container.addView(mapView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); initServices(context); initOverlays(context); setupMapUi(); - // 通知MainActivity if (context instanceof MainActivity) { ((MainActivity) context).setMapView(this); } - - Log.d(TAG, "NativeMapView初始化完成"); } - /** - * 初始化服务 - */ private void initServices(Context context) { try { geocoderSearch = new GeocodeSearch(context); @@ -156,75 +152,209 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } - /** - * 初始化覆盖层UI - */ private void initOverlays(Context context) { - LinearLayout searchBox = new LinearLayout(context); - searchBox.setOrientation(LinearLayout.VERTICAL); - searchBox.setBackground(getRoundedDrawable(Color.WHITE, 12)); - searchBox.setElevation(dp2px(8)); - int p = dp2px(15); - searchBox.setPadding(p, p, p, p); - searchBox.setClickable(true); - searchBox.setFocusable(true); + // --- 底部主容器 (包含两个互斥显示的面板) --- + LinearLayout bottomContainer = new LinearLayout(context); + bottomContainer.setOrientation(LinearLayout.VERTICAL); + bottomContainer.setGravity(Gravity.BOTTOM); - startInput = createInput(context, "起点: 正在定位..."); - searchBox.addView(startInput); + // 1. 详情面板 (用于显示加氢站详细信息,初始隐藏) + detailPanel = createDetailPanel(context); + detailPanel.setVisibility(View.GONE); + bottomContainer.addView(detailPanel); + + // 2. 搜索规划面板 (初始显示) + searchArea = new LinearLayout(context); + searchArea.setOrientation(LinearLayout.VERTICAL); + searchArea.setBackground(getRoundedDrawable(Color.WHITE, 16)); + searchArea.setElevation(dp2px(10)); + int p = dp2px(15); + searchArea.setPadding(p, p, p, p); + + endInput = new EditText(context); + endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站"); + endInput.setTextSize(13); + endInput.setHintTextColor(Color.LTGRAY); + endInput.setPadding(dp2px(12), dp2px(12), dp2px(12), dp2px(12)); + endInput.setBackground(getRoundedDrawable(Color.parseColor("#F8F8F8"), 8)); + endInput.setSingleLine(true); + endInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + endInput.addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s.length() > 1) { + InputtipsQuery query = new InputtipsQuery(s.toString(), ""); + query.setCityLimit(true); + Inputtips inputtips = new Inputtips(mContext, query); + inputtips.setInputtipsListener(NativeMapView.this); + inputtips.requestInputtipsAsyn(); + } + } + @Override public void afterTextChanged(Editable s) {} + }); + searchArea.addView(endInput); View vSpace = new View(context); - searchBox.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(10))); + searchArea.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(12))); - LinearLayout endRow = new LinearLayout(context); - endRow.setOrientation(LinearLayout.HORIZONTAL); - endRow.setGravity(Gravity.CENTER_VERTICAL); + Button planBtn = new Button(context); + planBtn.setText("规划路线"); + planBtn.setTextColor(Color.WHITE); + planBtn.setTypeface(Typeface.DEFAULT_BOLD); + planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10)); + planBtn.setOnClickListener(v -> calculateRouteBeforeNavi()); + searchArea.addView(planBtn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48))); - endInput = createInput(context, "终点: 请输入目的地"); - endRow.addView(endInput, new LinearLayout.LayoutParams(0, dp2px(42), 1f)); + bottomContainer.addView(searchArea); - Button routeBtn = new Button(context); - routeBtn.setText("路径规划"); - routeBtn.setTextColor(Color.WHITE); - routeBtn.setAllCaps(false); - routeBtn.setTextSize(14); - routeBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 6)); - routeBtn.setOnClickListener(v -> startRouteSearch()); - endRow.addView(routeBtn, new LinearLayout.LayoutParams(dp2px(90), dp2px(42))); - - searchBox.addView(endRow); - - FrameLayout.LayoutParams searchParams = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - searchParams.setMargins(dp2px(15), dp2px(50), dp2px(15), 0); - container.addView(searchBox, searchParams); + // 设置统一的底部间距 + FrameLayout.LayoutParams bottomParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + bottomParams.gravity = Gravity.BOTTOM; + bottomParams.setMargins(dp2px(12), 0, dp2px(12), dp2px(65)); + container.addView(bottomContainer, bottomParams); + // --- 右下角定位按钮 --- ImageButton locBtn = new ImageButton(context); locBtn.setImageResource(android.R.drawable.ic_menu_mylocation); - locBtn.setBackground(getRoundedDrawable(Color.WHITE, 30)); + locBtn.setBackground(getRoundedDrawable(Color.WHITE, 25)); locBtn.setElevation(dp2px(4)); locBtn.setOnClickListener(v -> { - if (currentLatLng != null) { - aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); - } + if (currentLatLng != null) aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); }); - FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(50), dp2px(50)); - locParams.setMargins(0, 0, dp2px(20), dp2px(120)); + FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(44), dp2px(44)); + locParams.setMargins(0, 0, dp2px(15), dp2px(250)); // 调高一点,避开底部的面板 locParams.gravity = Gravity.BOTTOM | Gravity.END; container.addView(locBtn, locParams); } - private EditText createInput(Context context, String hint) { - EditText et = new EditText(context); - et.setHint(hint); - et.setTextSize(14f); - et.setTextColor(Color.BLACK); - et.setPadding(dp2px(12), dp2px(10), dp2px(12), dp2px(10)); - et.setBackground(getRoundedDrawable(Color.parseColor("#F5F5F5"), 6)); - et.setSingleLine(true); - et.setImeOptions(EditorInfo.IME_ACTION_DONE); - et.setFocusable(true); - et.setFocusableInTouchMode(true); - return et; + private LinearLayout createDetailPanel(Context context) { + LinearLayout panel = new LinearLayout(context); + panel.setOrientation(LinearLayout.VERTICAL); + panel.setBackground(getRoundedDrawable(Color.WHITE, 16)); + panel.setPadding(dp2px(20), dp2px(20), dp2px(20), dp2px(20)); + panel.setElevation(dp2px(12)); + + tvStationName = new TextView(context); + tvStationName.setTextSize(18); + tvStationName.setTextColor(Color.BLACK); + tvStationName.setTypeface(Typeface.DEFAULT_BOLD); + panel.addView(tvStationName); + + tvStationAddr = new TextView(context); + tvStationAddr.setTextSize(13); + tvStationAddr.setPadding(0, dp2px(4), 0, dp2px(10)); + tvStationAddr.setTextColor(Color.GRAY); + panel.addView(tvStationAddr); + + tvRouteInfo = new TextView(context); + tvRouteInfo.setTextSize(14); + tvRouteInfo.setTextColor(Color.parseColor("#333333")); + panel.addView(tvRouteInfo); + + Button startNaviBtn = new Button(context); + startNaviBtn.setText("开始导航"); + startNaviBtn.setTextColor(Color.WHITE); + startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10)); + startNaviBtn.setOnClickListener(v -> startRouteSearch()); + + LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48)); + btnParams.topMargin = dp2px(15); + panel.addView(startNaviBtn, btnParams); + + return panel; + } + + private void calculateRouteBeforeNavi() { + if (startPoint == null) { + Toast.makeText(mContext, "正在定位...", Toast.LENGTH_SHORT).show(); + return; + } + + if (endPoint == null) { + Toast.makeText(mContext, "请先选择目的地", Toast.LENGTH_SHORT).show(); + return; + } + + // 开始规划前隐藏输入框面板 + searchArea.setVisibility(View.GONE); + + RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo( + new LatLonPoint(startPoint.latitude, startPoint.longitude), + new LatLonPoint(endPoint.latitude, endPoint.longitude)); + RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, ""); + routeSearch.calculateDriveRouteAsyn(query); + } + + @Override + public void onGetInputtips(List tipList, int rCode) { + if (rCode == 1000 && tipList != null && !tipList.isEmpty()) { + Tip tip = tipList.get(0); + if (tip.getPoint() != null) { + endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude()); + endName = tip.getName(); + } + } + } + + @Override + public void onDriveRouteSearched(DriveRouteResult result, int rCode) { + if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) { + DrivePath path = result.getPaths().get(0); + + // 规划成功,显示详情面板 + detailPanel.setVisibility(View.VISIBLE); + tvStationName.setText(endName); + tvStationAddr.setText(endInput.getText().toString()); + + String info = String.format("预计时间:%d分钟 | 行驶里程:%.1f公里 | 预计路费:%.0f元", + path.getDuration() / 60, path.getDistance() / 1000f, path.getTolls()); + tvRouteInfo.setText(info); + + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f)); + } else { + // 规划失败回退面板 + searchArea.setVisibility(View.VISIBLE); + Toast.makeText(mContext, "路径规划失败: " + rCode, Toast.LENGTH_SHORT).show(); + } + } + + private void startRouteSearch() { + if (mActivity == null || startPoint == null || endPoint == null) return; + + Poi start = new Poi(startName, startPoint, ""); + Poi end = new Poi(endName, endPoint, ""); + AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); + + try { + AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber("沪AGK2267"); + carInfo.setCarType("1"); + mAMapNavi.setCarInfo(carInfo); + } catch (Exception e) { e.printStackTrace(); } + + AmapNaviPage.getInstance().showRouteActivity(mActivity, params, null); + } + + private void setupMapUi() { + aMap.setLocationSource(this); + aMap.setMyLocationEnabled(true); + aMap.setOnMarkerClickListener(this); + + MyLocationStyle myLocationStyle = new MyLocationStyle(); + try { + Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car); + if (carBitmap != null) { + Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, dp2px(30), dp2px(30), true); + myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap)); + } + } catch (Exception e) { e.printStackTrace(); } + + myLocationStyle.anchor(0.5f, 0.5f); + myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); + aMap.setMyLocationStyle(myLocationStyle); + aMap.getUiSettings().setZoomControlsEnabled(false); + aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT); } private GradientDrawable getRoundedDrawable(int color, int radiusDp) { @@ -239,55 +369,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics()); } - private void setupMapUi() { - aMap.setLocationSource(this); - aMap.setMyLocationEnabled(true); - aMap.setOnMarkerClickListener(this); - - MyLocationStyle myLocationStyle = new MyLocationStyle(); - - // --- 放大定位图标 --- - try { - Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car); - if (carBitmap != null) { - // 放大到 80dp - int iconSize = dp2px(25); - Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, iconSize, iconSize, true); - myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap)); - } - } catch (Exception e) { - Log.e(TAG, "设置大图标失败", e); - } - - myLocationStyle.anchor(0.5f, 0.5f); - myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); - myLocationStyle.showMyLocation(true); - myLocationStyle.strokeColor(Color.TRANSPARENT); - myLocationStyle.radiusFillColor(Color.TRANSPARENT); - aMap.setMyLocationStyle(myLocationStyle); - - aMap.getUiSettings().setZoomControlsEnabled(true); - aMap.getUiSettings().setScaleControlsEnabled(true); - aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT); - } - - // ==================== LocationSource 接口实现 ==================== - @Override - public void activate(OnLocationChangedListener listener) { - mListener = listener; - startLocation(); - } - - @Override - public void deactivate() { - mListener = null; - if (mlocationClient != null) { - mlocationClient.stopLocation(); - mlocationClient.onDestroy(); - } - mlocationClient = null; - } - + @Override public void activate(OnLocationChangedListener listener) { mListener = listener; startLocation(); } + @Override public void deactivate() { mListener = null; if (mlocationClient != null) mlocationClient.stopLocation(); } + public void startLocation() { if (mlocationClient == null) { try { @@ -297,135 +381,49 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); mlocationClient.setLocationOption(option); mlocationClient.startLocation(); - Log.d(TAG, "定位启动成功"); - } catch (Exception e) { - Log.e(TAG, "定位启动失败", e); - } + } catch (Exception e) { e.printStackTrace(); } } } @Override public void onLocationChanged(AMapLocation loc) { - if (loc != null) { - if (mListener != null) { - mListener.onLocationChanged(loc); - } + if (loc != null && loc.getErrorCode() == 0) { currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude()); - - if (loc.getErrorCode() == 0) { - if (isFirstLocation) { - isFirstLocation = false; - startPoint = currentLatLng; - aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f)); - getAddressByLatlng(currentLatLng); - fetchRecommendStation(loc); - fetchNearbyStations(loc); - } + if (mListener != null) mListener.onLocationChanged(loc); + if (isFirstLocation) { + isFirstLocation = false; + startPoint = currentLatLng; + aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f)); + getAddressByLatlng(currentLatLng); + fetchRecommendStation(loc); + fetchNearbyStations(loc); } } } - // ==================== 逆地理编码 ==================== private void getAddressByLatlng(LatLng latLng) { - LatLonPoint point = new LatLonPoint(latLng.latitude, latLng.longitude); - RegeocodeQuery query = new RegeocodeQuery(point, 200, GeocodeSearch.AMAP); - geocoderSearch.getFromLocationAsyn(query); + geocoderSearch.getFromLocationAsyn(new RegeocodeQuery(new LatLonPoint(latLng.latitude, latLng.longitude), 200, GeocodeSearch.AMAP)); } @Override public void onRegeocodeSearched(RegeocodeResult result, int rCode) { - if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && result.getRegeocodeAddress() != null) { + if (rCode == 1000 && result != null) { RegeocodeAddress addr = result.getRegeocodeAddress(); - String fullAddr = addr.getFormatAddress(); - - // 优化地址显示逻辑 - startName = formatAddress(fullAddr,result); - - new Handler(Looper.getMainLooper()).post(() -> { - startInput.setText(startName); - startInput.setSelection(startName.length()); // 光标移到末尾 - }); - - Log.d(TAG, "逆地理编码成功: " + startName); - } else { - Log.e(TAG, "逆地理编码失败: code=" + rCode + ", result=" + (result != null ? "null" : "has data")); + startName = addr.getStreetNumber() != null ? addr.getStreetNumber().getStreet() : addr.getDistrict(); } } - /** - * 格式化地址显示,移除重复的前缀并限制长度 - */ - private String formatAddress(String fullAddress,RegeocodeResult result) { - if (fullAddress == null || fullAddress.isEmpty()) { - return "未知地点"; - } - - // 获取各级地址信息 - String province = null; - String city = null; - String district = null; - String township = null; - - try { - if (result.getRegeocodeAddress() != null) { - RegeocodeAddress addr = result.getRegeocodeAddress(); - province = addr.getProvince(); - city = addr.getCity(); - district = addr.getDistrict(); - township = addr.getTownship(); - } - } catch (Exception e) { - Log.e(TAG, "获取地址信息失败", e); - } - - String formattedAddr = fullAddress; - - // 按优先级移除重复前缀(省、市、区、乡) - String[] prefixes = {province, city, district, township}; - for (String prefix : prefixes) { - if (prefix != null && !prefix.isEmpty() && formattedAddr.startsWith(prefix)) { - formattedAddr = formattedAddr.substring(prefix.length()); - Log.d(TAG, "移除前缀: " + prefix + " -> " + formattedAddr); - } - } - - // 限制地址长度并添加省略号 - if (formattedAddr.length() > 25) { - formattedAddr = formattedAddr.substring(0, 25) + "..."; - Log.d(TAG, "地址长度截断: " + formattedAddr); - } - - return formattedAddr; - } - - @Override - public void onGeocodeSearched(GeocodeResult result, int rCode) { - } - - // ==================== API请求 ==================== - private void fetchRecommendStation(AMapLocation loc) { try { JSONObject json = new JSONObject(); - json.put("province", loc.getProvince() != null ? loc.getProvince() : ""); - json.put("city", loc.getCity() != null && !loc.getCity().isEmpty() ? loc.getCity() : ""); - json.put("district", loc.getDistrict() != null ? loc.getDistrict() : ""); - json.put("longitude", String.valueOf(loc.getLongitude())); - json.put("latitude", String.valueOf(loc.getLatitude())); + json.put("province", loc.getProvince()); + json.put("city", loc.getCity().isEmpty() ? loc.getProvince() : loc.getCity()); + json.put("longitude", loc.getLongitude()); + json.put("latitude", loc.getLatitude()); - RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); - Request request = new Request.Builder() - .url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea") - .post(body) - .build(); - - httpClient.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(@NonNull Call call, @NonNull IOException e) { - } - - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { + @Override public void onFailure(@NonNull Call call, @NonNull IOException e) {} + @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful() && response.body() != null) { try { JSONObject res = new JSONObject(response.body().string()); @@ -439,68 +437,43 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation markStation(endPoint, endName, true); }); } - } catch (Exception e) { - e.printStackTrace(); - } + } catch (Exception e) { e.printStackTrace(); } } } }); - } catch (Exception e) { - e.printStackTrace(); - } + } catch (Exception e) { e.printStackTrace(); } } private void fetchNearbyStations(AMapLocation loc) { try { JSONObject json = new JSONObject(); - json.put("longitude", String.valueOf(loc.getLongitude())); - json.put("latitude", String.valueOf(loc.getLatitude())); + json.put("longitude", loc.getLongitude()); + json.put("latitude", loc.getLatitude()); - RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); - Request request = new Request.Builder() - .url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation") - .post(body) - .build(); - - httpClient.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(@NonNull Call call, @NonNull IOException e) { - } - - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { + @Override public void onFailure(@NonNull Call call, @NonNull IOException e) {} + @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful() && response.body() != null) { try { JSONObject res = new JSONObject(response.body().string()); - if (res.getInt("code") == 0 && !res.isNull("data")) { - JSONArray array = res.getJSONArray("data"); - new Handler(Looper.getMainLooper()).post(() -> { - for (int i = 0; i < array.length(); i++) { - try { - JSONObject item = array.getJSONObject(i); - markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), - item.getString("name"), false); - } catch (Exception ignored) { - } - } - }); - } - } catch (Exception e) { - e.printStackTrace(); - } + JSONArray array = res.getJSONArray("data"); + new Handler(Looper.getMainLooper()).post(() -> { + for (int i = 0; i < array.length(); i++) { + try { + JSONObject item = array.getJSONObject(i); + markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), item.getString("name"), false); + } catch (Exception ignored) {} + } + }); + } catch (Exception e) { e.printStackTrace(); } } } }); - } catch (Exception e) { - e.printStackTrace(); - } + } catch (Exception e) { e.printStackTrace(); } } private void markStation(LatLng latLng, String name, boolean isRecommend) { - MarkerOptions opt = new MarkerOptions() - .position(latLng).title(name) - .icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN)); - Marker m = aMap.addMarker(opt); + Marker m = aMap.addMarker(new MarkerOptions().position(latLng).title(name).icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN))); m.setObject(latLng); stationMarkers.add(m); } @@ -511,185 +484,28 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation endPoint = (LatLng) marker.getObject(); endName = marker.getTitle(); endInput.setText(endName); - startRouteSearch(); + calculateRouteBeforeNavi(); } return true; } - // ==================== 路径规划 ==================== - - private void startRouteSearch() { - if (startPoint == null || endPoint == null) { - Toast.makeText(mContext, "正在定位中,请稍后...", Toast.LENGTH_SHORT).show(); - return; - } - - Poi start = new Poi(startName, startPoint, ""); - Poi end = new Poi(endName, endPoint, ""); - - AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); - - try { - AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); - AMapCarInfo carInfo = new AMapCarInfo(); - carInfo.setCarNumber("沪AGK2267"); - carInfo.setCarType("1"); - carInfo.setVehicleAxis("6"); - carInfo.setVehicleHeight("3.32"); - carInfo.setVehicleLength("6.9"); - carInfo.setVehicleWidth("2.26"); - carInfo.setVehicleSize("2"); - carInfo.setVehicleLoad("4.5"); - carInfo.setVehicleWeight("4.5"); - carInfo.setRestriction(true); - carInfo.setVehicleLoadSwitch(true); - mAMapNavi.setCarInfo(carInfo); - } catch (com.amap.api.maps.AMapException e) { - Log.e(TAG, "设置车辆信息失败", e); - } - - params.setRouteStrategy(PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); - - if (mActivity != null) { - AmapNaviPage.getInstance().showRouteActivity(mActivity, params, new INaviInfoCallback() { - @Override - public void onInitNaviFailure() { - Log.e(TAG, "导航初始化失败"); - } - - @Override - public void onGetNavigationText(String s) { - } - - @Override - public void onLocationChange(AMapNaviLocation location) { - } - - @Override - public void onArriveDestination(boolean b) { - } - - @Override - public void onStartNavi(int i) { - } - - @Override - public void onCalculateRouteSuccess(int[] ints) { - } - - @Override - public void onCalculateRouteFailure(int i) { - } - - @Override - public void onStopSpeaking() { - } - - @Override - public void onReCalculateRoute(int i) { - - } - - @Override - public void onArrivedWayPoint(int i) { - } - - @Override - public void onExitPage(int i) { - } - - @Override - public void onStrategyChanged(int i) { - } - - @Override - public void onMapTypeChanged(int i) { - } - - @Override - public void onNaviDirectionChanged(int i) { - } - - @Override - public void onDayAndNightModeChanged(int i) { - } - - @Override - public void onBroadcastModeChanged(int i) { - } - - @Override - public void onScaleAutoChanged(boolean b) { - } - - @Override - public View getCustomNaviBottomView() { - return null; - } - - @Override - public View getCustomNaviView() { - return null; - } - - @Override - public View getCustomMiddleView() { - return null; - } - }); - } - } - - @Override - public void onDriveRouteSearched(DriveRouteResult result, int rCode) { - } - - @Override - public void onBusRouteSearched(BusRouteResult r, int c) { - } - - @Override - public void onWalkRouteSearched(WalkRouteResult r, int c) { - } - - @Override - public void onRideRouteSearched(RideRouteResult r, int c) { - } + @Override public void onGeocodeSearched(GeocodeResult r, int c) {} + @Override public void onBusRouteSearched(BusRouteResult r, int c) {} + @Override public void onWalkRouteSearched(WalkRouteResult r, int c) {} + @Override public void onRideRouteSearched(RideRouteResult r, int c) {} private Activity getActivityFromContext(Context context) { - if (context instanceof Activity) - return (Activity) context; - if (context instanceof android.content.ContextWrapper) { - Context base = ((android.content.ContextWrapper) context).getBaseContext(); - if (base instanceof Activity) - return (Activity) base; - } + if (context instanceof Activity) return (Activity) context; + if (context instanceof android.content.ContextWrapper) return getActivityFromContext(((android.content.ContextWrapper) context).getBaseContext()); return null; } - public void onResume() { - mapView.onResume(); - } - - public void onPause() { - mapView.onPause(); - } - - public void onSaveInstanceState(Bundle out) { - mapView.onSaveInstanceState(out); - } - - @Override - public View getView() { - return container; - } - - @Override - public void dispose() { - if (mlocationClient != null) { - mlocationClient.stopLocation(); - mlocationClient.onDestroy(); - } + public void onResume() { mapView.onResume(); } + public void onPause() { mapView.onPause(); } + public void onSaveInstanceState(Bundle out) { mapView.onSaveInstanceState(out); } + @Override public View getView() { return container; } + @Override public void dispose() { + if (mlocationClient != null) { mlocationClient.stopLocation(); mlocationClient.onDestroy(); } mapView.onDestroy(); } } diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index 8b5621d..f26e170 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -49,6 +49,9 @@ PODS: - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - shared_preferences_foundation (0.0.1): @@ -70,6 +73,7 @@ DEPENDENCIES: - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -114,6 +118,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/mobile_scanner/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" shared_preferences_foundation: @@ -125,28 +131,29 @@ SPEC CHECKSUMS: AlicloudELS: fbf821383330465a5af84a033f36f263ae46ca41 AlicloudPush: 52cbf38ffc20c07f039cbc72d5738745fd986215 AlicloudUTDID: 5d2f22d50e11eecd38f30bc7a48c71925ea90976 - aliyun_push_flutter: ab0bf7112ef3797f506770a7a9f47f004635a9f6 + aliyun_push_flutter: 0fc2f048a08687ef256c0cfdd72dd7a550ef3347 AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05 AMapLocation-NO-IDFA: 590fd42af0c8ea9eac26978348221bbc16be4ef9 AMapNavi-NO-IDFA: 22edfa7d6a81d75c91756e31b6c26b7746152233 - AMapNavIOSSDK: 0cd6ec22ab6b6aba268028a5b580e18bb8066f7e + AMapNavIOSSDK: ca325c9ac3378daea6a6be4bd8c34fe48d3ac896 AMapSearch-NO-IDFA: 53b2193244be8f07f3be0a4d5161200236960587 - connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d - device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d + connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd + device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 - flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29 - flutter_pdfview: 2e4d13ffb774858562ffbdfdb61b40744b191adc - geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd - image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf + flutter_pdfview: 32bf27bda6fd85b9dd2c09628a824df5081246cf + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8 - mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e + mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 - url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b PODFILE CHECKSUM: 97188da9dab9d4b3372eb4c16e872fbd555fdbea diff --git a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj index 55acb81..6ed39fa 100644 --- a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj +++ b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj @@ -477,8 +477,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; @@ -742,8 +741,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; @@ -844,8 +842,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = 2228B9MS38; ENABLE_BITCODE = NO; diff --git a/ln_jq_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ln_jq_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e3773d4..b213f83 100644 --- a/ln_jq_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ln_jq_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -61,6 +61,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUFrameCaptureMode = "3" enableGPUValidationMode = "1" allowLocationSimulation = "YES"> aps-environment development + com.apple.developer.background-tasks.continued-processing.gpu + + com.apple.developer.location.push + diff --git a/ln_jq_app/lib/common/styles/theme.dart b/ln_jq_app/lib/common/styles/theme.dart index d925319..4406085 100644 --- a/ln_jq_app/lib/common/styles/theme.dart +++ b/ln_jq_app/lib/common/styles/theme.dart @@ -12,7 +12,7 @@ class AppTheme { //http://192.168.110.222:8080/ //http://192.168.110.44:8080/ - static String test_service_url = "http://47.101.201.13:8443/api/"; + static String test_service_url = "https://beta-esg.api.lnh2e.com/"; static const String release_service_url = ""; //加氢站相关查询 diff --git a/ln_jq_app/lib/main.dart b/ln_jq_app/lib/main.dart index 8f0a668..1fafdc1 100644 --- a/ln_jq_app/lib/main.dart +++ b/ln_jq_app/lib/main.dart @@ -16,7 +16,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); WidgetsBinding widgetsBinding = await init( - isDebug: false, + isDebug: true, logTag: '小羚羚', supportedLocales: [const Locale('zh', 'CN')], ); @@ -34,7 +34,7 @@ void main() async { // 设计稿尺寸 单位:dp designSize: const Size(390, 844), // Getx Log - enableLog: false, + enableLog: true, // 默认的跳转动画 defaultTransition: Transition.rightToLeft, // 主题模式 @@ -77,7 +77,7 @@ void initHttpSet() { return null; } else if (baseModel.code == 401) { await StorageService.to.clearLoginInfo(); - // Get.offAll(() => const LoginPage()); + Get.offAll(() => const LoginPage()); return baseModel.message; } else { return (baseModel.error.toString()).isEmpty 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 4e9db82..f525e37 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 @@ -1,10 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:ln_jq_app/common/login_util.dart'; import 'package:ln_jq_app/pages/c_page/base_widgets/NativePageIOS.dart'; import 'package:ln_jq_app/pages/c_page/car_info/view.dart'; -import 'package:ln_jq_app/pages/c_page/map/view.dart'; import 'package:ln_jq_app/pages/c_page/mine/view.dart'; import 'package:ln_jq_app/pages/c_page/reservation/view.dart'; diff --git a/ln_jq_app/lib/pages/home/controller.dart b/ln_jq_app/lib/pages/home/controller.dart index 4919c47..7c339cb 100644 --- a/ln_jq_app/lib/pages/home/controller.dart +++ b/ln_jq_app/lib/pages/home/controller.dart @@ -43,8 +43,7 @@ class HomeController extends GetxController with BaseControllerMixin { } } else { // 未登录,直接去登录页 - return BaseWidgetsPage(); - // return LoginPage(); + return LoginPage(); } } From d3edf95df3d2abde44c0fe2235f1761b77e1a03b Mon Sep 17 00:00:00 2001 From: userGyl Date: Tue, 24 Mar 2026 09:38:16 +0800 Subject: [PATCH 09/19] =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E8=BD=A6=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ios/Runner.xcodeproj/project.pbxproj | 4 + ln_jq_app/lib/storage_service.dart | 7 + ln_jq_app/pubspec.lock | 438 ++++++++---------- ln_jq_app/pubspec.yaml | 1 + 4 files changed, 203 insertions(+), 247 deletions(-) diff --git a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj index 6ed39fa..27a8385 100644 --- a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj +++ b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj @@ -357,10 +357,14 @@ 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", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; diff --git a/ln_jq_app/lib/storage_service.dart b/ln_jq_app/lib/storage_service.dart index ec73139..9d5f595 100644 --- a/ln_jq_app/lib/storage_service.dart +++ b/ln_jq_app/lib/storage_service.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:getx_scaffold/common/utils/log_util.dart'; import 'package:ln_jq_app/common/model/vehicle_info.dart'; +import 'package:shared_preferences/shared_preferences.dart'; /// 定义登录渠道的枚举类型 enum LoginChannel { @@ -103,6 +104,9 @@ class StorageService extends GetxService { Future saveVehicleInfo(VehicleInfo data) async { await _box.write(_vehicleInfoKey, vehicleInfoToJson(data)); + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('plateNumber', data.plateNumber ?? ""); } Future saveStationCredentials(String account, String password) async { @@ -117,6 +121,9 @@ class StorageService extends GetxService { Future clearVehicleInfo() async { await _box.remove(_vehicleInfoKey); + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.remove('plateNumber'); } Future clearStationCredentials() async { diff --git a/ln_jq_app/pubspec.lock b/ln_jq_app/pubspec.lock index e252a45..33eec3f 100644 --- a/ln_jq_app/pubspec.lock +++ b/ln_jq_app/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: aliyun_push_flutter sha256: fd1a13ab37f30274e1eaa9c0f68001bf268f8f2e1c83730b4520aa4dff46ce70 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.6" ansicolor: @@ -14,23 +14,23 @@ packages: description: name: ansicolor sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" archive: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" asn1lib: @@ -38,7 +38,7 @@ packages: description: name: asn1lib sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.6.5" async: @@ -46,7 +46,7 @@ packages: description: name: async sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.13.0" badges: @@ -54,7 +54,7 @@ packages: description: name: badges sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.2" boolean_selector: @@ -62,7 +62,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" characters: @@ -70,7 +70,7 @@ packages: description: name: characters sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" clock: @@ -78,23 +78,15 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" - source: hosted - version: "1.0.0" collection: dependency: transitive description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.19.1" connectivity_plus: @@ -102,7 +94,7 @@ packages: description: name: connectivity_plus sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.5" connectivity_plus_platform_interface: @@ -110,7 +102,7 @@ packages: description: name: connectivity_plus_platform_interface sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" convert: @@ -118,7 +110,7 @@ packages: description: name: convert sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.2" cross_file: @@ -126,7 +118,7 @@ packages: description: name: cross_file sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.5+2" crypto: @@ -134,7 +126,7 @@ packages: description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.7" csslib: @@ -142,7 +134,7 @@ packages: description: name: csslib sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" cupertino_icons: @@ -150,7 +142,7 @@ packages: description: name: cupertino_icons sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.8" dbus: @@ -158,7 +150,7 @@ packages: description: name: dbus sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.12" decimal: @@ -166,7 +158,7 @@ packages: description: name: decimal sha256: fc706a5618b81e5b367b01dd62621def37abc096f2b46a9bd9068b64c1fa36d0 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.4" device_info_plus: @@ -174,7 +166,7 @@ packages: description: name: device_info_plus sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "10.1.2" device_info_plus_platform_interface: @@ -182,31 +174,31 @@ packages: description: name: device_info_plus_platform_interface sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.3" dio: dependency: transitive description: name: dio - sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25 - url: "https://pub.dev" + sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c + url: "https://pub.flutter-io.cn" source: hosted - version: "5.9.1" + version: "5.9.2" dio_web_adapter: dependency: transitive description: name: dio_web_adapter - sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" - url: "https://pub.dev" + sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.2" dropdown_button2: dependency: "direct main" description: name: dropdown_button2 sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.9" encrypt: @@ -214,7 +206,7 @@ packages: description: name: encrypt sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.3" event_bus: @@ -222,7 +214,7 @@ packages: description: name: event_bus sha256: "1a55e97923769c286d295240048fc180e7b0768902c3c2e869fe059aafa15304" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" extended_image: @@ -230,7 +222,7 @@ packages: description: name: extended_image sha256: "69d4299043334ecece679996e47d0b0891cd8c29d8da0034868443506f1d9a78" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.3.1" extended_image_library: @@ -238,7 +230,7 @@ packages: description: name: extended_image_library sha256: e61dafd94400fff6ef7ed1523d445ff3af137f198f3228e4a3107bc5b4bec5d1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.6" fake_async: @@ -246,23 +238,23 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c - url: "https://pub.dev" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.5" + version: "2.2.0" file: dependency: transitive description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.1" file_selector_linux: @@ -270,7 +262,7 @@ packages: description: name: file_selector_linux sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.4" file_selector_macos: @@ -278,7 +270,7 @@ packages: description: name: file_selector_macos sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.5" file_selector_platform_interface: @@ -286,7 +278,7 @@ packages: description: name: file_selector_platform_interface sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" file_selector_windows: @@ -294,7 +286,7 @@ packages: description: name: file_selector_windows sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3+5" fixnum: @@ -302,7 +294,7 @@ packages: description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" flutter: @@ -315,7 +307,7 @@ packages: description: name: flutter_easyloading sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.5" flutter_inappwebview: @@ -323,7 +315,7 @@ packages: description: name: flutter_inappwebview sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.5" flutter_inappwebview_android: @@ -331,7 +323,7 @@ packages: description: name: flutter_inappwebview_android sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.3" flutter_inappwebview_internal_annotations: @@ -339,7 +331,7 @@ packages: description: name: flutter_inappwebview_internal_annotations sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" flutter_inappwebview_ios: @@ -347,7 +339,7 @@ packages: description: name: flutter_inappwebview_ios sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_macos: @@ -355,7 +347,7 @@ packages: description: name: flutter_inappwebview_macos sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_platform_interface: @@ -363,7 +355,7 @@ packages: description: name: flutter_inappwebview_platform_interface sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0+1" flutter_inappwebview_web: @@ -371,7 +363,7 @@ packages: description: name: flutter_inappwebview_web sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_windows: @@ -379,7 +371,7 @@ packages: description: name: flutter_inappwebview_windows sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.0" flutter_lints: @@ -387,7 +379,7 @@ packages: description: name: flutter_lints sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.0" flutter_localizations: @@ -400,7 +392,7 @@ packages: description: name: flutter_native_splash sha256: "4fb9f4113350d3a80841ce05ebf1976a36de622af7d19aca0ca9a9911c7ff002" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.7" flutter_pdfview: @@ -408,7 +400,7 @@ packages: description: name: flutter_pdfview sha256: c0b2cc4ebf461a5a4bb9312a165222475a7d93845c7a0703f4abb7f442eb6d54 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.3" flutter_plugin_android_lifecycle: @@ -416,7 +408,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.33" flutter_screenutil: @@ -424,7 +416,7 @@ packages: description: name: flutter_screenutil sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.9.3" flutter_spinkit: @@ -432,17 +424,17 @@ packages: description: name: flutter_spinkit sha256: "77850df57c00dc218bfe96071d576a8babec24cf58b2ed121c83cca4a2fdce7f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.2.2" flutter_svg: dependency: transitive description: name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" + sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.3" + version: "2.2.4" flutter_test: dependency: "direct dev" description: flutter @@ -458,7 +450,7 @@ packages: description: name: geoclue sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.1" geolocator: @@ -466,7 +458,7 @@ packages: description: name: geolocator sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "14.0.2" geolocator_android: @@ -474,7 +466,7 @@ packages: description: name: geolocator_android sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.2" geolocator_apple: @@ -482,7 +474,7 @@ packages: description: name: geolocator_apple sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.13" geolocator_linux: @@ -490,7 +482,7 @@ packages: description: name: geolocator_linux sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.3" geolocator_platform_interface: @@ -498,7 +490,7 @@ packages: description: name: geolocator_platform_interface sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.6" geolocator_web: @@ -506,7 +498,7 @@ packages: description: name: geolocator_web sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.3" geolocator_windows: @@ -514,7 +506,7 @@ packages: description: name: geolocator_windows sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.5" get: @@ -522,7 +514,7 @@ packages: description: name: get sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.7.3" get_storage: @@ -530,7 +522,7 @@ packages: description: name: get_storage sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" getx_scaffold: @@ -538,39 +530,23 @@ packages: description: name: getx_scaffold sha256: caf11b370c20840352230f50221bcef1454b30ec56cce10ba25741fbbdf0a806 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" gsettings: dependency: transitive description: name: gsettings sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.8" - hooks: - dependency: transitive - description: - name: hooks - sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" html: dependency: transitive description: name: html sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.15.6" http: @@ -578,7 +554,7 @@ packages: description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.6.0" http_client_helper: @@ -586,7 +562,7 @@ packages: description: name: http_client_helper sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" http_parser: @@ -594,55 +570,55 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.2" image: dependency: "direct main" description: name: image - sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c" - url: "https://pub.dev" + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + url: "https://pub.flutter-io.cn" source: hosted - version: "4.7.2" + version: "4.8.0" image_picker: dependency: "direct main" description: name: image_picker sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "518a16108529fc18657a3e6dde4a043dc465d16596d20ab2abd49a4cac2e703d" - url: "https://pub.dev" + sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156 + url: "https://pub.flutter-io.cn" source: hosted - version: "0.8.13+13" + version: "0.8.13+14" image_picker_for_web: dependency: transitive description: name: image_picker_for_web sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 - url: "https://pub.dev" + sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.8.13+6" + version: "0.8.13+3" image_picker_linux: dependency: transitive description: name: image_picker_linux sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" image_picker_macos: @@ -650,7 +626,7 @@ packages: description: name: image_picker_macos sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2+1" image_picker_platform_interface: @@ -658,7 +634,7 @@ packages: description: name: image_picker_platform_interface sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.11.1" image_picker_windows: @@ -666,7 +642,7 @@ packages: description: name: image_picker_windows sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" intl: @@ -674,7 +650,7 @@ packages: description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.19.0" js: @@ -682,7 +658,7 @@ packages: description: name: js sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.2" leak_tracker: @@ -690,7 +666,7 @@ packages: description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -698,7 +674,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.10" leak_tracker_testing: @@ -706,7 +682,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" lints: @@ -714,23 +690,15 @@ packages: description: name: lints sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" lottie: dependency: transitive description: name: lottie sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.2" matcher: @@ -738,7 +706,7 @@ packages: description: name: matcher sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.17" material_color_utilities: @@ -746,71 +714,55 @@ packages: description: name: material_color_utilities sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.flutter-io.cn" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" mobile_scanner: dependency: "direct main" description: name: mobile_scanner - sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 - url: "https://pub.dev" + sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce + url: "https://pub.flutter-io.cn" source: hosted - version: "7.1.4" + version: "7.2.0" modal_bottom_sheet: dependency: transitive description: name: modal_bottom_sheet sha256: eac66ef8cb0461bf069a38c5eb0fa728cee525a531a8304bd3f7b2185407c67e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" - url: "https://pub.dev" - source: hosted - version: "0.17.4" nm: dependency: transitive description: name: nm sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.0" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" package_info_plus: dependency: transitive description: name: package_info_plus sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.3.1" package_info_plus_platform_interface: @@ -818,7 +770,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" path: @@ -826,7 +778,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" path_parsing: @@ -834,7 +786,7 @@ packages: description: name: path_parsing sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" path_provider: @@ -842,7 +794,7 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.5" path_provider_android: @@ -850,23 +802,23 @@ packages: description: name: path_provider_android sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.22" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.6.0" + version: "2.5.1" path_provider_linux: dependency: transitive description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -874,7 +826,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" path_provider_windows: @@ -882,7 +834,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" permission_handler: @@ -890,7 +842,7 @@ packages: description: name: permission_handler sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "11.4.0" permission_handler_android: @@ -898,7 +850,7 @@ packages: description: name: permission_handler_android sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "12.1.0" permission_handler_apple: @@ -906,7 +858,7 @@ packages: description: name: permission_handler_apple sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "9.4.7" permission_handler_html: @@ -914,7 +866,7 @@ packages: description: name: permission_handler_html sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3+5" permission_handler_platform_interface: @@ -922,7 +874,7 @@ packages: description: name: permission_handler_platform_interface sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.3.0" permission_handler_windows: @@ -930,23 +882,23 @@ packages: description: name: permission_handler_windows sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.1" petitparser: dependency: transitive description: name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.dev" + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.flutter-io.cn" source: hosted - version: "7.0.1" + version: "7.0.2" photo_view: dependency: "direct main" description: name: photo_view sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.15.0" platform: @@ -954,7 +906,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.6" plugin_platform_interface: @@ -962,7 +914,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.8" pointycastle: @@ -970,31 +922,23 @@ packages: description: name: pointycastle sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.9.1" posix: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.flutter-io.cn" source: hosted - version: "6.0.3" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" + version: "6.5.0" pull_to_refresh: dependency: "direct main" description: name: pull_to_refresh sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" rational: @@ -1002,31 +946,31 @@ packages: description: name: rational sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.3" shared_preferences: - dependency: transitive + dependency: "direct main" description: name: shared_preferences sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.4" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f - url: "https://pub.dev" + sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.20" + version: "2.4.21" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.6" shared_preferences_linux: @@ -1034,7 +978,7 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" shared_preferences_platform_interface: @@ -1042,7 +986,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" shared_preferences_web: @@ -1050,7 +994,7 @@ packages: description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.3" shared_preferences_windows: @@ -1058,7 +1002,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" sky_engine: @@ -1071,7 +1015,7 @@ packages: description: name: slider_captcha sha256: "0fc2e0e8af7bf0e7ece23b8213e6becf841dd7839a40ad4b2a5071eaf5135774" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" source_span: @@ -1079,7 +1023,7 @@ packages: description: name: source_span sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.2" stack_trace: @@ -1087,7 +1031,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.12.1" stream_channel: @@ -1095,7 +1039,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" string_scanner: @@ -1103,7 +1047,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" term_glyph: @@ -1111,23 +1055,23 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" universal_io: @@ -1135,7 +1079,7 @@ packages: description: name: universal_io sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" url_launcher: @@ -1143,7 +1087,7 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.2" url_launcher_android: @@ -1151,7 +1095,7 @@ packages: description: name: url_launcher_android sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.28" url_launcher_ios: @@ -1159,7 +1103,7 @@ packages: description: name: url_launcher_ios sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.6" url_launcher_linux: @@ -1167,7 +1111,7 @@ packages: description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.2" url_launcher_macos: @@ -1175,7 +1119,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -1183,39 +1127,39 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.2" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.5" uuid: dependency: transitive description: name: uuid - sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 - url: "https://pub.dev" + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.5.2" + version: "4.5.3" vector_graphics: dependency: transitive description: name: vector_graphics sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.19" vector_graphics_codec: @@ -1223,23 +1167,23 @@ packages: description: name: vector_graphics_codec sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "201e876b5d52753626af64b6359cd13ac6011b80728731428fd34bc840f71c9b" - url: "https://pub.dev" + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.20" + version: "1.2.0" vector_math: dependency: transitive description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" vm_service: @@ -1247,7 +1191,7 @@ packages: description: name: vm_service sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "15.0.2" web: @@ -1255,7 +1199,7 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" win32: @@ -1263,7 +1207,7 @@ packages: description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.15.0" win32_registry: @@ -1271,7 +1215,7 @@ packages: description: name: win32_registry sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.5" xdg_directories: @@ -1279,7 +1223,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" xml: @@ -1287,7 +1231,7 @@ packages: description: name: xml sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.6.1" yaml: @@ -1295,9 +1239,9 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.3" sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.35.0" diff --git a/ln_jq_app/pubspec.yaml b/ln_jq_app/pubspec.yaml index 2416bf3..4ef1118 100644 --- a/ln_jq_app/pubspec.yaml +++ b/ln_jq_app/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: encrypt: ^5.0.3 get_storage: ^2.1.1 + shared_preferences: ^2.5.4 flutter_native_splash: ^2.4.7 dropdown_button2: ^2.3.8 From c10c92afdcbf17a4c995654e76aa78721bd64cc0 Mon Sep 17 00:00:00 2001 From: userGyl Date: Wed, 25 Mar 2026 11:02:15 +0800 Subject: [PATCH 10/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lnkj/ln_jq_app/NativeMapView.java | 519 ++++++++++++++++-- ln_jq_app/lib/storage_service.dart | 6 +- 2 files changed, 482 insertions(+), 43 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 6932c81..eebc2d9 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -47,7 +47,9 @@ import com.amap.api.navi.AmapNaviPage; import com.amap.api.navi.AmapNaviParams; import com.amap.api.navi.AmapNaviType; import com.amap.api.navi.AmapPageType; +import com.amap.api.navi.enums.PathPlanningStrategy; import com.amap.api.navi.model.AMapCarInfo; +import com.amap.api.navi.model.NaviPoi; import com.amap.api.services.core.AMapException; import com.amap.api.services.core.LatLonPoint; import com.amap.api.services.geocoder.GeocodeResult; @@ -115,6 +117,125 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private boolean isFirstLocation = true; private final List stationMarkers = new ArrayList<>(); + // 存储token和车牌号 + private String token; + private String plateNumber; + + // 存储货车路线算法接口返回的数据 + private TruckRouteData truckRouteData; + + // 货车路线算法数据Bean + public static class TruckRouteData { + public TruckDto truckDto; + public String truckDtoStr; + public DestinationSite destinationSite; + public PathDto pathDto; + public AlgorithmPath algorithmPath; + public boolean isInvokeAlgorithm; + } + + public static class TruckDto { + public boolean isRestriction; + public String mvehicleSizeName; + public String mvehicleAxisUnit; + public String mcarNumber; + public int mcarType; + public String mvehicleHeight; + public String mvehicleHeightUnit; + public String mvehicleWeight; + public String mvehicleWeightUnit; + public String mvehicleLoad; + public String mvehicleLoadUnit; + public boolean mvehicleLoadSwitch; + public String mvehicleWidth; + public String mvehicleWidthUnit; + public String mvehicleLength; + public String mvehicleLengthUnit; + public int mvehicleSize; + public int mvehicleAxis; + } + + public static class PathDto { + public int distance; + public int duration; + public String strategy; + public String tolls; + public int toll_distance; + public int restriction; + public int traffic_lights; + public List naviList; + } + + public static class NaviPoint { + public String name; + public String poiId; + public Coordinate coordinate; + } + + public static class Coordinate { + public String longitude; + public String latitude; + } + + public static class AlgorithmPath { + public String tripRecommendationId; + public String staId; + public String tripOneWayPathId; + public String tripReturnPathId; + public String oneWayDis; + public String returnDis; + public String roundTripDis; + public String oneWayTime; + public String returnTime; + public String roundTripTime; + public String oneWayCost; + public String returnCost; + public String roundTripCost; + public String oneWayLaborCost; + public String returnLaborCost; + public String roundTripLaborCost; + public String oneWayChargerouteCost; + public String returnChargerouteCost; + public String roundTripChargerouteCost; + public String oneWayHydrogenConsumption; + public String returnLaborHydrogenConsumption; + public String roundTripHydrogenConsumption; + public String oneWayHydrogenCost; + public String returnLaborHydrogenCost; + public String roundTripHydrogenCost; + public String hydrogenCost; + public String hydrogenStaServiceTime; + public String hydrogenStaRefuelingTime; + public String hydrogenStaQueueTime; + public String hydrogenStaServiceTimeCost; + public String hydrogenStaRefuelingTimeCost; + public String hydrogenStaQueueTimeCost; + } + + public static class DestinationSite { + public String innerSiteId; + public String name; + public String shortName; + public String siteNo; + public String city; + public String address; + public String contact; + public String phone; + public String type; + public String coOpMode; + public String booking; + public String siteStatus; + public String siteStatusName; + public String startBusiness; + public String endBusiness; + public String billingMethod; + public String term; + public String remark; + public String longitude; + public String latitude; + public String distance; + } + public NativeMapView(Context context, int id, Object args) { this.mContext = context; mActivity = getActivityFromContext(context); @@ -132,6 +253,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation container.addView(mapView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + initData(context); initServices(context); initOverlays(context); setupMapUi(); @@ -141,6 +263,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } + + private void initServices(Context context) { try { geocoderSearch = new GeocodeSearch(context); @@ -180,8 +304,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation endInput.setSingleLine(true); endInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH); endInput.addTextChangedListener(new TextWatcher() { - @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() > 1) { InputtipsQuery query = new InputtipsQuery(s.toString(), ""); query.setCityLimit(true); @@ -190,7 +318,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation inputtips.requestInputtipsAsyn(); } } - @Override public void afterTextChanged(Editable s) {} + + @Override + public void afterTextChanged(Editable s) { + } }); searchArea.addView(endInput); @@ -219,7 +350,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation locBtn.setBackground(getRoundedDrawable(Color.WHITE, 25)); locBtn.setElevation(dp2px(4)); locBtn.setOnClickListener(v -> { - if (currentLatLng != null) aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); + if (currentLatLng != null) + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); }); FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(44), dp2px(44)); locParams.setMargins(0, 0, dp2px(15), dp2px(250)); // 调高一点,避开底部的面板 @@ -256,7 +388,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation startNaviBtn.setTextColor(Color.WHITE); startNaviBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10)); startNaviBtn.setOnClickListener(v -> startRouteSearch()); - + LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48)); btnParams.topMargin = dp2px(15); panel.addView(startNaviBtn, btnParams); @@ -269,7 +401,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation Toast.makeText(mContext, "正在定位...", Toast.LENGTH_SHORT).show(); return; } - + if (endPoint == null) { Toast.makeText(mContext, "请先选择目的地", Toast.LENGTH_SHORT).show(); return; @@ -300,16 +432,16 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public void onDriveRouteSearched(DriveRouteResult result, int rCode) { if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) { DrivePath path = result.getPaths().get(0); - + // 规划成功,显示详情面板 detailPanel.setVisibility(View.VISIBLE); tvStationName.setText(endName); tvStationAddr.setText(endInput.getText().toString()); - + String info = String.format("预计时间:%d分钟 | 行驶里程:%.1f公里 | 预计路费:%.0f元", path.getDuration() / 60, path.getDistance() / 1000f, path.getTolls()); tvRouteInfo.setText(info); - + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f)); } else { // 规划失败回退面板 @@ -319,23 +451,119 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } private void startRouteSearch() { - if (mActivity == null || startPoint == null || endPoint == null) return; + if (mActivity == null || startPoint == null || endPoint == null) + return; Poi start = new Poi(startName, startPoint, ""); Poi end = new Poi(endName, endPoint, ""); AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); + //todo 根据接口的返回数据填充 try { AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); - AMapCarInfo carInfo = new AMapCarInfo(); - carInfo.setCarNumber("沪AGK2267"); - carInfo.setCarType("1"); - mAMapNavi.setCarInfo(carInfo); - } catch (Exception e) { e.printStackTrace(); } + //添加车辆信息示例代码 + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber("沪AGK2267");//设置车牌号 + carInfo.setCarType("1"); //设置车辆类型,0:小车; 1:货车. 默认0(小车). + carInfo.setVehicleAxis("6"); //设置货车的轴数,mCarType = 1时候生效,取值[0-255],默认为2 + carInfo.setVehicleHeight("3.56"); //设置货车的高度,单位:米,mCarType = 1时候生效,取值[0-25.5],默认1.6米 + carInfo.setVehicleLength("7.3"); //设置货车的最大长度,单位:米,mCarType = 1时候生效,取值[0-25],默认6米 + carInfo.setVehicleWidth("2.5"); //设置货车的最大宽度,单位:米,mCarType = 1时候生效,取值[0-25.5],默认2.5米 + carInfo.setVehicleSize("4"); //设置货车的大小,1-微型货车 2-轻型/小型货车 3-中型货车 4-重型货车,默认为2 + carInfo.setVehicleLoad("25.99"); //设置货车的总重,即车重+核定载重,单位:吨,mCarType = 1时候生效,取值[0-6553.5] + carInfo.setVehicleWeight("20"); //设置货车的核定载重,单位:吨,mCarType = 1时候生效,取值[0-6553.5] + carInfo.setRestriction(true); //设置是否躲避车辆限行,true代表躲避车辆限行,false代表不躲避车辆限行,默认为true + carInfo.setVehicleLoadSwitch(true); //设置货车重量是否参与算路,true-重量会参与算路;false-重量不会参与算路。默认为false + params.setCarInfo(carInfo); + mAMapNavi.setCarInfo(carInfo); + + //添加途经点算路示例代码 + // 起点信息 + NaviPoi startNaviPoi = new NaviPoi("龙城花园", null, "B000A8UF3J"); + // 终点信息 + NaviPoi endNaviPoi = new NaviPoi("北京大学", null, "B000A816R6"); + // 途经点信息 + List waysPoiIds = new ArrayList(); + waysPoiIds.add(new NaviPoi("途经点1", null, "B000A805M7")); + waysPoiIds.add(new NaviPoi("途经点2", null, "B0FFFAADBU")); + waysPoiIds.add(new NaviPoi("途经点3", null, "B0FFF5BER7")); + // POI算路 + mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, waysPoiIds, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + } catch (Exception e) { + e.printStackTrace(); + } + + //启动货车导航组件 AmapNaviPage.getInstance().showRouteActivity(mActivity, params, null); } + private void initData(Context context) { + //获取从Flutter端存储的车牌和token + android.content.SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE); + String plateNumber = prefs.getString("flutter.plateNumber", ""); + String token = prefs.getString("flutter.token", ""); + + Log.d(TAG, "initData - plateNumber: " + plateNumber + ", token: " + (token.isEmpty() ? "empty" : "present")); + + // 保存token供后续使用 + this.token = token; + this.plateNumber = plateNumber; + } + + /** + * 定位成功后调用,获取货车路线算法信息 + */ + private void fetchTruckRouteAlgorithm(AMapLocation loc) { + if (plateNumber == null || plateNumber.isEmpty()) { + return; + } + + try { + JSONObject json = new JSONObject(); + json.put("longitude", String.valueOf(loc.getLongitude())); + json.put("latitude", String.valueOf(loc.getLatitude())); + json.put("plateNumber", plateNumber); + json.put("hydrogenSiteId", ""); + + Request.Builder requestBuilder = new Request.Builder() + .url("https://beta-esg.api.lnh2e.com/appointment/truck/truckRouteAlgorithm") + .post(RequestBody.create(json.toString(), MediaType.parse("application/json"))); + + if (token != null && !token.isEmpty()) { + requestBuilder.addHeader("asoco-token", token); + } + + httpClient.newCall(requestBuilder.build()).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + Log.e(TAG, "fetchTruckRouteAlgorithm failed", e); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + try { + String responseString = response.body().string(); + Log.d(TAG, "fetchTruckRouteAlgorithm response: " + responseString); + + JSONObject res = new JSONObject(responseString); + if (res.getInt("code") == 200) { + JSONObject data = res.getJSONObject("data"); + truckRouteData = parseTruckRouteData(data); + Log.d(TAG, "TruckRouteAlgorithm data loaded"); + } + } catch (Exception e) { + Log.e(TAG, "parseTruckRouteAlgorithm error", e); + } + } + } + }); + } catch (Exception e) { + Log.e(TAG, "fetchTruckRouteAlgorithm error", e); + } + } + private void setupMapUi() { aMap.setLocationSource(this); aMap.setMyLocationEnabled(true); @@ -348,7 +576,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, dp2px(30), dp2px(30), true); myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap)); } - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } myLocationStyle.anchor(0.5f, 0.5f); myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); @@ -369,9 +599,19 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics()); } - @Override public void activate(OnLocationChangedListener listener) { mListener = listener; startLocation(); } - @Override public void deactivate() { mListener = null; if (mlocationClient != null) mlocationClient.stopLocation(); } - + @Override + public void activate(OnLocationChangedListener listener) { + mListener = listener; + startLocation(); + } + + @Override + public void deactivate() { + mListener = null; + if (mlocationClient != null) + mlocationClient.stopLocation(); + } + public void startLocation() { if (mlocationClient == null) { try { @@ -381,7 +621,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); mlocationClient.setLocationOption(option); mlocationClient.startLocation(); - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } } } @@ -389,7 +631,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public void onLocationChanged(AMapLocation loc) { if (loc != null && loc.getErrorCode() == 0) { currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude()); - if (mListener != null) mListener.onLocationChanged(loc); + if (mListener != null) + mListener.onLocationChanged(loc); if (isFirstLocation) { isFirstLocation = false; startPoint = currentLatLng; @@ -397,6 +640,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation getAddressByLatlng(currentLatLng); fetchRecommendStation(loc); fetchNearbyStations(loc); + // 获取货车路线算法信息 + fetchTruckRouteAlgorithm(loc); } } } @@ -422,8 +667,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("latitude", loc.getLatitude()); httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { - @Override public void onFailure(@NonNull Call call, @NonNull IOException e) {} - @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful() && response.body() != null) { try { JSONObject res = new JSONObject(response.body().string()); @@ -437,11 +686,15 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation markStation(endPoint, endName, true); }); } - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } } } }); - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } } private void fetchNearbyStations(AMapLocation loc) { @@ -451,8 +704,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("latitude", loc.getLatitude()); httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { - @Override public void onFailure(@NonNull Call call, @NonNull IOException e) {} - @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful() && response.body() != null) { try { JSONObject res = new JSONObject(response.body().string()); @@ -462,14 +719,162 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation try { JSONObject item = array.getJSONObject(i); markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), item.getString("name"), false); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } }); - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } } } }); - } catch (Exception e) { e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 解析接口返回的data数据 + */ + private TruckRouteData parseTruckRouteData(JSONObject data) throws Exception { + TruckRouteData truckRouteData = new TruckRouteData(); + + // 解析truckDto + if (data.has("truckDto") && !data.isNull("truckDto")) { + JSONObject truckJson = data.getJSONObject("truckDto"); + TruckDto truckDto = new TruckDto(); + truckDto.isRestriction = truckJson.optBoolean("isRestriction", true); + truckDto.mvehicleSizeName = truckJson.optString("mvehicleSizeName", ""); + truckDto.mvehicleAxisUnit = truckJson.optString("mvehicleAxisUnit", "轴"); + truckDto.mcarNumber = truckJson.optString("mcarNumber", ""); + truckDto.mcarType = truckJson.optInt("mcarType", 0); + truckDto.mvehicleHeight = truckJson.optString("mvehicleHeight", ""); + truckDto.mvehicleHeightUnit = truckJson.optString("mvehicleHeightUnit", "M"); + truckDto.mvehicleWeight = truckJson.optString("mvehicleWeight", ""); + truckDto.mvehicleWeightUnit = truckJson.optString("mvehicleWeightUnit", "T"); + truckDto.mvehicleLoad = truckJson.optString("mvehicleLoad", ""); + truckDto.mvehicleLoadUnit = truckJson.optString("mvehicleLoadUnit", "T"); + truckDto.mvehicleLoadSwitch = truckJson.optBoolean("mvehicleLoadSwitch", false); + truckDto.mvehicleWidth = truckJson.optString("mvehicleWidth", ""); + truckDto.mvehicleWidthUnit = truckJson.optString("mvehicleWidthUnit", "M"); + truckDto.mvehicleLength = truckJson.optString("mvehicleLength", ""); + truckDto.mvehicleLengthUnit = truckJson.optString("mvehicleLengthUnit", "M"); + truckDto.mvehicleSize = truckJson.optInt("mvehicleSize", 2); + truckDto.mvehicleAxis = truckJson.optInt("mvehicleAxis", 2); + truckRouteData.truckDto = truckDto; + } + + // 解析destinationSite + if (data.has("destinationSite") && !data.isNull("destinationSite")) { + JSONObject siteJson = data.getJSONObject("destinationSite"); + DestinationSite destinationSite = new DestinationSite(); + destinationSite.innerSiteId = siteJson.optString("innerSiteId", ""); + destinationSite.name = siteJson.optString("name", ""); + destinationSite.shortName = siteJson.optString("shortName", ""); + destinationSite.siteNo = siteJson.optString("siteNo", ""); + destinationSite.city = siteJson.optString("city", ""); + destinationSite.address = siteJson.optString("address", ""); + destinationSite.contact = siteJson.optString("contact", ""); + destinationSite.phone = siteJson.optString("phone", ""); + destinationSite.type = siteJson.optString("type", ""); + destinationSite.coOpMode = siteJson.optString("coOpMode", ""); + destinationSite.booking = siteJson.optString("booking", ""); + destinationSite.siteStatus = siteJson.optString("siteStatus", ""); + destinationSite.siteStatusName = siteJson.optString("siteStatusName", ""); + destinationSite.startBusiness = siteJson.optString("startBusiness", ""); + destinationSite.endBusiness = siteJson.optString("endBusiness", ""); + destinationSite.billingMethod = siteJson.optString("billingMethod", ""); + destinationSite.term = siteJson.optString("term", ""); + destinationSite.remark = siteJson.optString("remark", ""); + destinationSite.longitude = siteJson.optString("longitude", ""); + destinationSite.latitude = siteJson.optString("latitude", ""); + destinationSite.distance = siteJson.optString("distance", ""); + truckRouteData.destinationSite = destinationSite; + } + + // 解析pathDto + if (data.has("pathDto") && !data.isNull("pathDto")) { + JSONObject pathJson = data.getJSONObject("pathDto"); + PathDto pathDto = new PathDto(); + pathDto.distance = pathJson.optInt("distance", 0); + pathDto.duration = pathJson.optInt("duration", 0); + pathDto.strategy = pathJson.optString("strategy", ""); + pathDto.tolls = pathJson.optString("tolls", ""); + pathDto.toll_distance = pathJson.optInt("toll_distance", 0); + pathDto.restriction = pathJson.optInt("restriction", -1); + pathDto.traffic_lights = pathJson.optInt("traffic_lights", 0); + + // 解析naviList + if (pathJson.has("naviList") && !pathJson.isNull("naviList")) { + JSONArray naviArray = pathJson.getJSONArray("naviList"); + List naviList = new ArrayList<>(); + for (int i = 0; i < naviArray.length(); i++) { + JSONObject naviJson = naviArray.getJSONObject(i); + NaviPoint naviPoint = new NaviPoint(); + naviPoint.name = naviJson.optString("name", ""); + naviPoint.poiId = naviJson.optString("poiId", ""); + + if (naviJson.has("coordinate") && !naviJson.isNull("coordinate")) { + JSONObject coordJson = naviJson.getJSONObject("coordinate"); + Coordinate coordinate = new Coordinate(); + coordinate.longitude = coordJson.optString("longitude", ""); + coordinate.latitude = coordJson.optString("latitude", ""); + naviPoint.coordinate = coordinate; + } + + naviList.add(naviPoint); + } + pathDto.naviList = naviList; + } + + truckRouteData.pathDto = pathDto; + } + + // 解析algorithmPath + if (data.has("algorithmPath") && !data.isNull("algorithmPath")) { + JSONObject algorithmJson = data.getJSONObject("algorithmPath"); + AlgorithmPath algorithmPath = new AlgorithmPath(); + algorithmPath.tripRecommendationId = algorithmJson.optString("tripRecommendationId", ""); + algorithmPath.staId = algorithmJson.optString("staId", ""); + algorithmPath.tripOneWayPathId = algorithmJson.optString("tripOneWayPathId", ""); + algorithmPath.tripReturnPathId = algorithmJson.optString("tripReturnPathId", ""); + algorithmPath.oneWayDis = algorithmJson.optString("oneWayDis", ""); + algorithmPath.returnDis = algorithmJson.optString("returnDis", ""); + algorithmPath.roundTripDis = algorithmJson.optString("roundTripDis", ""); + algorithmPath.oneWayTime = algorithmJson.optString("oneWayTime", ""); + algorithmPath.returnTime = algorithmJson.optString("returnTime", ""); + algorithmPath.roundTripTime = algorithmJson.optString("roundTripTime", ""); + algorithmPath.oneWayCost = algorithmJson.optString("oneWayCost", ""); + algorithmPath.returnCost = algorithmJson.optString("returnCost", ""); + algorithmPath.roundTripCost = algorithmJson.optString("roundTripCost", ""); + algorithmPath.oneWayLaborCost = algorithmJson.optString("oneWayLaborCost", ""); + algorithmPath.returnLaborCost = algorithmJson.optString("returnLaborCost", ""); + algorithmPath.roundTripLaborCost = algorithmJson.optString("roundTripLaborCost", ""); + algorithmPath.oneWayChargerouteCost = algorithmJson.optString("oneWayChargerouteCost", ""); + algorithmPath.returnChargerouteCost = algorithmJson.optString("returnChargerouteCost", ""); + algorithmPath.roundTripChargerouteCost = algorithmJson.optString("roundTripChargerouteCost", ""); + algorithmPath.oneWayHydrogenConsumption = algorithmJson.optString("oneWayHydrogenConsumption", ""); + algorithmPath.returnLaborHydrogenConsumption = algorithmJson.optString("returnLaborHydrogenConsumption", ""); + algorithmPath.roundTripHydrogenConsumption = algorithmJson.optString("roundTripHydrogenConsumption", ""); + algorithmPath.oneWayHydrogenCost = algorithmJson.optString("oneWayHydrogenCost", ""); + algorithmPath.returnLaborHydrogenCost = algorithmJson.optString("returnLaborHydrogenCost", ""); + algorithmPath.roundTripHydrogenCost = algorithmJson.optString("roundTripHydrogenCost", ""); + algorithmPath.hydrogenCost = algorithmJson.optString("hydrogenCost", ""); + algorithmPath.hydrogenStaServiceTime = algorithmJson.optString("hydrogenStaServiceTime", ""); + algorithmPath.hydrogenStaRefuelingTime = algorithmJson.optString("hydrogenStaRefuelingTime", ""); + algorithmPath.hydrogenStaQueueTime = algorithmJson.optString("hydrogenStaQueueTime", ""); + algorithmPath.hydrogenStaServiceTimeCost = algorithmJson.optString("hydrogenStaServiceTimeCost", ""); + algorithmPath.hydrogenStaRefuelingTimeCost = algorithmJson.optString("hydrogenStaRefuelingTimeCost", ""); + algorithmPath.hydrogenStaQueueTimeCost = algorithmJson.optString("hydrogenStaQueueTimeCost", ""); + truckRouteData.algorithmPath = algorithmPath; + } + + // 其他字段 + truckRouteData.truckDtoStr = data.optString("truckDtoStr", null); + truckRouteData.isInvokeAlgorithm = data.optBoolean("isInvokeAlgorithm", false); + + return truckRouteData; } private void markStation(LatLng latLng, String name, boolean isRecommend) { @@ -489,23 +894,53 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return true; } - @Override public void onGeocodeSearched(GeocodeResult r, int c) {} - @Override public void onBusRouteSearched(BusRouteResult r, int c) {} - @Override public void onWalkRouteSearched(WalkRouteResult r, int c) {} - @Override public void onRideRouteSearched(RideRouteResult r, int c) {} + @Override + public void onGeocodeSearched(GeocodeResult r, int c) { + } + + @Override + public void onBusRouteSearched(BusRouteResult r, int c) { + } + + @Override + public void onWalkRouteSearched(WalkRouteResult r, int c) { + } + + @Override + public void onRideRouteSearched(RideRouteResult r, int c) { + } private Activity getActivityFromContext(Context context) { - if (context instanceof Activity) return (Activity) context; - if (context instanceof android.content.ContextWrapper) return getActivityFromContext(((android.content.ContextWrapper) context).getBaseContext()); + if (context instanceof Activity) + return (Activity) context; + if (context instanceof android.content.ContextWrapper) + return getActivityFromContext(((android.content.ContextWrapper) context).getBaseContext()); return null; } - public void onResume() { mapView.onResume(); } - public void onPause() { mapView.onPause(); } - public void onSaveInstanceState(Bundle out) { mapView.onSaveInstanceState(out); } - @Override public View getView() { return container; } - @Override public void dispose() { - if (mlocationClient != null) { mlocationClient.stopLocation(); mlocationClient.onDestroy(); } + public void onResume() { + mapView.onResume(); + } + + public void onPause() { + mapView.onPause(); + } + + public void onSaveInstanceState(Bundle out) { + mapView.onSaveInstanceState(out); + } + + @Override + public View getView() { + return container; + } + + @Override + public void dispose() { + if (mlocationClient != null) { + mlocationClient.stopLocation(); + mlocationClient.onDestroy(); + } mapView.onDestroy(); } } diff --git a/ln_jq_app/lib/storage_service.dart b/ln_jq_app/lib/storage_service.dart index 9d5f595..c71b70b 100644 --- a/ln_jq_app/lib/storage_service.dart +++ b/ln_jq_app/lib/storage_service.dart @@ -100,13 +100,16 @@ class StorageService extends GetxService { await _box.write(_nameKey, name); await _box.write(_phoneKey, phone); await _box.write(_idCardKey, idCard); + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('token', token); } Future saveVehicleInfo(VehicleInfo data) async { await _box.write(_vehicleInfoKey, vehicleInfoToJson(data)); final SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.setString('plateNumber', data.plateNumber ?? ""); + await prefs.setString('plateNumber', data.plateNumber); } Future saveStationCredentials(String account, String password) async { @@ -124,6 +127,7 @@ class StorageService extends GetxService { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove('plateNumber'); + await prefs.remove('token'); } Future clearStationCredentials() async { From 67c36f436cb9d9f3e1df0068f84f2b5006bf6917 Mon Sep 17 00:00:00 2001 From: userGyl Date: Wed, 25 Mar 2026 17:18:06 +0800 Subject: [PATCH 11/19] bugfix --- .../com/lnkj/ln_jq_app/NativeMapView.java | 205 ++++++++++++++---- 1 file changed, 159 insertions(+), 46 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index eebc2d9..3c2053f 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -11,6 +11,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.TypedValue; @@ -72,7 +73,9 @@ import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import androidx.annotation.NonNull; import io.flutter.plugin.platform.PlatformView; @@ -121,6 +124,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private String token; private String plateNumber; + private String mDebugUrl = "https://beta-esg.api.lnh2e.com/appointment/"; + private String mReleaseUrl = ""; + // 存储货车路线算法接口返回的数据 private TruckRouteData truckRouteData; @@ -264,7 +270,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } - private void initServices(Context context) { try { geocoderSearch = new GeocodeSearch(context); @@ -451,50 +456,104 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } private void startRouteSearch() { - if (mActivity == null || startPoint == null || endPoint == null) + if (mActivity == null || startPoint == null) { + Toast.makeText(mContext, "定位信息不足,请稍后再试", Toast.LENGTH_SHORT).show(); return; + } + //确定目的地坐标和名称 + // 优先级:truckRouteData (接口返回的精准点) > endPoint (地图点击/搜索的点) + LatLng finalDestinationLatLng = null; + String finalDestinationName = endName; + + if (truckRouteData != null && truckRouteData.destinationSite != null) { + String latStr = truckRouteData.destinationSite.latitude; + String lngStr = truckRouteData.destinationSite.longitude; + + //防止 parseDouble 崩溃 + if (latStr != null && !latStr.isEmpty() && lngStr != null && !lngStr.isEmpty()) { + try { + finalDestinationLatLng = new LatLng( + Double.parseDouble(latStr), + Double.parseDouble(lngStr) + ); + if (truckRouteData.destinationSite.name != null && !truckRouteData.destinationSite.name.isEmpty()) { + finalDestinationName = truckRouteData.destinationSite.name; + } + } catch (NumberFormatException e) { + Log.e(TAG, "解析 truckRouteData 坐标失败: " + e.getMessage()); + } + } + } + + // 如果接口数据不可用,使用之前标记点/输入点作为兜底 + if (finalDestinationLatLng == null) { + finalDestinationLatLng = endPoint; + } + + // 最终校验 + if (finalDestinationLatLng == null) { + Toast.makeText(mContext, "请先选择有效的目的地", Toast.LENGTH_SHORT).show(); + return; + } + + //构造起点和终点 POI Poi start = new Poi(startName, startPoint, ""); - Poi end = new Poi(endName, endPoint, ""); + Poi end = new Poi(finalDestinationName, finalDestinationLatLng, ""); + + //配置导航参数 AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); - //todo 根据接口的返回数据填充 try { AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); - //添加车辆信息示例代码 - AMapCarInfo carInfo = new AMapCarInfo(); - carInfo.setCarNumber("沪AGK2267");//设置车牌号 - carInfo.setCarType("1"); //设置车辆类型,0:小车; 1:货车. 默认0(小车). - carInfo.setVehicleAxis("6"); //设置货车的轴数,mCarType = 1时候生效,取值[0-255],默认为2 - carInfo.setVehicleHeight("3.56"); //设置货车的高度,单位:米,mCarType = 1时候生效,取值[0-25.5],默认1.6米 - carInfo.setVehicleLength("7.3"); //设置货车的最大长度,单位:米,mCarType = 1时候生效,取值[0-25],默认6米 - carInfo.setVehicleWidth("2.5"); //设置货车的最大宽度,单位:米,mCarType = 1时候生效,取值[0-25.5],默认2.5米 - carInfo.setVehicleSize("4"); //设置货车的大小,1-微型货车 2-轻型/小型货车 3-中型货车 4-重型货车,默认为2 - carInfo.setVehicleLoad("25.99"); //设置货车的总重,即车重+核定载重,单位:吨,mCarType = 1时候生效,取值[0-6553.5] - carInfo.setVehicleWeight("20"); //设置货车的核定载重,单位:吨,mCarType = 1时候生效,取值[0-6553.5] - carInfo.setRestriction(true); //设置是否躲避车辆限行,true代表躲避车辆限行,false代表不躲避车辆限行,默认为true - carInfo.setVehicleLoadSwitch(true); //设置货车重量是否参与算路,true-重量会参与算路;false-重量不会参与算路。默认为false - params.setCarInfo(carInfo); - mAMapNavi.setCarInfo(carInfo); + // 设置车辆信息 (只有在数据完整时设置) + if (truckRouteData != null && truckRouteData.truckDto != null) { + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber(plateNumber); // 使用初始化时获取的车牌 + carInfo.setCarType(String.valueOf(truckRouteData.truckDto.mcarType)); + carInfo.setVehicleAxis(String.valueOf(truckRouteData.truckDto.mvehicleAxis)); + carInfo.setVehicleHeight(truckRouteData.truckDto.mvehicleHeight); + carInfo.setVehicleLength(truckRouteData.truckDto.mvehicleLength); + carInfo.setVehicleWidth(truckRouteData.truckDto.mvehicleWidth); + carInfo.setVehicleSize(String.valueOf(truckRouteData.truckDto.mvehicleSize)); + carInfo.setVehicleLoad(truckRouteData.truckDto.mvehicleLoad); + carInfo.setVehicleWeight(truckRouteData.truckDto.mvehicleWeight); + carInfo.setRestriction(truckRouteData.truckDto.isRestriction); + carInfo.setVehicleLoadSwitch(truckRouteData.truckDto.mvehicleLoadSwitch); - //添加途经点算路示例代码 - // 起点信息 - NaviPoi startNaviPoi = new NaviPoi("龙城花园", null, "B000A8UF3J"); - // 终点信息 - NaviPoi endNaviPoi = new NaviPoi("北京大学", null, "B000A816R6"); - // 途经点信息 - List waysPoiIds = new ArrayList(); - waysPoiIds.add(new NaviPoi("途经点1", null, "B000A805M7")); - waysPoiIds.add(new NaviPoi("途经点2", null, "B0FFFAADBU")); - waysPoiIds.add(new NaviPoi("途经点3", null, "B0FFF5BER7")); - // POI算路 - mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, waysPoiIds, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + params.setCarInfo(carInfo); + mAMapNavi.setCarInfo(carInfo); + } + + //处理途径点 (如果接口返回了 naviList) + if (truckRouteData != null && truckRouteData.pathDto != null && truckRouteData.pathDto.naviList != null) { + NaviPoi startNaviPoi = new NaviPoi(startName, startPoint, ""); + NaviPoi endNaviPoi = new NaviPoi(finalDestinationName, finalDestinationLatLng, ""); + + List waysPoiIds = new ArrayList<>(); + for (NaviPoint np : truckRouteData.pathDto.naviList) { + if (np.coordinate != null && !TextUtils.isEmpty(np.coordinate.latitude) && !TextUtils.isEmpty(np.coordinate.longitude)) { + try { + double lat = Double.parseDouble(np.coordinate.latitude); + double lng = Double.parseDouble(np.coordinate.longitude); + waysPoiIds.add(new NaviPoi(np.name, new LatLng(lat, lng), np.poiId)); + } catch (Exception e) { + Log.e(TAG, "途径点坐标解析错误: " + np.name); + } + } + } + + // 如果有途径点,主动触发算路逻辑 + if (!waysPoiIds.isEmpty()) { + mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, waysPoiIds, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + } + } } catch (Exception e) { - e.printStackTrace(); + Log.e(TAG, "配置导航参数出错: " + e.getMessage()); } - //启动货车导航组件 + //启动高德 AmapNaviPage.getInstance().showRouteActivity(mActivity, params, null); } @@ -511,8 +570,12 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation this.plateNumber = plateNumber; } + // 当前选中的站点ID,默认id和选择地图id + private String selectedSiteId = ""; + /** - * 定位成功后调用,获取货车路线算法信息 + * 定位成功后调用,地图选点后调用 + * 获取货车路线算法信息 */ private void fetchTruckRouteAlgorithm(AMapLocation loc) { if (plateNumber == null || plateNumber.isEmpty()) { @@ -524,16 +587,16 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("longitude", String.valueOf(loc.getLongitude())); json.put("latitude", String.valueOf(loc.getLatitude())); json.put("plateNumber", plateNumber); - json.put("hydrogenSiteId", ""); + json.put("hydrogenSiteId", selectedSiteId); Request.Builder requestBuilder = new Request.Builder() - .url("https://beta-esg.api.lnh2e.com/appointment/truck/truckRouteAlgorithm") + .url(mDebugUrl + "truck/truckRouteAlgorithm") .post(RequestBody.create(json.toString(), MediaType.parse("application/json"))); if (token != null && !token.isEmpty()) { requestBuilder.addHeader("asoco-token", token); } - + Log.d("566-", "asoco-token:" + token + "requestBuilder:" + json); httpClient.newCall(requestBuilder.build()).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { @@ -658,6 +721,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } + /** + * 获取定位地区的推荐站点 + * + * @param loc + */ private void fetchRecommendStation(AMapLocation loc) { try { JSONObject json = new JSONObject(); @@ -666,7 +734,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("longitude", loc.getLongitude()); json.put("latitude", loc.getLatitude()); - httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { + httpClient.newCall(new Request.Builder().url(mDebugUrl + "station/getStationInfoByArea").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { } @@ -680,10 +748,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation JSONObject data = res.getJSONObject("data"); endPoint = new LatLng(data.getDouble("latitude"), data.getDouble("longitude")); endName = data.getString("name"); + selectedSiteId = data.optString("id", ""); String addr = data.optString("address", ""); new Handler(Looper.getMainLooper()).post(() -> { endInput.setText(addr); - markStation(endPoint, endName, true); + markStation(endPoint, endName, selectedSiteId, true); }); } } catch (Exception e) { @@ -703,7 +772,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("longitude", loc.getLongitude()); json.put("latitude", loc.getLatitude()); - httpClient.newCall(new Request.Builder().url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { + httpClient.newCall(new Request.Builder().url(mDebugUrl + "station/getNearbyHydrogenStationsByLocation").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))).build()).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { } @@ -718,7 +787,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation for (int i = 0; i < array.length(); i++) { try { JSONObject item = array.getJSONObject(i); - markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), item.getString("name"), false); + String id = item.getString("id"); + markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), + item.getString("name"), id, false); } catch (Exception ignored) { } } @@ -877,20 +948,62 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return truckRouteData; } - private void markStation(LatLng latLng, String name, boolean isRecommend) { - Marker m = aMap.addMarker(new MarkerOptions().position(latLng).title(name).icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN))); - m.setObject(latLng); + private void markStation(LatLng latLng, String name, String stationId, + boolean isRecommend) { + MarkerOptions markerOptions = new MarkerOptions() + .position(latLng).title(name) + .icon(BitmapDescriptorFactory.defaultMarker( + isRecommend ? BitmapDescriptorFactory.HUE_RED + : BitmapDescriptorFactory.HUE_GREEN)); + Marker m = aMap.addMarker(markerOptions); + + Map dataMap = new HashMap<>(); + dataMap.put("latLng", latLng); + dataMap.put("stationId", stationId); + m.setObject(dataMap); + stationMarkers.add(m); } @Override public boolean onMarkerClick(Marker marker) { - if (marker.getObject() instanceof LatLng) { - endPoint = (LatLng) marker.getObject(); + Object obj = marker.getObject(); + + if (obj instanceof Map) { + Map dataMap = (Map) obj; + + // 获取坐标并赋值 + LatLng latLng = (LatLng) dataMap.get("latLng"); + if (latLng != null) { + this.endPoint = latLng; + } + + // 获取站点ID并赋值 + String stationId = (String) dataMap.get("stationId"); + if (stationId != null) { + this.selectedSiteId = stationId; + } + + // 更新 UI 和 业务逻辑 endName = marker.getTitle(); endInput.setText(endName); + + // 需要传入当前位置以便接口计算路线 + if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) { + fetchTruckRouteAlgorithm(mlocationClient.getLastKnownLocation()); + } else if (currentLatLng != null) { + // 如果没有精准定位,尝试使用上次记录的经纬度 + AMapLocation tempLoc = new AMapLocation(""); + tempLoc.setLatitude(currentLatLng.latitude); + tempLoc.setLongitude(currentLatLng.longitude); + fetchTruckRouteAlgorithm(tempLoc); + } + + + // 计算路径 calculateRouteBeforeNavi(); } + return true; } From bf80931f375790962cd0ab9d504e472cb94aad60 Mon Sep 17 00:00:00 2001 From: userGyl Date: Wed, 25 Mar 2026 17:56:37 +0800 Subject: [PATCH 12/19] bugfix --- .../com/lnkj/ln_jq_app/NativeMapView.java | 428 +++++++++--------- 1 file changed, 216 insertions(+), 212 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 3c2053f..c7df795 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -88,7 +88,7 @@ import okhttp3.RequestBody; import okhttp3.Response; /** - * 高德地图导航 Native View - 底部精简交互优化版 + * 高德地图导航 */ public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener { @@ -115,6 +115,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private LatLng currentLatLng; private String startName = "我的位置"; private String endName = ""; + private String endAddress = ""; private LatLng startPoint; private LatLng endPoint; private boolean isFirstLocation = true; @@ -130,117 +131,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation // 存储货车路线算法接口返回的数据 private TruckRouteData truckRouteData; - // 货车路线算法数据Bean - public static class TruckRouteData { - public TruckDto truckDto; - public String truckDtoStr; - public DestinationSite destinationSite; - public PathDto pathDto; - public AlgorithmPath algorithmPath; - public boolean isInvokeAlgorithm; - } - - public static class TruckDto { - public boolean isRestriction; - public String mvehicleSizeName; - public String mvehicleAxisUnit; - public String mcarNumber; - public int mcarType; - public String mvehicleHeight; - public String mvehicleHeightUnit; - public String mvehicleWeight; - public String mvehicleWeightUnit; - public String mvehicleLoad; - public String mvehicleLoadUnit; - public boolean mvehicleLoadSwitch; - public String mvehicleWidth; - public String mvehicleWidthUnit; - public String mvehicleLength; - public String mvehicleLengthUnit; - public int mvehicleSize; - public int mvehicleAxis; - } - - public static class PathDto { - public int distance; - public int duration; - public String strategy; - public String tolls; - public int toll_distance; - public int restriction; - public int traffic_lights; - public List naviList; - } - - public static class NaviPoint { - public String name; - public String poiId; - public Coordinate coordinate; - } - - public static class Coordinate { - public String longitude; - public String latitude; - } - - public static class AlgorithmPath { - public String tripRecommendationId; - public String staId; - public String tripOneWayPathId; - public String tripReturnPathId; - public String oneWayDis; - public String returnDis; - public String roundTripDis; - public String oneWayTime; - public String returnTime; - public String roundTripTime; - public String oneWayCost; - public String returnCost; - public String roundTripCost; - public String oneWayLaborCost; - public String returnLaborCost; - public String roundTripLaborCost; - public String oneWayChargerouteCost; - public String returnChargerouteCost; - public String roundTripChargerouteCost; - public String oneWayHydrogenConsumption; - public String returnLaborHydrogenConsumption; - public String roundTripHydrogenConsumption; - public String oneWayHydrogenCost; - public String returnLaborHydrogenCost; - public String roundTripHydrogenCost; - public String hydrogenCost; - public String hydrogenStaServiceTime; - public String hydrogenStaRefuelingTime; - public String hydrogenStaQueueTime; - public String hydrogenStaServiceTimeCost; - public String hydrogenStaRefuelingTimeCost; - public String hydrogenStaQueueTimeCost; - } - - public static class DestinationSite { - public String innerSiteId; - public String name; - public String shortName; - public String siteNo; - public String city; - public String address; - public String contact; - public String phone; - public String type; - public String coOpMode; - public String booking; - public String siteStatus; - public String siteStatusName; - public String startBusiness; - public String endBusiness; - public String billingMethod; - public String term; - public String remark; - public String longitude; - public String latitude; - public String distance; - } public NativeMapView(Context context, int id, Object args) { this.mContext = context; @@ -441,7 +331,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation // 规划成功,显示详情面板 detailPanel.setVisibility(View.VISIBLE); tvStationName.setText(endName); - tvStationAddr.setText(endInput.getText().toString()); + tvStationAddr.setText(endAddress); String info = String.format("预计时间:%d分钟 | 行驶里程:%.1f公里 | 预计路费:%.0f元", path.getDuration() / 60, path.getDistance() / 1000f, path.getTolls()); @@ -749,10 +639,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation endPoint = new LatLng(data.getDouble("latitude"), data.getDouble("longitude")); endName = data.getString("name"); selectedSiteId = data.optString("id", ""); - String addr = data.optString("address", ""); + endAddress = data.optString("address", ""); new Handler(Looper.getMainLooper()).post(() -> { - endInput.setText(addr); - markStation(endPoint, endName, selectedSiteId, true); + markStation(endPoint, endName, endAddress, selectedSiteId, true); }); } } catch (Exception e) { @@ -789,7 +678,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation JSONObject item = array.getJSONObject(i); String id = item.getString("id"); markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), - item.getString("name"), id, false); + item.getString("name"), item.getString("address"), id, false); } catch (Exception ignored) { } } @@ -805,6 +694,118 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } + + private void markStation(LatLng latLng, String name, String address, String stationId, + boolean isRecommend) { + MarkerOptions markerOptions = new MarkerOptions() + .position(latLng).title(name) + .icon(BitmapDescriptorFactory.defaultMarker( + isRecommend ? BitmapDescriptorFactory.HUE_RED + : BitmapDescriptorFactory.HUE_GREEN)); + Marker m = aMap.addMarker(markerOptions); + + Map dataMap = new HashMap<>(); + dataMap.put("latLng", latLng); + dataMap.put("stationId", stationId); + dataMap.put("address", address); + m.setObject(dataMap); + + stationMarkers.add(m); + } + + @Override + public boolean onMarkerClick(Marker marker) { + Object obj = marker.getObject(); + + if (obj instanceof Map) { + Map dataMap = (Map) obj; + + // 获取坐标并赋值 + LatLng latLng = (LatLng) dataMap.get("latLng"); + if (latLng != null) { + this.endPoint = latLng; + } + + // 获取站点ID并赋值 + String stationId = (String) dataMap.get("stationId"); + String address = (String) dataMap.get("address"); + if (stationId != null) { + this.selectedSiteId = stationId; + this.endAddress = address; + } + + // 更新 UI 和 业务逻辑 + endName = marker.getTitle(); + + // 需要传入当前位置以便接口计算路线 + if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) { + fetchTruckRouteAlgorithm(mlocationClient.getLastKnownLocation()); + } else if (currentLatLng != null) { + // 如果没有精准定位,尝试使用上次记录的经纬度 + AMapLocation tempLoc = new AMapLocation(""); + tempLoc.setLatitude(currentLatLng.latitude); + tempLoc.setLongitude(currentLatLng.longitude); + fetchTruckRouteAlgorithm(tempLoc); + } + + + // 计算路径 + calculateRouteBeforeNavi(); + } + + return true; + } + + @Override + public void onGeocodeSearched(GeocodeResult r, int c) { + } + + @Override + public void onBusRouteSearched(BusRouteResult r, int c) { + } + + @Override + public void onWalkRouteSearched(WalkRouteResult r, int c) { + } + + @Override + public void onRideRouteSearched(RideRouteResult r, int c) { + } + + private Activity getActivityFromContext(Context context) { + if (context instanceof Activity) + return (Activity) context; + if (context instanceof android.content.ContextWrapper) + return getActivityFromContext(((android.content.ContextWrapper) context).getBaseContext()); + return null; + } + + public void onResume() { + mapView.onResume(); + } + + public void onPause() { + mapView.onPause(); + } + + public void onSaveInstanceState(Bundle out) { + mapView.onSaveInstanceState(out); + } + + @Override + public View getView() { + return container; + } + + @Override + public void dispose() { + if (mlocationClient != null) { + mlocationClient.stopLocation(); + mlocationClient.onDestroy(); + } + mapView.onDestroy(); + } + /** * 解析接口返回的data数据 */ @@ -948,112 +949,115 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return truckRouteData; } - private void markStation(LatLng latLng, String name, String stationId, - boolean isRecommend) { - MarkerOptions markerOptions = new MarkerOptions() - .position(latLng).title(name) - .icon(BitmapDescriptorFactory.defaultMarker( - isRecommend ? BitmapDescriptorFactory.HUE_RED - : BitmapDescriptorFactory.HUE_GREEN)); - Marker m = aMap.addMarker(markerOptions); - - Map dataMap = new HashMap<>(); - dataMap.put("latLng", latLng); - dataMap.put("stationId", stationId); - m.setObject(dataMap); - - stationMarkers.add(m); + // 货车路线算法数据Bean + public static class TruckRouteData { + public TruckDto truckDto; + public String truckDtoStr; + public DestinationSite destinationSite; + public PathDto pathDto; + public AlgorithmPath algorithmPath; + public boolean isInvokeAlgorithm; } - @Override - public boolean onMarkerClick(Marker marker) { - Object obj = marker.getObject(); - - if (obj instanceof Map) { - Map dataMap = (Map) obj; - - // 获取坐标并赋值 - LatLng latLng = (LatLng) dataMap.get("latLng"); - if (latLng != null) { - this.endPoint = latLng; - } - - // 获取站点ID并赋值 - String stationId = (String) dataMap.get("stationId"); - if (stationId != null) { - this.selectedSiteId = stationId; - } - - // 更新 UI 和 业务逻辑 - endName = marker.getTitle(); - endInput.setText(endName); - - // 需要传入当前位置以便接口计算路线 - if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) { - fetchTruckRouteAlgorithm(mlocationClient.getLastKnownLocation()); - } else if (currentLatLng != null) { - // 如果没有精准定位,尝试使用上次记录的经纬度 - AMapLocation tempLoc = new AMapLocation(""); - tempLoc.setLatitude(currentLatLng.latitude); - tempLoc.setLongitude(currentLatLng.longitude); - fetchTruckRouteAlgorithm(tempLoc); - } - - - // 计算路径 - calculateRouteBeforeNavi(); - } - - return true; + public static class TruckDto { + public boolean isRestriction; + public String mvehicleSizeName; + public String mvehicleAxisUnit; + public String mcarNumber; + public int mcarType; + public String mvehicleHeight; + public String mvehicleHeightUnit; + public String mvehicleWeight; + public String mvehicleWeightUnit; + public String mvehicleLoad; + public String mvehicleLoadUnit; + public boolean mvehicleLoadSwitch; + public String mvehicleWidth; + public String mvehicleWidthUnit; + public String mvehicleLength; + public String mvehicleLengthUnit; + public int mvehicleSize; + public int mvehicleAxis; } - @Override - public void onGeocodeSearched(GeocodeResult r, int c) { + public static class PathDto { + public int distance; + public int duration; + public String strategy; + public String tolls; + public int toll_distance; + public int restriction; + public int traffic_lights; + public List naviList; } - @Override - public void onBusRouteSearched(BusRouteResult r, int c) { + public static class NaviPoint { + public String name; + public String poiId; + public Coordinate coordinate; } - @Override - public void onWalkRouteSearched(WalkRouteResult r, int c) { + public static class Coordinate { + public String longitude; + public String latitude; } - @Override - public void onRideRouteSearched(RideRouteResult r, int c) { + public static class AlgorithmPath { + public String tripRecommendationId; + public String staId; + public String tripOneWayPathId; + public String tripReturnPathId; + public String oneWayDis; + public String returnDis; + public String roundTripDis; + public String oneWayTime; + public String returnTime; + public String roundTripTime; + public String oneWayCost; + public String returnCost; + public String roundTripCost; + public String oneWayLaborCost; + public String returnLaborCost; + public String roundTripLaborCost; + public String oneWayChargerouteCost; + public String returnChargerouteCost; + public String roundTripChargerouteCost; + public String oneWayHydrogenConsumption; + public String returnLaborHydrogenConsumption; + public String roundTripHydrogenConsumption; + public String oneWayHydrogenCost; + public String returnLaborHydrogenCost; + public String roundTripHydrogenCost; + public String hydrogenCost; + public String hydrogenStaServiceTime; + public String hydrogenStaRefuelingTime; + public String hydrogenStaQueueTime; + public String hydrogenStaServiceTimeCost; + public String hydrogenStaRefuelingTimeCost; + public String hydrogenStaQueueTimeCost; } - private Activity getActivityFromContext(Context context) { - if (context instanceof Activity) - return (Activity) context; - if (context instanceof android.content.ContextWrapper) - return getActivityFromContext(((android.content.ContextWrapper) context).getBaseContext()); - return null; - } - - public void onResume() { - mapView.onResume(); - } - - public void onPause() { - mapView.onPause(); - } - - public void onSaveInstanceState(Bundle out) { - mapView.onSaveInstanceState(out); - } - - @Override - public View getView() { - return container; - } - - @Override - public void dispose() { - if (mlocationClient != null) { - mlocationClient.stopLocation(); - mlocationClient.onDestroy(); - } - mapView.onDestroy(); + public static class DestinationSite { + public String innerSiteId; + public String name; + public String shortName; + public String siteNo; + public String city; + public String address; + public String contact; + public String phone; + public String type; + public String coOpMode; + public String booking; + public String siteStatus; + public String siteStatusName; + public String startBusiness; + public String endBusiness; + public String billingMethod; + public String term; + public String remark; + public String longitude; + public String latitude; + public String distance; } } From b275c663837f533a58b5f537280cffca213f67b6 Mon Sep 17 00:00:00 2001 From: userGyl Date: Thu, 26 Mar 2026 16:58:57 +0800 Subject: [PATCH 13/19] ui --- .../com/lnkj/ln_jq_app/NativeMapView.java | 257 ++++++++++++++++-- .../app/src/main/res/drawable/ic_close.png | Bin 0 -> 880 bytes .../app/src/main/res/drawable/ic_fuel.png | Bin 0 -> 1150 bytes .../app/src/main/res/drawable/ic_location.png | Bin 0 -> 3173 bytes .../app/src/main/res/drawable/ic_mileage.png | Bin 0 -> 1102 bytes .../app/src/main/res/drawable/ic_time.png | Bin 0 -> 810 bytes .../app/src/main/res/drawable/ic_toll.png | Bin 0 -> 924 bytes 7 files changed, 240 insertions(+), 17 deletions(-) create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_close.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_fuel.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_location.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_mileage.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_time.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_toll.png diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index c7df795..d3dfc36 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -7,6 +7,7 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -23,6 +24,7 @@ import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -110,7 +112,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private EditText endInput; private LinearLayout searchArea; // 规划路线面板 private LinearLayout detailPanel; // 详情面板 - private TextView tvStationName, tvStationAddr, tvRouteInfo; + + private View modeMenu; //模式选择 + private TextView tvStationName, tvStationAddr, planToggleBtn; + //时间 费用 里程 路费 + private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel; private LatLng currentLatLng; private String startName = "我的位置"; @@ -239,17 +245,57 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation bottomParams.setMargins(dp2px(12), 0, dp2px(12), dp2px(65)); container.addView(bottomContainer, bottomParams); + + // --- 模式选择菜单 --- + modeMenu = createModeMenu(context); + modeMenu.setVisibility(View.GONE); + // 布局参数:位于规划按钮上方 + FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(dp2px(130), ViewGroup.LayoutParams.WRAP_CONTENT); + menuParams.gravity = Gravity.BOTTOM | Gravity.END; + menuParams.setMargins(0, 0, dp2px(15), dp2px(330)); // 高度根据按钮位置调整 + container.addView(modeMenu, menuParams); + + // 加氢规划圆形按钮 + planToggleBtn = new TextView(context); + planToggleBtn.setText("加氢\n规划"); + planToggleBtn.setTextSize(11); + planToggleBtn.setTextColor(Color.WHITE); + planToggleBtn.setGravity(Gravity.CENTER); + planToggleBtn.setTypeface(Typeface.DEFAULT_BOLD); + // 设置深绿色圆形背景 + planToggleBtn.setBackground(getCircleDrawable(Color.parseColor("#017143"))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + planToggleBtn.setElevation(dp2px(6)); + } + planToggleBtn.setOnClickListener(v -> { + // 切换菜单显示/隐藏 + modeMenu.setVisibility(modeMenu.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); + }); + + int layoutSize = dp2px(44); + FrameLayout.LayoutParams toggleParams = new FrameLayout.LayoutParams(layoutSize, layoutSize); + toggleParams.gravity = Gravity.BOTTOM | Gravity.END; + toggleParams.setMargins(0, 0, dp2px(12), dp2px(340)); // 位于定位按钮上方 + container.addView(planToggleBtn, toggleParams); + // --- 右下角定位按钮 --- ImageButton locBtn = new ImageButton(context); - locBtn.setImageResource(android.R.drawable.ic_menu_mylocation); - locBtn.setBackground(getRoundedDrawable(Color.WHITE, 25)); - locBtn.setElevation(dp2px(4)); + locBtn.setImageResource(R.drawable.ic_location); + // 设置自定义的白色圆形背景 + locBtn.setBackgroundColor(Color.TRANSPARENT); + // 设置投影(仅在 API 21+ 有效,能产生干净的阴影而非黑块) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + locBtn.setElevation(dp2px(4)); + } + locBtn.setScaleType(ImageView.ScaleType.FIT_CENTER); + int padding = dp2px(2); + locBtn.setPadding(padding, padding, padding, padding); locBtn.setOnClickListener(v -> { if (currentLatLng != null) aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); }); - FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(44), dp2px(44)); - locParams.setMargins(0, 0, dp2px(15), dp2px(250)); // 调高一点,避开底部的面板 + FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(layoutSize, layoutSize); + locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板 locParams.gravity = Gravity.BOTTOM | Gravity.END; container.addView(locBtn, locParams); } @@ -259,24 +305,71 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation panel.setOrientation(LinearLayout.VERTICAL); panel.setBackground(getRoundedDrawable(Color.WHITE, 16)); panel.setPadding(dp2px(20), dp2px(20), dp2px(20), dp2px(20)); - panel.setElevation(dp2px(12)); + // --- (包含标题和关闭按钮) --- + LinearLayout titleLayout = new LinearLayout(context); + titleLayout.setOrientation(LinearLayout.HORIZONTAL); + titleLayout.setGravity(Gravity.CENTER_VERTICAL); + + // 站点名称 (设置 weight: 1 占据剩余空间) tvStationName = new TextView(context); tvStationName.setTextSize(18); tvStationName.setTextColor(Color.BLACK); tvStationName.setTypeface(Typeface.DEFAULT_BOLD); - panel.addView(tvStationName); + LinearLayout.LayoutParams nameParams = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + titleLayout.addView(tvStationName, nameParams); + + // 关闭按钮 (X) + ImageView ivClose = new ImageView(context); + ivClose.setImageResource(R.drawable.ic_close); + ivClose.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + ivClose.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5)); + ivClose.setOnClickListener(v -> { + if (detailPanel != null) + detailPanel.setVisibility(View.GONE); + searchArea.setVisibility(View.VISIBLE); + planToggleBtn.setVisibility(View.VISIBLE); + }); + + LinearLayout.LayoutParams closeParams = new LinearLayout.LayoutParams(dp2px(28), dp2px(28)); + titleLayout.addView(ivClose, closeParams); + + panel.addView(titleLayout); tvStationAddr = new TextView(context); tvStationAddr.setTextSize(13); - tvStationAddr.setPadding(0, dp2px(4), 0, dp2px(10)); + tvStationAddr.setPadding(0, dp2px(4), 0, 0); tvStationAddr.setTextColor(Color.GRAY); panel.addView(tvStationAddr); - tvRouteInfo = new TextView(context); - tvRouteInfo.setTextSize(14); - tvRouteInfo.setTextColor(Color.parseColor("#333333")); - panel.addView(tvRouteInfo); + /*内容*/ + LinearLayout routeInfoLayout = new LinearLayout(context); + routeInfoLayout.setOrientation(LinearLayout.VERTICAL); + routeInfoLayout.setPadding(0, dp2px(5), 0, 0); + + // 第一行:预计时间 + LinearLayout row1 = new LinearLayout(context); + row1.setOrientation(LinearLayout.HORIZONTAL); + row1.setGravity(Gravity.CENTER_VERTICAL); + row1.setPadding(0, dp2px(8), 0, 0); // 增加行间距 + tvDuration = createInfoItem(row1, R.drawable.ic_time, "预计时间:", "", 1.0f); + tvTollsFuel = createInfoItem(row1, R.drawable.ic_fuel, "加氢费用:", "", 1.0f); + routeInfoLayout.addView(row1); + + // 第二行:里程 + 过路费 + LinearLayout row2 = new LinearLayout(context); + row2.setOrientation(LinearLayout.HORIZONTAL); + row2.setGravity(Gravity.CENTER_VERTICAL); + row2.setPadding(0, dp2px(10), 0, 0); // 增加行间距 + + // 里程 + tvDistance = createInfoItem(row2, R.drawable.ic_mileage, "行驶里程:", "", 1.0f); + // 过路费 + tvTolls = createInfoItem(row2, R.drawable.ic_toll, "过路费:", "", 1.0f); + + routeInfoLayout.addView(row2); + panel.addView(routeInfoLayout); Button startNaviBtn = new Button(context); startNaviBtn.setText("开始导航"); @@ -328,14 +421,24 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && !result.getPaths().isEmpty()) { DrivePath path = result.getPaths().get(0); - // 规划成功,显示详情面板 + // 规划成功,显示详情面板,隐藏模式选择 detailPanel.setVisibility(View.VISIBLE); + planToggleBtn.setVisibility(View.GONE); + modeMenu.setVisibility(View.GONE); + tvStationName.setText(endName); tvStationAddr.setText(endAddress); - String info = String.format("预计时间:%d分钟 | 行驶里程:%.1f公里 | 预计路费:%.0f元", - path.getDuration() / 60, path.getDistance() / 1000f, path.getTolls()); - tvRouteInfo.setText(info); + + double distanceKm = path.getDistance() / 1000f; + long durationMin = path.getDuration() / 60; + double tolls = path.getTolls(); + String hydrogenCost = truckRouteData.algorithmPath.hydrogenCost; + + tvDuration.setText("预计时间:" + durationMin + "分钟"); + tvDistance.setText("行驶里程:" + String.format("%.1f", distanceKm) + "公里"); + tvTolls.setText("过路费:" + (int) tolls + "元"); + tvTollsFuel.setText("加氢费用:" + hydrogenCost + "元"); aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(endPoint, 13f)); } else { @@ -806,6 +909,126 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation mapView.onDestroy(); } + + /** + * 辅助方法:创建带图标的文本项 + */ + private TextView createInfoItem(LinearLayout parent, int iconRes, String label, String value, float weight) { + LinearLayout itemContainer = new LinearLayout(mContext); + itemContainer.setOrientation(LinearLayout.HORIZONTAL); + itemContainer.setGravity(Gravity.CENTER_VERTICAL); + + // 图标 + ImageView iv = new ImageView(mContext); + iv.setImageResource(iconRes); + iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + iv.setColorFilter(Color.parseColor("#017143")); // 统一设为主题绿 + itemContainer.addView(iv, new LinearLayout.LayoutParams(dp2px(18), dp2px(18))); + + // 文本内容 + TextView tv = new TextView(mContext); + tv.setText(label + value); + tv.setTextSize(14); + tv.setTextColor(Color.parseColor("#333333")); + tv.setPadding(dp2px(6), 0, 0, 0); + + LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + itemContainer.addView(tv, tvParams); + + // 将整个项加入父容器 + LinearLayout.LayoutParams containerParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, weight); + parent.addView(itemContainer, containerParams); + + return tv; // 返回TextView以便后续更新内容 + } + + // 过载一个不需要weight的方法给第一行使用 + private TextView createInfoItem(LinearLayout parent, int iconRes, String label, String value) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + ImageView iv = new ImageView(mContext); + iv.setImageResource(iconRes); + iv.setColorFilter(Color.parseColor("#017143")); + parent.addView(iv, new LinearLayout.LayoutParams(dp2px(18), dp2px(18))); + + TextView tv = new TextView(mContext); + tv.setTextSize(14); + tv.setTextColor(Color.parseColor("#333333")); + tv.setPadding(dp2px(6), 0, 0, 0); + parent.addView(tv, params); + + return tv; + } + + // 创建模式菜单视图 + private View createModeMenu(Context context) { + LinearLayout menu = new LinearLayout(context); + menu.setOrientation(LinearLayout.VERTICAL); + menu.setBackground(getRoundedDrawable(Color.WHITE, 12)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + menu.setElevation(dp2px(10)); + } + + // 1. 成本计算模式 (高亮绿色头部) + TextView item1 = createMenuItem(context, "成本计算模式", true); + item1.setOnClickListener(v -> switchMode("成本计算")); + + // 2. 送货规划模式 + TextView item2 = createMenuItem(context, "送货规划模式", false); + item2.setOnClickListener(v -> switchMode("送货规划")); + + // 3. 加氢规划模式 + TextView item3 = createMenuItem(context, "加氢规划模式", false); + item3.setOnClickListener(v -> switchMode("加氢规划")); + + menu.addView(item1); + menu.addView(item2); + menu.addView(item3); + return menu; + } + + private TextView createMenuItem(Context context, String text, boolean isHighlight) { + TextView tv = new TextView(context); + tv.setText(text); + tv.setTextSize(13); + tv.setPadding(dp2px(15), dp2px(12), dp2px(15), dp2px(12)); + tv.setGravity(Gravity.CENTER); + if (isHighlight) { + tv.setTextColor(Color.WHITE); + // 顶部圆角绿色背景 + tv.setBackground(getTopRoundedDrawable(Color.parseColor("#27AE60"), 12)); + } else { + tv.setTextColor(Color.parseColor("#666666")); + tv.setBackgroundColor(Color.TRANSPARENT); + } + return tv; + } + + private void switchMode(String mode) { + // 处理模式切换逻辑 + Toast.makeText(mContext, "切换到:" + mode, Toast.LENGTH_SHORT).show(); + modeMenu.setVisibility(View.GONE); + } + + // 获取纯圆形背景 + private GradientDrawable getCircleDrawable(int color) { + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + gd.setShape(GradientDrawable.OVAL); + return gd; + } + + // 获取顶部带圆角,底部直角的背景(用于菜单第一项) + private GradientDrawable getTopRoundedDrawable(int color, int radiusDp) { + float r = dp2px(radiusDp); + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + // 顺序:左上x2, 右上x2, 右下x2, 左下x2 + gd.setCornerRadii(new float[]{r, r, r, r, 0, 0, 0, 0}); + return gd; + } + + /** * 解析接口返回的data数据 */ diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_close.png b/ln_jq_app/android/app/src/main/res/drawable/ic_close.png new file mode 100644 index 0000000000000000000000000000000000000000..b934db94424a3ac3bea0a3ec387ccc1a259d718a GIT binary patch literal 880 zcmV-$1CRWPP)`V|&n2;%-kDI2Vcu;OP#4##rx>+9kFmH-cb0AK3`tQYWb1=d&K z;SXT_5?o(_^%Z!y0_!XA@CUH|3S@o-{=8ljdmTf6%wU&>)R(dZKML=fV)%px$YS}O4m%7&$#)_~|xM0Avxj0Ka7xXRVr? zyL#}4*k}Qewtz+WXUrXU&)hkUogn~H7O@cjh{3vZ1lxs~B><8ZvKW8MU|_c}hiiMl znF8!_`Ih=j0eq@kzwn9xFt8;add?ESLKZu^46Hjx@t1Kk1h9yO&XRP;-Lv;j;YSN# z0gFVW{K8{V-CaGRdUt-L0Ek;4B583L#*c7%z(n<~{3rnsMm!>CVVF|q%ayo3^@6GM z-SG$k5Jfm5XHl5CE~i%KOROhMiBryO0T4tqB4ZkLW0w9K9M8aY) zQN840U`t$|X28_>OL3L}2q6}cunWA{Z0w91$G|U1pQGGA(t{xH2Y?!FNo9`81YXIV15dG@~y0n9`MA;y;*VS1av_}w$I z1V98K#vf^Bu#_2@0;CX{-DC+cTk*TiTQA^lpU7-J>jlhK{BHBs3%J`SGMmqO0kajq z+r0Gx?)Hhy=JVrUK(Ao`00030{}%D5PXGV_21!IgR09Az7;=FG%TB}q0000YiXTK2ElwZ$%jGOmzqlVH;*QVz3<&;owfJ6XWw(L z!A6Hd(3&XqzR?`=HYVVTr|WhK^nHOHL|ffMXl@RezpiaeAeDGfEC!+41jQ4K-@{$M z)~s8dgc}REr)*8s@~J;2w~9>~@eWjajBD%dWNiUusfx>wis%UdrSxId_%qI3OfU6o z;NRg!u!$x)o;#yOw6r$4!KxktS<1{&JqLL1IT>&3-B_4zZBXHV?&dydmZW8Dq;moKT_qfxJ)YK5Wxu%?8W5u z1mlQB1zHou#-f>wGEw;g`E6&76eU&AEukDivZma*gmXt6h8)_EzwI=+pE0MxK=v$e zmEppFrdr9w-2|p=kUN0G=jLoqk3l3$tid37)47YG%Kqb&=Qu7fr9cC$xrggZ78QUt zvY%xn9>rT1e(cjcRPZx(dR8(A_DAV1Mv_l zXLtwNYHpWQ-A4lR35!+(LOxxjT8K$&{WvXG0xE^>3Mp{LesqG6lxI8Zek3dBN!La$S-7>fR>XyPWBw{z`^YAOzfk`fCx@5 z6rL8VCme>*cCkHwdM?5_D3}ZP)fXUMmkHn>wqgt7LBKVjwWdr0dz8hUNSXz1A-+{b zQVx^A97nRgk{GZ_-A-?1>~_mr!J+~x-$7(M!ufj(%Ox{>c^^VB3?KtwcEK|aV~d6e zO%Ma-gB`@~fcg{XA$N%gu-Hk0F@Z_Ljs6UiO^4dK78W}|=x^sPb{G(Jp#LH{0C)Nd z6q~tr3jZ4s0mN|{qHY(BNYI;}{wWIbX7w(dq=v|>TdSbea+=e?v|Kbl$&Dn-WjXv03g+D=}(NC(Em*j zcR7P)W2L|%VPN!(#_VG%@~S8X31yO^V{4MC!BglPJ&QHQ+5#@&Q1&W%M~>O+ z`F)y?Kc_`SP2L$h485c8@~MA>aIcQPivJ4$0RR7`A0%x6000I_L_t&o0Pw@jn$2T| Qi2wiq07*qoM6N<$g8!`@umAu6 literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.png b/ln_jq_app/android/app/src/main/res/drawable/ic_location.png new file mode 100644 index 0000000000000000000000000000000000000000..fa96dc0b1ac8042f49eff9b1d3152728accf1aa8 GIT binary patch literal 3173 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 U%wYT}A^-pY07*qoM6N<$f_Q`noB#j- literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_time.png b/ln_jq_app/android/app/src/main/res/drawable/ic_time.png new file mode 100644 index 0000000000000000000000000000000000000000..38bc14ba2006770faf9f09df22caf31f46022879 GIT binary patch literal 810 zcmV+_1J(SAP)Qv{4*zHevd%sJYS5h3%FQUgRm3XYlWDLmYa08fc$yIVB{G?M$RDu&}#sL z0DcQoAs=p(K$22`#eY z29~$4Y~m0C@4A=P+zEI3^a75@-O*`uj=V&0xECG6UFaAIA{gpLAoR*PijHfl{vQAU o0RR8XgYZoN000I_L_t&o0IIY8F^EkbPXGV_07*qoM6N<$f{6od)c^nh literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_toll.png b/ln_jq_app/android/app/src/main/res/drawable/ic_toll.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae32e3857d1f63fc7178e2dc6a8a8d069d1f27f GIT binary patch literal 924 zcmV;N17rM&P)+H49K94Jy z=uog&iir{Yyr9}^jW0rC-mEB+2@%MoCv8r#j?~>~Yj~v)iQt#{)1)Q7gNeG+Y>6KW zVR~Q>{9`6IHhTDRZl#m{W$Hbip*5)nw4b;)Ce923FH@z!`v3=&=okV-kh7Z~`6EdF z+VxMR+FK>AVh#LBzajnZi}@k>a@ZpE@HbYZRt`a-|K|sW^7I>3aD2--4p@77K|O`q z+P=^~N(c$y-0cxQ;=u?#P+I4{43AR*b^!iANTw1Xtt9=7u#eT zdf3n@^u7vxMTGGa#QN{6i!D*Og(~u;^PX%ik~egfCQ!c|&2^3N%NxO`^~j{d5J8uPnIvOlD%j-%#fZD2y;5_>JySmJR+S5Yn?DW$-hq>&s4RPj&aDM>Dl^%3CgS@dk?!0}x;X^? zL`(el5-SL52;jZ}(Ew!^gfmV4q6mU_?W)b1YvKW|KV`t8)pW{^*^zxNR!3)$UGO?7P}j3Lq3WUp?gdGR>&@r1(Wkp1c+0 yLuN`lHg@+u0{{U3|6z&ZwEzGB21!IgR09BDjiV8ZGuvhW0000 Date: Thu, 26 Mar 2026 18:01:05 +0800 Subject: [PATCH 14/19] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=E9=80=89=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lnkj/ln_jq_app/NativeMapView.java | 114 ++++++++++++++---- .../app/src/main/res/drawable/ic_marker.png | Bin 0 -> 2681 bytes .../src/main/res/drawable/ic_un_marker.png | Bin 0 -> 1859 bytes 3 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_marker.png create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_un_marker.png diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index d3dfc36..68d6b44 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -4,7 +4,9 @@ import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; import android.os.Build; @@ -39,6 +41,7 @@ import com.amap.api.maps.CameraUpdateFactory; import com.amap.api.maps.LocationSource; import com.amap.api.maps.MapView; import com.amap.api.maps.MapsInitializer; +import com.amap.api.maps.model.BitmapDescriptor; import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; @@ -92,8 +95,7 @@ import okhttp3.Response; /** * 高德地图导航 */ -public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, - GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener { +public class NativeMapView implements PlatformView, LocationSource, AMapLocationListener, GeocodeSearch.OnGeocodeSearchListener, RouteSearch.OnRouteSearchListener, AMap.OnMarkerClickListener, Inputtips.InputtipsListener { private static final String TAG = "NativeMapView"; private final FrameLayout container; @@ -316,8 +318,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation tvStationName.setTextSize(18); tvStationName.setTextColor(Color.BLACK); tvStationName.setTypeface(Typeface.DEFAULT_BOLD); - LinearLayout.LayoutParams nameParams = new LinearLayout.LayoutParams( - 0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + LinearLayout.LayoutParams nameParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); titleLayout.addView(tvStationName, nameParams); // 关闭按钮 (X) @@ -398,9 +399,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation // 开始规划前隐藏输入框面板 searchArea.setVisibility(View.GONE); - RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo( - new LatLonPoint(startPoint.latitude, startPoint.longitude), - new LatLonPoint(endPoint.latitude, endPoint.longitude)); + RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude)); RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, ""); routeSearch.calculateDriveRouteAsyn(query); } @@ -466,10 +465,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation //防止 parseDouble 崩溃 if (latStr != null && !latStr.isEmpty() && lngStr != null && !lngStr.isEmpty()) { try { - finalDestinationLatLng = new LatLng( - Double.parseDouble(latStr), - Double.parseDouble(lngStr) - ); + finalDestinationLatLng = new LatLng(Double.parseDouble(latStr), Double.parseDouble(lngStr)); if (truckRouteData.destinationSite.name != null && !truckRouteData.destinationSite.name.isEmpty()) { finalDestinationName = truckRouteData.destinationSite.name; } @@ -582,9 +578,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation json.put("plateNumber", plateNumber); json.put("hydrogenSiteId", selectedSiteId); - Request.Builder requestBuilder = new Request.Builder() - .url(mDebugUrl + "truck/truckRouteAlgorithm") - .post(RequestBody.create(json.toString(), MediaType.parse("application/json"))); + Request.Builder requestBuilder = new Request.Builder().url(mDebugUrl + "truck/truckRouteAlgorithm").post(RequestBody.create(json.toString(), MediaType.parse("application/json"))); if (token != null && !token.isEmpty()) { requestBuilder.addHeader("asoco-token", token); @@ -780,8 +774,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation try { JSONObject item = array.getJSONObject(i); String id = item.getString("id"); - markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), - item.getString("name"), item.getString("address"), id, false); + //推荐站点跳出 + if (selectedSiteId.equals(id)) { + continue; + } + markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), item.getString("name"), item.getString("address"), id, false); } catch (Exception ignored) { } } @@ -798,13 +795,17 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } - private void markStation(LatLng latLng, String name, String address, String stationId, - boolean isRecommend) { - MarkerOptions markerOptions = new MarkerOptions() - .position(latLng).title(name) - .icon(BitmapDescriptorFactory.defaultMarker( - isRecommend ? BitmapDescriptorFactory.HUE_RED - : BitmapDescriptorFactory.HUE_GREEN)); + private void markStation(LatLng latLng, String name, String address, String stationId, boolean isRecommend) { + + String displayName = name; + if (displayName != null && displayName.length() > 7) { + displayName = displayName.substring(0, 7) + "..."; + } + + BitmapDescriptor icon = getMarkerIconWithText(mContext, displayName, isRecommend); + + MarkerOptions markerOptions = new MarkerOptions().position(latLng).icon(icon).anchor(0.5f, 0.8f); // 重点:调整锚点,确保图标尖端对准经纬度 + Marker m = aMap.addMarker(markerOptions); Map dataMap = new HashMap<>(); @@ -818,8 +819,14 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public boolean onMarkerClick(Marker marker) { - Object obj = marker.getObject(); + //地图选点 + for (Marker m : stationMarkers) { + m.setIcon(BitmapDescriptorFactory.fromResource(m.equals(marker) ? R.drawable.ic_marker : R.drawable.ic_un_marker)); + } + + + Object obj = marker.getObject(); if (obj instanceof Map) { Map dataMap = (Map) obj; @@ -909,6 +916,61 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation mapView.onDestroy(); } + public BitmapDescriptor getMarkerIconWithText(Context context, String text, boolean isRecommend) { + // 创建主容器 + LinearLayout container = new LinearLayout(context); + container.setOrientation(LinearLayout.VERTICAL); + container.setGravity(Gravity.CENTER_HORIZONTAL); + // 必须要给容器本身也设置一个基础参数,否则测量可能失败 + container.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + // 文字部分:必须显式设置 LayoutParams + TextView textView = new TextView(context); + textView.setText(text); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + textView.setTextColor(Color.BLACK); + // 设置文字的参数为 WRAP_CONTENT + LinearLayout.LayoutParams textLp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + textView.setLayoutParams(textLp); + container.addView(textView); + + // 图标部分:设置固定大小 + ImageView imageView = new ImageView(context); + imageView.setImageResource(isRecommend ? R.drawable.ic_marker : R.drawable.ic_un_marker); + + int size = dp2px(30); + LinearLayout.LayoutParams imgLp = new LinearLayout.LayoutParams(size, size); + imgLp.topMargin = dp2px(2); + imageView.setLayoutParams(imgLp); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + container.addView(imageView); + + // --- 精准测量 --- + int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + container.measure(spec, spec); + + // 获取测量后的实际宽高 + int measuredWidth = container.getMeasuredWidth(); + int measuredHeight = container.getMeasuredHeight(); + + // 如果测出来是 0,说明有问题 + if (measuredWidth <= 0 || measuredHeight <= 0) { + // 兜底逻辑:如果测量失败,给一个默认大小 + measuredWidth = dp2px(100); + measuredHeight = dp2px(60); + } + + container.layout(0, 0, measuredWidth, measuredHeight); + + // 绘制到 Bitmap + Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + // 绘制前可以选清空背景(透明) + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + container.draw(canvas); + + return BitmapDescriptorFactory.fromBitmap(bitmap); + } /** * 辅助方法:创建带图标的文本项 @@ -970,7 +1032,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } // 1. 成本计算模式 (高亮绿色头部) - TextView item1 = createMenuItem(context, "成本计算模式", true); + TextView item1 = createMenuItem(context, "成本计算模式", false); item1.setOnClickListener(v -> switchMode("成本计算")); // 2. 送货规划模式 @@ -978,7 +1040,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation item2.setOnClickListener(v -> switchMode("送货规划")); // 3. 加氢规划模式 - TextView item3 = createMenuItem(context, "加氢规划模式", false); + TextView item3 = createMenuItem(context, "加氢规划模式", true); item3.setOnClickListener(v -> switchMode("加氢规划")); menu.addView(item1); diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_marker.png b/ln_jq_app/android/app/src/main/res/drawable/ic_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..abafc0a3947df281016f31df872d17764e13e687 GIT binary patch literal 2681 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 literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_un_marker.png b/ln_jq_app/android/app/src/main/res/drawable/ic_un_marker.png new file mode 100644 index 0000000000000000000000000000000000000000..38dc60d03b4a87a570d68c7ddf5c28a464d8ba2c GIT binary patch literal 1859 zcmV-J2fX-+P)s5QBmvm`j+<`s*+o=Vmf5G_t|Ifwb$AA)U~u67V-1=@#CTC>FLW) zpFW*^^5jV-n_)Z9RxDyx{)F}pFQP^0OOS-rgjo?!35UOZ`&P;H({8u*XO^|w?T}?z zkS#@!BOK8BiVo3GeP6;B6!hT1gP}){9yQc#RK!sPjT6+gr2R}5QMUNX@5~v{`pUzH z4;%OH-5b!Mdj9qlBr&H-rP4nlhb)LN$Y%n{k85l$swCh0L zAf2Knf{P-zfM^x-1Y~I%AC+S|K_seRObsAoDz-Tp696fu zJRTWq8uQq?YSp6won*ufHL)<+v`?MZ2(-9d zfb-=$U)F+^Crx3Lo;VRn(A3lvcZJ8~1}aEn&i&3N>YZ6|-XP_&7A#8EIjXma?E5Ft zG5PS3H%jk$f^>l|#v~DtNFhikR0E5Z<+S9m_C7U&*I2V3IO zkQ5H7=m1HwByl1WY7L2FBEXOFP%f9l=FOYK)~#E^wr$(Oh7B9S^5x5E?tImzT>PA$ z$&dpVJ~=~ZK$IVu635hxq)3EMfrV+GxQp>utXL8D?Aa6c?b{c2?AQ^uZ{Ke0+O;d} z-MiN@awNj_xrHOHBNt*~e9VHbU%$@X8KM!OcrGN?1jN^^TNefg2Ll#@B5c{RB~+_b zPmCJsL5H6XOblrM*NKUV3KQaSp;EETQz1d(lKQV-zuI59a%I@Pdw0;wtw={#jGUc2 zcZM}<)_5wB4;zu`hhBi#>eZ_cmlgY60fhLX%14|*5^Lpn&17iQ)p>yhxja%hBE&^6 zPl$u&Ysb{@7X5wx}RzgK!kuk#DXAP3bwQJY*(YiQ= z$#(E^Xu!1S0W_QpTR~9VpgBR34W=Vl{g*Faio5j@<=rG6_mO2H?t==g@ly;zv#8HE z5P|>_0LjMt_wV~?U7XTtwakG4dI9z8;@6s-f4S5%Bme~w!-h{oEaK(Mm&M)sh`xC7 z!kprYB5di0NLfC0^lWmer^2F4lMBu$a3V3huQOUX%y z;;HcY^XEZ-|Aj`Qp|av%9xplM#@hHw5ifToLHq70TbC9;GB(E*U?Y9>Dby*F5bY_3rGjC4&}%LV1(9^}=%3m;O&JU3W|lNPoL(Z`(34JF%37vmnhZoM7K23#f}BR@&!0aipL@lHHJA`F?d`ACYCpU$ z%ANQ7Q-UJPg$oyWUvc4E5;Lo59V8a_f5t9J5Dhg6UI~K|RK+K@6f9W~%_XD>@Ry4J xMbJ`3bk_d|00960K=#F~00006Nkl Date: Fri, 27 Mar 2026 09:37:52 +0800 Subject: [PATCH 15/19] =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/.claude/settings.local.json | 8 ++++++++ .../src/main/java/com/lnkj/ln_jq_app/NativeMapView.java | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 ln_jq_app/.claude/settings.local.json diff --git a/ln_jq_app/.claude/settings.local.json b/ln_jq_app/.claude/settings.local.json new file mode 100644 index 0000000..f948202 --- /dev/null +++ b/ln_jq_app/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(flutter build apk --debug 2>&1 | tail -15)", + "Bash(flutter build apk --debug 2>&1 | tail -10)" + ] + } +} diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 68d6b44..70ca7da 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -804,7 +804,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation BitmapDescriptor icon = getMarkerIconWithText(mContext, displayName, isRecommend); - MarkerOptions markerOptions = new MarkerOptions().position(latLng).icon(icon).anchor(0.5f, 0.8f); // 重点:调整锚点,确保图标尖端对准经纬度 + MarkerOptions markerOptions = new MarkerOptions() + .title(name). + position(latLng).icon(icon).anchor(0.5f, 0.8f); Marker m = aMap.addMarker(markerOptions); @@ -929,6 +931,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation textView.setText(text); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); textView.setTextColor(Color.BLACK); + textView.setTypeface(null, Typeface.BOLD); // 设置文字的参数为 WRAP_CONTENT LinearLayout.LayoutParams textLp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); textView.setLayoutParams(textLp); From 587dd48896da2872d4911bcc7a8296074eecf511 Mon Sep 17 00:00:00 2001 From: userGyl Date: Fri, 27 Mar 2026 11:45:07 +0800 Subject: [PATCH 16/19] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lnkj/ln_jq_app/NativeMapView.java | 166 ++++++++++++++++-- .../c_page/base_widgets/NativePageIOS.dart | 30 +++- 2 files changed, 180 insertions(+), 16 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 70ca7da..3acfd12 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -7,27 +7,34 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PorterDuff; +import android.graphics.Rect; import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Editable; +import android.text.InputType; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; @@ -117,6 +124,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private View modeMenu; //模式选择 private TextView tvStationName, tvStationAddr, planToggleBtn; + private ListView suggestionList; // 输入提示列表 + private ArrayAdapter suggestionAdapter; // 提示列表适配器 + private List currentTipList; // 当前提示列表 //时间 费用 里程 路费 private TextView tvDuration, tvDistance, tvTolls, tvTollsFuel; @@ -150,6 +160,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation container = new FrameLayout(context); container.setClickable(true); container.setFocusable(true); + container.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); + mapView = new MapView(context); mapView.onCreate(null); @@ -179,9 +191,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } + private LinearLayout bottomContainer; private void initOverlays(Context context) { // --- 底部主容器 (包含两个互斥显示的面板) --- - LinearLayout bottomContainer = new LinearLayout(context); + bottomContainer = new LinearLayout(context); bottomContainer.setOrientation(LinearLayout.VERTICAL); bottomContainer.setGravity(Gravity.BOTTOM); @@ -194,18 +207,72 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation searchArea = new LinearLayout(context); searchArea.setOrientation(LinearLayout.VERTICAL); searchArea.setBackground(getRoundedDrawable(Color.WHITE, 16)); - searchArea.setElevation(dp2px(10)); int p = dp2px(15); searchArea.setPadding(p, p, p, p); + searchArea.setFocusable(true); + searchArea.setFocusableInTouchMode(true); endInput = new EditText(context); endInput.setHint("请输入目的地,不输入则自动匹配推荐加氢站"); endInput.setTextSize(13); - endInput.setHintTextColor(Color.LTGRAY); + endInput.setHintTextColor(Color.GRAY); endInput.setPadding(dp2px(12), dp2px(12), dp2px(12), dp2px(12)); endInput.setBackground(getRoundedDrawable(Color.parseColor("#F8F8F8"), 8)); endInput.setSingleLine(true); + endInput.setInputType(InputType.TYPE_CLASS_TEXT); // 明确输入类型 endInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + endInput.setFocusable(true); + endInput.setFocusableInTouchMode(true); + endInput.setClickable(true); + endInput.setCursorVisible(true); + + // 针对 EditText 的特殊处理 + endInput.setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_UP) { + v.requestFocus(); + v.postDelayed(() -> { + InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + // 使用 SHOW_FORCED 或确保结果成功 + imm.showSoftInput(v, InputMethodManager.SHOW_FORCED); + } + }, 100); + } + return false; + }); + + // 处理搜索键按下 + endInput.setOnEditorActionListener((v, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_SEARCH) { + suggestionList.setVisibility(View.GONE); + // 可以在这里直接触发路线规划,但保持原来的按钮点击逻辑 + return true; + } + return false; + }); + + // 初始化提示列表 + currentTipList = new ArrayList<>(); + suggestionList = new ListView(context); + suggestionList.setBackgroundColor(Color.WHITE); + suggestionList.setDividerHeight(1); + suggestionList.setDivider(new ColorDrawable(Color.LTGRAY)); + suggestionList.setPadding(dp2px(5), dp2px(5), dp2px(5), dp2px(5)); + suggestionAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1); + suggestionList.setAdapter(suggestionAdapter); + suggestionList.setVisibility(View.GONE); + suggestionList.setOnItemClickListener((parent, view, position, id) -> { + Tip tip = currentTipList.get(position); + if (tip.getPoint() != null) { + endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude()); + String name = tip.getName(); + String district = tip.getDistrict(); + endName = name; + endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name); + suggestionList.setVisibility(View.GONE); + } + }); + endInput.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -214,11 +281,15 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() > 1) { - InputtipsQuery query = new InputtipsQuery(s.toString(), ""); + // 使用当前位置的城市进行搜索 + String city = currentLatLng != null ? "" : ""; + InputtipsQuery query = new InputtipsQuery(s.toString(), city); query.setCityLimit(true); Inputtips inputtips = new Inputtips(mContext, query); inputtips.setInputtipsListener(NativeMapView.this); inputtips.requestInputtipsAsyn(); + } else { + suggestionList.setVisibility(View.GONE); } } @@ -226,7 +297,14 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public void afterTextChanged(Editable s) { } }); + endInput.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + suggestionList.setVisibility(View.GONE); + } + }); + searchArea.addView(endInput); + searchArea.addView(suggestionList); View vSpace = new View(context); searchArea.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(12))); @@ -235,7 +313,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation planBtn.setText("规划路线"); planBtn.setTextColor(Color.WHITE); planBtn.setTypeface(Typeface.DEFAULT_BOLD); - planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 10)); + planBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 99)); planBtn.setOnClickListener(v -> calculateRouteBeforeNavi()); searchArea.addView(planBtn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(48))); @@ -300,8 +378,40 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation locParams.setMargins(0, 0, dp2px(15), dp2px(285)); // 调高一点,避开底部的面板 locParams.gravity = Gravity.BOTTOM | Gravity.END; container.addView(locBtn, locParams); - } + //最后调用监听函数 + addKeyboardListener(); + } + private void addKeyboardListener() { + container.getViewTreeObserver().addOnGlobalLayoutListener(() -> { + Rect r = new Rect(); + // 获取当前窗口可视区域 + container.getWindowVisibleDisplayFrame(r); + + // screenHeight - 可视区域高度 = 键盘高度 + int screenHeight = container.getRootView().getHeight(); + int keypadHeight = screenHeight - r.bottom; + + // 如果键盘高度大于屏幕的 15%,说明键盘弹出了 + if (keypadHeight > screenHeight * 0.15) { + // 键盘弹出:增加底部 Margin + updateBottomMargin(keypadHeight); + } else { + // 键盘收起:恢复原有 Margin (你代码中设置的是 dp2px(65)) + updateBottomMargin(dp2px(65)); + } + }); + } + private void updateBottomMargin(int bottomPx) { + if (bottomContainer != null) { + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomContainer.getLayoutParams(); + if (params != null) { + // 动态设置底部间距 + params.setMargins(dp2px(12), 0, dp2px(12), bottomPx); + bottomContainer.setLayoutParams(params); + } + } + } private LinearLayout createDetailPanel(Context context) { LinearLayout panel = new LinearLayout(context); panel.setOrientation(LinearLayout.VERTICAL); @@ -407,11 +517,40 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onGetInputtips(List tipList, int rCode) { if (rCode == 1000 && tipList != null && !tipList.isEmpty()) { - Tip tip = tipList.get(0); - if (tip.getPoint() != null) { - endPoint = new LatLng(tip.getPoint().getLatitude(), tip.getPoint().getLongitude()); - endName = tip.getName(); + currentTipList.clear(); + currentTipList.addAll(tipList); + + List suggestionNames = new ArrayList<>(); + for (Tip tip : tipList) { + String name = tip.getName(); + String district = tip.getDistrict(); + // 在提示中显示名称和区域 + String displayText = district != null && !district.isEmpty() ? name + " " + district : name; + suggestionNames.add(displayText); } + + suggestionAdapter.clear(); + suggestionAdapter.addAll(suggestionNames); + suggestionAdapter.notifyDataSetChanged(); + + // 显示提示列表 + new Handler(Looper.getMainLooper()).post(() -> { + if (suggestionNames.size() > 0) { + suggestionList.setVisibility(View.VISIBLE); + // 限制显示的高度 + int height = Math.min(suggestionNames.size() * dp2px(45), dp2px(200)); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + height + ); + suggestionList.setLayoutParams(params); + } else { + suggestionList.setVisibility(View.GONE); + } + }); + } else { + // 请求失败或无结果,隐藏提示列表 + new Handler(Looper.getMainLooper()).post(() -> suggestionList.setVisibility(View.GONE)); } } @@ -619,6 +758,13 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation aMap.setMyLocationEnabled(true); aMap.setOnMarkerClickListener(this); + // 添加地图触摸监听器,点击地图时隐藏提示列表 + aMap.setOnMapClickListener(latLng -> { + if (suggestionList != null && suggestionList.getVisibility() == View.VISIBLE) { + suggestionList.setVisibility(View.GONE); + } + }); + MyLocationStyle myLocationStyle = new MyLocationStyle(); try { Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car); diff --git a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart index 150ab11..cb131ea 100644 --- a/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart +++ b/ln_jq_app/lib/pages/c_page/base_widgets/NativePageIOS.dart @@ -45,12 +45,30 @@ class NativePageIOS extends StatelessWidget { width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - 100, color: Colors.white, - child: AndroidView( - viewType: 'NativeFirstPage', // 与Android原生端注册的标识一致 - gestureRecognizers: >{}.toSet(), - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - creationParamsCodec: const StandardMessageCodec(), - layoutDirection: TextDirection.ltr, + child: PlatformViewLink( + viewType: 'NativeFirstPage', + surfaceFactory: (context, controller) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (params) { + // 使用 initSurfaceAndroidView 强制开启 Hybrid Composition + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: 'NativeFirstPage', + layoutDirection: TextDirection.ltr, + creationParams: {}, // 你的参数 + creationParamsCodec: const StandardMessageCodec(), + onFocus: () { + params.onFocusChanged(true); + }, + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, ), ); } From 01230252969ddc735f538c6d13da10382106bb72 Mon Sep 17 00:00:00 2001 From: userGyl Date: Fri, 27 Mar 2026 13:23:10 +0800 Subject: [PATCH 17/19] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/lnkj/ln_jq_app/NativeMapView.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 3acfd12..720435a 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -137,6 +137,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private LatLng startPoint; private LatLng endPoint; private boolean isFirstLocation = true; + private boolean isUserSelectedDestination = false; // 标识用户是否手动选择了目的地 + private boolean isProgrammaticTextChange = false; // 标识是否是程序自动设置文本 private final List stationMarkers = new ArrayList<>(); // 存储token和车牌号 @@ -268,7 +270,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation String name = tip.getName(); String district = tip.getDistrict(); endName = name; + isUserSelectedDestination = true; // 标识用户手动选择了目的地 + isProgrammaticTextChange = true; // 标识是程序自动设置文本 endInput.setText(district != null && !district.isEmpty() ? name + " " + district : name); + isProgrammaticTextChange = false; // 恢复标志 suggestionList.setVisibility(View.GONE); } }); @@ -280,6 +285,11 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onTextChanged(CharSequence s, int start, int before, int count) { + // 如果是程序自动设置文本,不触发搜索 + if (isProgrammaticTextChange) { + return; + } + if (s.length() > 1) { // 使用当前位置的城市进行搜索 String city = currentLatLng != null ? "" : ""; @@ -593,11 +603,16 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } //确定目的地坐标和名称 - // 优先级:truckRouteData (接口返回的精准点) > endPoint (地图点击/搜索的点) + // 优先级:用户手动选择 > truckRouteData (接口返回的精准点) > endPoint (地图点击/搜索的点) LatLng finalDestinationLatLng = null; String finalDestinationName = endName; - if (truckRouteData != null && truckRouteData.destinationSite != null) { + // 如果用户手动选择了目的地,直接使用用户选择的地址 + if (isUserSelectedDestination && endPoint != null) { + finalDestinationLatLng = endPoint; + finalDestinationName = endName; + } else if (truckRouteData != null && truckRouteData.destinationSite != null) { + // 否则使用接口返回的推荐加氢站地址 String latStr = truckRouteData.destinationSite.latitude; String lngStr = truckRouteData.destinationSite.longitude; @@ -883,6 +898,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation endName = data.getString("name"); selectedSiteId = data.optString("id", ""); endAddress = data.optString("address", ""); + isUserSelectedDestination = false; // 系统推荐的地址,不是用户选择 new Handler(Looper.getMainLooper()).post(() -> { markStation(endPoint, endName, endAddress, selectedSiteId, true); }); @@ -994,6 +1010,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation // 更新 UI 和 业务逻辑 endName = marker.getTitle(); + isUserSelectedDestination = true; // 标识用户手动选择了目的地 // 需要传入当前位置以便接口计算路线 if (mlocationClient != null && mlocationClient.getLastKnownLocation() != null) { From 5843ef6e87b306c5998d81f99fb7f0b01bdd34bb Mon Sep 17 00:00:00 2001 From: xiaogg Date: Fri, 27 Mar 2026 15:39:36 +0800 Subject: [PATCH 18/19] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E9=80=94=E7=BB=8F?= =?UTF-8?q?=E7=82=B9=EF=BC=8C=E5=AE=8C=E5=96=84=E8=A7=84=E5=88=92=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E8=88=AA=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes .../ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec | 1 + .../cal_ruoute_icon@3x.png | Bin 0 -> 966 bytes .../Assets/AMapNavIOSSDK.bundle/car@2x.png | Bin 0 -> 8414 bytes .../AMapNavIOSSDK.bundle/ic_fuel@3x.png | Bin 0 -> 1279 bytes .../Assets/AMapNavIOSSDK.bundle/ic_tag@2x.png | Bin 0 -> 3468 bytes .../locationing_arrow_icon@3x.png | Bin 0 -> 2067 bytes .../my_location_icon@3x.png | Bin 0 -> 2796 bytes .../AMapNavIOSSDK.bundle/pre_cost_icon@3x.png | Bin 0 -> 1053 bytes .../pre_distance_icon@3x.png | Bin 0 -> 1187 bytes .../AMapNavIOSSDK.bundle/pre_time_icon@3x.png | Bin 0 -> 829 bytes .../AMapNavIOSSDK.bundle/search_icon@3x.png | Bin 0 -> 1321 bytes .../station_normal_icon@3x.png | Bin 0 -> 1379 bytes .../station_select_icon@3x.png | Bin 0 -> 1810 bytes .../Classes/Class/ACustomAnnotationView.h | 17 + .../Classes/Class/ACustomAnnotationView.m | 177 ++++ .../Classes/Class/AMapNavSDKHeader.h | 39 + .../Classes/Class/AMapNavSDKManager.h | 2 - .../Classes/Class/ARoutePlaneController.h | 6 + .../Classes/Class/ARoutePlaneController.m | 772 ++++++++++++------ .../Classes/Class/ASearchAddressController.m | 5 +- .../Class/AStationDetailPopupController.h | 55 ++ .../Class/AStationDetailPopupController.m | 485 +++++++++++ .../Classes/Model/AAlgorithmPathModel.h | 67 ++ .../Classes/Model/AAlgorithmPathModel.m | 12 + .../Classes/Model/ACustomPointAnnotation.h | 17 + .../Classes/Model/ACustomPointAnnotation.m | 12 + .../{Class => Model}/AMapHyStationModel.h | 2 + .../{Class => Model}/AMapHyStationModel.m | 4 + .../Classes/Model/ANavPointModel.h | 26 + .../Classes/Model/ANavPointModel.m | 22 + .../Classes/Model/ANaviPathInfoModel.h | 32 + .../Classes/Model/ANaviPathInfoModel.m | 20 + .../AMapNavIOSSDK/Classes/Model/APathModel.h | 29 + .../AMapNavIOSSDK/Classes/Model/APathModel.m | 17 + .../AMapNavIOSSDK/Classes/Model/ASiteModel.h | 64 ++ .../AMapNavIOSSDK/Classes/Model/ASiteModel.m | 12 + .../Classes/Model/ATripCalcResponse.h | 65 ++ .../Classes/Model/ATripCalcResponse.m | 33 + .../AMapNavIOSSDK/Classes/Model/ATruckModel.h | 58 ++ .../AMapNavIOSSDK/Classes/Model/ATruckModel.m | 12 + .../Classes/Tools/AMapNavCommonUtil.h | 22 +- .../Classes/Tools/AMapNavCommonUtil.m | 119 ++- .../Classes/Tools/SelectableOverlay.h | 12 +- .../Classes/Tools/SelectableOverlay.m | 32 +- .../Classes/View/ABottomBarView.h | 32 + .../Classes/View/ABottomBarView.m | 204 +++++ .../Classes/View/ACustomStepView.h | 21 + .../Classes/View/ACustomStepView.m | 121 +++ ln_jq_app/ios/Podfile | 2 + ln_jq_app/ios/Podfile.lock | 41 +- .../ios/Runner.xcodeproj/project.pbxproj | 4 - ln_jq_app/lib/common/token_interceptor.dart | 1 + ln_jq_app/pubspec.lock | 428 +++++----- 54 files changed, 2596 insertions(+), 506 deletions(-) create mode 100644 .DS_Store create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/cal_ruoute_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/car@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_tag@2x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/locationing_arrow_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/my_location_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_cost_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_distance_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_time_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/search_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_normal_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_select_icon@3x.png create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomAnnotationView.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomAnnotationView.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.m rename ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/{Class => Model}/AMapHyStationModel.h (95%) rename ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/{Class => Model}/AMapHyStationModel.m (78%) create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.h create mode 100644 ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.m diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..efe8a43032128f49b8c4fed186c168ee371ff489 GIT binary patch literal 6148 zcmeHKL5tHs6n?WC-HFRW5rqXk40x^DxXa?=C3Y*`jp#w8CZ=?wX(qO*J(NO@vi^qM zn-}q}|3L5uh(~{d{s6)EW~P|ZxCaj+WgfiuP3FBfllPU(^Z@{Ck7Ey@0RSA8&^d>u zM#xXPBx`1d@))g=_PyYl9OO%pcEU1X8TcO=pl{cKYtV-TiiPj@>iD?o8^}&4N@av| z{LNf$0$#eQPFCBVQcHo znX?;wgKzRD!J(W4MOchS?Qr;rp6*MTM)PqPJxF?!ZsWp%%!)9{dP9|v#61jo{4mL4 zIcdvr7LQbJpdH-hZnv>Loq9W7Q+VF~tSP4ZH(E`xyR$c&x%}dl>$mQ8U!;Rf9?`4g zfrlrak}ZRCc!PtQ%BtMHyL|q8eN>g@t=DgFx+jX|n)L?qH{Yj6R+)eQ^BcWq&3dnb zVV26QkKTD@6lrC388E*y-(1}iZDp1L%fMeUK<9%%CG-uJ8r9K(MzsKl4o)kLoON}}mm}x$k*_oLRg{j?feWAjE`5LXY3|Iyh z8Cchk4Z8pD{JH;MOtMdw0n5NjF~FQo&}m~y=5Adoj_z84`V^If;!2Gw1&z6m)qt+z dZB!-b6Er~d4VD^l2F3mnP&8O$8Th9R`~sfBkXir$ literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec index 60e22d0..b5adbfa 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec @@ -46,5 +46,6 @@ TODO: Add long description of the pod here. s.dependency 'AMapNavi-NO-IDFA' s.dependency 'AMapLocation-NO-IDFA' s.dependency 'AMapSearch-NO-IDFA' + s.dependency 'MBProgressHUD' end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/cal_ruoute_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/cal_ruoute_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..65a78f1a0ecf095062e3b2c5dec558fab353e3c2 GIT binary patch literal 966 zcmV;%13CPOP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0FiAu~R9Fe^mu+Z`VHn4EwrLw1 z>�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 HET8=k=``(M literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_fuel@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a928c03fb80efaf4e3ab97f9459d84cd03599259 GIT binary patch literal 1279 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR917@z|H1ONa40RR917ytkO0OB=utpET7X-PyuR7eetRb6aUMHK#K?)KM! zq}5ntt=iClF)F5EyK9ZKF&2ZVF&duKL|#b62U}?IC(+i#2cuw15H;0kd?5s4tf5MH zAQ&)oX;aih(V&nDT?wf_wYBYTZ|@wxneA?NTMC_I=FXh+o!>cUu7{-#fx>vK46)lv z5FeRds+hMVpjF;hTc-r?D9Gce3y&cDKmupa%Jt-zW?(!PQAR$avMA>o1w4f16a9=N zaXkaXUSn+D>>)f-qhJmbRmM3uhhER`-vZr)k?;@>9SY{?3qE=QB}1@j314bZD%ekw zRo*L7_>`S?Z)uK43@mn$v3QEcW2@--r+~VP^Eef6Mfb_eh+q5<(W-BiGWSy_qmz4Z zw6c%snz)*ct4FZ2ZkdMJMaB10Xiz-;v{RnZKttj!f5P%0Y8{QekJea8hMoIe7{PP( z#VDM4ji6@EGh%{g(RKP_u8`ZGI`5-)P=jAy1vCh=%>9N!F^T2$DrSlj>wf>12&N&n@!|$Vv*10-==S?;E^=KzA|p zJxt93dN@h?Bo*(sGYkP~9fw>d=j_Y~G0Fez4%*i!t*O}n== zcpY#UUcINcG0I{#=Rqesx8z3<;7eX9p9r-PEwybdn0@H#w|}o`zBL!<`#CTa=-_AU zw#GR+>x=bR@+B&MlBZ!Z4_k6(>M11sfL&bAbktK}0Xy@YdnxT}S+}|mp{ZW% zI&;M-cp*}*XM-2n6YV_vH1aAEl_zrlbZowP!@i12cJi`2$w_klL1Q1YqrXOZ=}!** z*VNrw>kXm})1=mrR>FH}&xzQoxSDA4M}+_Y002ovPDHLkV1gI9MDzdv literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_tag@2x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/ic_tag@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dcae650ed00ba1898bc26a07ed2e1943fef0ec8c GIT binary patch literal 3468 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 literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/my_location_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/my_location_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3488026b797db3e92d12a041d32eb0fca1c84970 GIT binary patch literal 2796 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 Xb~ieoG&B}i00000NkvXXu0mjfk?h#~ literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_distance_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_distance_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..aeb9896fc60d61959af831446f910d55977ad77c GIT binary patch literal 1187 zcmV;U1YG-xP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR917@z|H1ONa40RR917ytkO0OB=utpET74M{{nR7ee-Rc~mORT%$0=e^tA zl{RK87|iRZhNY1Zx;dAT_Q&i)5#g60%>I!|qbp@$(8TgX|JZ06Nn#E} z@0~+RVJ4#wk-Kw&#IAG8yX(%=@4WZl`|d6q9XRhf=lA^1^E~G~&v{;fYkTgi!IkM{ zM&%U+9wSlMjwTj3B$aP)ghKnBwg&xqV)b%~nlH%tn#wm4tMzfkO72ZCrUS@KC$N3R zO%C_4CjO^D*KxkYC(iTX+vrAmX+IvRzm>7+=V{t#(3^+qps1*{BT_Ymhnr7(NR3XS zZRs>EKR{tk#U|Aubf4aW`)8^}qJ2EsDk?ACT?O9(f+|v$BRkXYvIxjt=~JtR{CW8E zo7%`TK2+VnY?Ir=VodRLJ?wj#EXOD-UbUk&k^fZQz=7ebz|3w{(8E%jP?%0!YRU)K znq`#Km86`g>U+q>wxMgVla*jA6@C|#^Au0y4LG#>mkEg3&TTF|b0YE;YtSJaKI|T! z(-!A9oT@qW;=ll%W7|J;QN_AM$n$*=x0Ma}q~w?y>EKCr+1%n+^PIw0)V=KB6#!L% z#Bc@EN}LH0(5aVi9IT*)MC(H&yEruj;9<3R5z)w5WOGl7!P~s1Qo*F7-$nvtm_+Nl zEEQXs&!6*NcLim9GQ)r!pJQMJm7YM32QwAEUW3{X1IOVtgWk{szKf2qa<2GKphxdi z;Qs=!LLY(T&V>w+`*)r%QFN@jvtn<3td|>mEAUF-FM9tO6DJckAV`(Co_Q3TH-}%V zt1njGBIgD_AGLh#edro;DXSp^yaMN)pDE1YZCEn;V1MLPx#u-pI2;Z9zoVJthzpAfn`NK?|Hm`YOIJ? zgdQ)iX=hzJNWvXOQem8A5_}xYF0-@cpsGAgxy!~&jL&n}Klnp|?+>9X@{#V;Nj2UU zrqodut!n`?Pvpu$xmg>1lbr8))e|bxiMrU2WodpEzM`Tud2tNwjr|Ph5c7Kx;c6;h z#P{(DQt6{b8d85;#oESW@Vp+>#*P<%G9@`D{{Yn@V0@avNVNa}002ovPDHLkV1h|n BD`Efu literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_time_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/pre_time_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..1803f2c832d3c44eb3b81922f6c123ebcabc6a18 GIT binary patch literal 829 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfoZv?i(`lf z@7B<>*};wi|Ia=KmRc5IK_7I;Sh?VA~4ah+tFB_fLB_SKi$B-De&rXKX~;^VjCT4UM_id|a^Y z$MoZ6Og3B=yAMoRb6fjgpA=WX)$b?jH2&}_+Z_b=DSXrB@%hHVU69GQ+vCxk9c zo!PypzAfVk-@AQrnJ<`@SRS}?ktOVu`-y|j8)Y~n+6~WCrj?4FJi@cAXxn|AN9hU= zvUb+^mHl!k(+R))P(e!NkYUIheT#k7d^;csaXF}TN@qUD4+n>LM&4@*+8q0% zUu?;UXu5N_-|N`=@9SRNTG*R%Q{L6`g}Fg?nvLt08o4cX>^J|onO)2;VO+JoTZw(* z+-vzP?^(ifgMLhVz}Qg6b209KoOxOvgQqLge4|5gnvT8>c`lE4Fy4@4PK;iE!0!Ls z6}NuxVQ}E$Ir*8-jWxBcN;Q9y@at(i^*`CoJZvPbu8=dS)Q9_4-+E_Pjcl2%KQc8p zbt`@=bjjF!&DEJ_){#khnPozmOT?x<@NjfrI#0$kMxTFn&6Wea2Q)ets@D9_XI4puPKB%4g3!|7reHj|usl>wN1L_hsH=_~O^n z?f87&4yB}xk-ZO=WtQza&?0W@_-l^jIpxc-d%en5ZFijW{buRblxNe6KKu7<7Ju;X zjgj>XfurV&-!#>+xvraSx8(0$hFQOZtF^6nX!74XTYaYcy{OKTG?OWkXEO^F_wr3S z6X4?MRd($Ui$(tg{^gbpoNH%KP4yLev7}?$sVh&{+iSdCT(5gqt?MiM)$)58=asm7 zJ}?}6laFA7hB~-`h$|Lr>mdKI;Vst E0ALJY5C8xG literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/search_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/search_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..47cb9b95b9543f7624b43aebd9bad8dafb5788f7 GIT binary patch literal 1321 zcmV+^1=jkBP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR918=wOK1ONa40RR918vpVrB{V@#TM#Wx z0c+62`^RWfidv}g8d@>7NdXB`OOJ!wH_qN=$=&f$O8@gEo7tH+GryVHdGi+F|GIFg z#0m-y*c}No845)?A!Y%nQ~*>2FodMOlQulv>24Zb%18L#f?&G-M(nJd$yGwRfFPR< zCK+Igm1mhE(^vvZKtMYYH7kJ)Iq50GE|*J%JCA;!2UhUHfpsy)>>kPt7mOqPxMP@J@RO3yD?^91}>vS}T#Ycc`)Av4T*X+jt zXeVdzejuPVY~7eRzF5S0yLUTQ&))Z_GK>?PZaM?L`9wxa%VPR-V5}hey*Ca6h<6pK z+U~ZdBUVI3d-kjnw__4XQk)1#@++8#hq1Aajt;}r$$zmb*&e_yc9urU*wNMA+;7>2 zQ(-X|yra4NIo<{&_l#|-&XPMzYn}w3y;&iCPfA=g1pTT>>YTPEy=4Yr>h*Gy5UO&{ z>^h>TH5<#a52tfr0_b%HyM-tld)@9SQ^{FcnZeOEa!K>~`A{jfS&=B<<`_YOcQ}X> zma{GCX;%=@&F!;QTOD}bl84h^84HVF$r3{JaA$qn)z(yDDKJHx>68c{&7U)Va@Fu7&%s%9zGN$4vSCx9e-xKSS^62&xjQQLyTvs<~h~;cf{@r z7zM@zn@Ne%^ck^&U zY#;=`k}z*(hQI_2vDGaya63Hy&f=Iax@BL}zZHGEkvwFsT1`!o2aIL;kd!jof!l>BEgi|A&+g5t{c zHYty?@iRP8&Vz!F&$c(7j&_ire>mQrzNG%NGrKEk-KL5M*Hnqc5~23d=O9^e43@%uSMIx6gr54t~V7&gD}nk|oA zj4^DJ47iI>Zpz%4{p0VKE|?P~xE9UKQZT7`KiN}ctbfX|X_}uL0d0D0EP2}FadA?S z%k1QM???$}QO_w|_K(Lu-P>Ciyt0-B7U}NJoCz2zDb^TD={@aDgLk&N2MzQ8q^NXX f%00NaH`D(BAYHjYaVjc=00000NkvXXu0mjf8pBsk literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_normal_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_normal_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..720eec260b341187543e14e6a4f8b8ec206ae008 GIT binary patch literal 1379 zcmV-p1)TbcP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR918=wOK1ONa40RR919{>OV00WQmIRF3z%}GQ-R7efQR$oYDRTw{a=8l>& zXrnIFBCDn-6S1_QY^5O)^cX?-5Nzd24?q`yxK{60{U#kBdl_ir}9` zVqHWBLYQW7M-Vmt%{Y4Z_d9pa-E;5E#jTePoO{0W{ri32cfNb>HH6QYo}M<#%gZlY zmUTTC40ZFH?~GJHe^hf)-? zv$M=-90n}}(ZD2atJ_ZnsOwQ*4aLWP31|69dwctzlu59;xw$Zy_o4Kf7M%k^V+@Gw z^TJ-w$SZU0v6)13z0WfY4h{|mYHDh3fcX)e6=OcU=u=VfaRQt1S2?JY|-4@EVCi7KA17yN72~WD6`w$-Ib+>j$9#E zK8rwn5I{ZOX6=D&09bG;n&oP0YAOh%gHo@qu8wCZ?LB_1+`h#G&`Zofi^8ERDk}0y zr-SG;&$6_%RP5~R=xov|%P7kjA(zyP*k6%`d3jQUvyvkHYmGBeuJ27Xmp=`cdD zG??y_x4j$bbXs=Vvj8$+b|_1RA%nH?oLeQ$GR83*Z2#`({{Fsnz=$szxS9kSLYK9;A}KGQz#RJrR$`U9UkQP&!YgQi8$Jj()UNHXeA72zH+W?^FhB zYilBzO!@*6i1L+{l{_E1PxzZ)8RuY-K*TRHYS8kkK^bHcydCg05cT!-A{vd#CXfO= z=xlv`T~1sMiY)_!JzUw}KnRkU^CoVE#NpxLuMqTTb#`S!z}3}N5sSq{Wo4zjve-O{ zL_z}QP@E2Apadcx$yn&r3A`3@$rv9WzYc|aP`Ev4x-R|k>`C7?LMQ}yy-oeG1g`+Q^T&2r2+7+P2cSzW8V>5DaaB$aQg2*!*9UXlR z%GWS|f&7xLd=U*Bo>vNi-oVk!c6D_;Lqr%;7|1R_2vDT>bky}DW$2YsSN-9;4B8PS23Sw zHdvY6Uznd~GMRh*{rzcW8D8k(9lo|mO%i&1(4rJ4-5>r{(7nBH~tkEo#5B+ l62M*o*hA1MKga(&{|Qa_ZKhA_UWNbw002ovPDHLkV1hM)cftSw literal 0 HcmV?d00001 diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_select_icon@3x.png b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Assets/AMapNavIOSSDK.bundle/station_select_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9654ffab13a7d985e0a6a5b2e1e894b40a16347c GIT binary patch literal 1810 zcmV+t2krQYP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR919-spN1ONa40RR91ApigX0O>FoQUCx3d`Uz>R7ee_S6ggVMHJmL=d``I z&E-*iQYAqsuQmdK5-C4TwCD#K305UBL`4aRi7^5p1QU#nN-$`mF$jhaKh>koZv> z6iEz1czQvSA_4({G~rcCX?uIm%((W=CL1Z?b)+uZYyYnX12ba?(HeB zltIaKBC~`@)RLfSa2qSo8ABaJx`VXbYe=`ILV1dMsY7hq6b%Q>zC$+C)D-mAOsSKB zcuA97AcUzEWCCM^0P*cw9~5WEh+Rs_?<-E8JRw?I)KJFZP(qgV)K+f*(JH0Q{era6 z*lJ>HFe|K_*vV2@)F8BJ_+AFam()V|7=|QNGO6&Nzx)~XOK+W0ELE* z1>VnK=Hw=pV4rUj*c~JDm!E(?pg)V#~*=R`ExOiib2tEn;Suxjv z^>sP$92U}cLTn!0dFx%VeS6*(*Y%3j<5KJ808gOp)Uq3+9cMxsTP4+vvPEc)2SX7z z3teq+Y>4sItL3FXLbz94S+_1Day{Enxl6qfP+)`Y*wOm(W^D_rr%=i4xg@KqaD5G_ zix()$W+^&-%9~)srQ<#!Wfg}cG?2IT%Ca@0YxU|W{X*>l&G}PqC0WQJ4_fhJZ zXDOUf!zll0(O;*jujM<^SFaXy2>_0RPX#!@zNEEmkbS1VUTal_LJ}rI!SJVWZ*4(o zE+8StR#NJ@7bu)QqX0T+7EYQ>sU^=7WkwZ>PAj3K$Z#PtevDlusJ~7MWfr392&C44 zjktn22wS-r%bsYYaMC1y5`!q?B@Tvo&)_D9HBL?uPh10j@UTmu7|D@iT|5@W{>P~FKw@Hrz}T-<=*o)LNG zZ{4U62AvR$848fYQCF@Er5aYIy1KA4g}CkYMmZyMm?9J>Aj*Z5SLbn}Ahxk_ZyWBD z73JF7$@KP;NT-J-^GdeO9nYdzQ7a6|3f?Kda@L5EMZ3gxImAYUsXlB#~pF(*|Ucfd>DhT56;sTsm0`*VrA-x)cO2Rd?0A3WJJbFyhvQpzRGWcxbN^` zyi^GAb`83|BS)xf*DjFSn_)4uHhe=|QDK4CPDN4F7MdV9fb%$uG)zV=lJ}R>;?u4= zJL$&Gos_wDjnZ{>xMGz9=+*V>)N|kfbt6Ew9niR*VpL#qm0dvA4~mmbO{MAHTr*;N z2Z!N)CSz7t9PooPdLdF}6ppK;5OXgm`cJhJABpMDgTvktUqt+9yZ9NC zo1h(K>GWGxcy`gEc}nRPh$mR(|Lr^paJax6GZsQz(kfaywXN+}`?GkyyZh+)($qGX zePDk?Y#s6zT?BCg?1Hbnmpe$uV*A)o+6=|Me#clEDYjnD<@U2C3FhzlP3c?Zou5Ir z+$)lYg_#^at75)l0n5Mu2P@@}`EcS5SQjb2l_lXT)vc{L55c2tC+9y|8I(m|z-KW~ zN(*thb92F4=weoTKa(9eDAu!x$A0+jQn~Prn*D9pow|VR*OYB&cqlYt8LrcMIApwc zVlcwQ*(U|rjZAzJ1!l+0y?ZYfyABG}sZ2vdcp@^3h0>d0Fwq~#fb;cx@@RZ*u#s5I z57lKY<;qkhz1yePoANj$u{ZdmzP`>ViK5f9um^k9;9yH9xh63L%R$P2XW+@8-=(IN zwTFH?+LI>*sx(wL-pMq=g*8I}#SM&k!Ya`W1GY=j-m*|F=j7ZEr z?Nb+I`YQ6Tk*4=Ro?%(c>mCTZ5M4sZO{sM7)wF&4ZnDjA?T&~&z|lwNzKDCW1qb*b zQW`K{oZ-v(b8gj~ +#import "AMapNavCommonUtil.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ACustomAnnotationView : MAAnnotationView + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomAnnotationView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomAnnotationView.m new file mode 100644 index 0000000..5f81c4b --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ACustomAnnotationView.m @@ -0,0 +1,177 @@ +// +// ACustomAnnotationView.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/17. +// + +#import "ACustomAnnotationView.h" + +// ─── 布局常量 ───────────────────────────────────────────────────────────────── +static const CGFloat kIconSize = 30; // 图标宽高 +static const CGFloat kIconTextGap = 6.0; // 图标与文字间距 +static const CGFloat kMaxTextWidth = 100.0; // 文字区域最大宽度 +static const CGFloat kMaxTextLines = 2; // 最多行数 +static const CGFloat kVPad = 4.0; // 整体上下内边距(用于 centerOffset 微调) + +@interface ACustomAnnotationView () + +@property (nonatomic, strong) UIImageView *iconView; +@property (nonatomic, strong) UILabel *titleLabel; + +/// 当前是否选中(用于更新图标 & 文字样式) +@property (nonatomic, assign) BOOL isAnnotationSelected; + +@end + +@implementation ACustomAnnotationView + +#pragma mark - Init / Reuse + +- (instancetype)initWithAnnotation:(id)annotation + reuseIdentifier:(NSString *)reuseIdentifier { + self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + // 关闭 MAAnnotationView 自带的 image 渲染,避免干扰 + self.image = nil; + [self _buildSubviews]; + [self _updateFromAnnotation]; + [self setNeedsLayout]; + } + return self; +} + +- (void)setAnnotation:(id)annotation { + [super setAnnotation:annotation]; + [self _updateFromAnnotation]; + [self setNeedsLayout]; +} + +#pragma mark - Build + +- (void)_buildSubviews { + // ── 图标 ────────────────────────────────────────────────── + if (!self.iconView) { + UIImageView *iv = [[UIImageView alloc] init]; + iv.contentMode = UIViewContentModeScaleAspectFit; + [self addSubview:iv]; + self.iconView = iv; + } + + // ── 文字 ────────────────────────────────────────────────── + if (!self.titleLabel) { + UILabel *lbl = [[UILabel alloc] init]; + lbl.numberOfLines = kMaxTextLines; + lbl.lineBreakMode = NSLineBreakByTruncatingTail; + lbl.textAlignment = NSTextAlignmentLeft; + [self addSubview:lbl]; + self.titleLabel = lbl; + } + + // 初始化为默认(未选中)样式 + [self _applyStyle:NO]; +} + +/// 根据选中状态切换图标 & 文字样式 +- (void)_applyStyle:(BOOL)selected { + if (selected) { + self.iconView.image = [AMapNavCommonUtil imageWithName3x:@"station_select_icon"]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + self.titleLabel.textColor = [UIColor colorWithWhite:0.12 alpha:1.0]; + } else { + self.iconView.image = [AMapNavCommonUtil imageWithName3x:@"station_normal_icon"]; + self.titleLabel.font = [UIFont systemFontOfSize:13]; + self.titleLabel.textColor = [UIColor colorWithWhite:0.25 alpha:1.0]; + } +} + +#pragma mark - Data + +- (void)_updateFromAnnotation { + NSString *text = nil; + id ann = self.annotation; + if ([ann respondsToSelector:@selector(title)]) { + text = ann.title; + } + if (text.length == 0) { + text = @"加氢站"; + } + self.titleLabel.text = text; +} + +#pragma mark - Selection(MAAnnotationView 官方选中回调) + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + self.isAnnotationSelected = selected; + [self _applyStyle:selected]; + [self setNeedsLayout]; +} + +#pragma mark - Layout + +- (void)layoutSubviews { + [super layoutSubviews]; + + // 文字最大 100pt、最多 2 行 + CGSize textConstraint = CGSizeMake(kMaxTextWidth, + CGFLOAT_MAX); + CGSize textFit = [self.titleLabel sizeThatFits:textConstraint]; + // 高度上限:2 行 + CGFloat lineH = self.titleLabel.font.lineHeight; + CGFloat maxTextH = lineH * kMaxTextLines + + self.titleLabel.font.leading * (kMaxTextLines - 1); + CGFloat textW = MIN(textFit.width, kMaxTextWidth); + CGFloat textH = MIN(textFit.height, maxTextH); + + CGFloat totalW = kIconSize + kIconTextGap + textW; + CGFloat totalH = MAX(kIconSize, textH) + kVPad * 2; + + // 更新自身 bounds + self.bounds = CGRectMake(0, 0, totalW, totalH); + + // 图标:垂直居中 + CGFloat iconY = (totalH - kIconSize) * 0.5; + self.iconView.frame = CGRectMake(0, iconY, kIconSize, kIconSize); + + // 文字:垂直居中 + CGFloat textY = (totalH - textH) * 0.5; + self.titleLabel.frame = CGRectMake(kIconSize + 1, textY, textW, textH); + + // 锚点:让图标底部对齐地图坐标点 + // MAAnnotationView 的 centerOffset 以 (0,0)=中心 为原点 + // 默认选中图标底部对准坐标:向上偏移 totalH/2 + self.centerOffset = CGPointMake(totalW / 2.0 - kIconSize / 2.0, + -(totalH / 2.0)); +} + +#pragma mark - Hit Test + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + UIView *hit = [super hitTest:point withEvent:event]; + if (hit == self || [hit isDescendantOfView:self]) { + return self; + } + return hit; +} + +#pragma mark - Touch + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + + id annotation = self.annotation; + if (!annotation) return; + + UIView *sv = self.superview; + while (sv && ![sv isKindOfClass:[MAMapView class]]) { + sv = sv.superview; + } + MAMapView *mapView = (MAMapView *)sv; + if (!mapView) return; + +// [mapView deselectAnnotation:annotation animated:NO]; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h index e2a6a10..eea9824 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKHeader.h @@ -8,5 +8,44 @@ #ifndef AMapNavSDKHeader_h #define AMapNavSDKHeader_h +//#define kAMapSDKDebugFlag +// iPhone X +#define AMP_iPhoneX (UIApplication.sharedApplication.keyWindow.safeAreaInsets.bottom > 0 ? YES : NO) + +// Status bar height. +#define AMP_StatusBarHeight (AMP_iPhoneX ? 44.f : 20.f) + +// Navigation bar height. +#define AMP_NavigationBarHeight 44.f + +// Tabbar height. +#define AMP_TabbarHeight (AMP_iPhoneX ? (49.f+34.f + 5) : 49.f) + +// Tabbar safe bottom margin. +#define AMP_TabbarSafeBottomMargin (AMP_iPhoneX ? 34.f : 0.f) + + +#pragma mark - url +///获取站点列表 +#define kGetStationListUrl @"https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation" + +///单个站点详情 +#define kGetStationDetailtUrl @"https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea" + + +///获取途经点 +/** + 请求方式:post 暂时调不通 + { +    "longitude":"121.254139", +     "latitude":"31.214628", +     "plateNumber":"浙F32111F", + "hydrogenSiteId":""//加氢站DI } + + */ +#define kGetRoutePointtUrl @"https://beta-esg.api.lnh2e.com/appointment/truck/truckRouteAlgorithm" + + +#import "ANavPointModel.h" #endif /* AMapNavSDKHeader_h */ diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h index 638593a..e2e227b 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapNavSDKManager.h @@ -9,8 +9,6 @@ #import "ARoutePlaneController.h" -#define kAMapSDKDebugFlag - NS_ASSUME_NONNULL_BEGIN @interface AMapNavSDKManager : NSObject diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h index 66d956a..3a34308 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.h @@ -13,6 +13,12 @@ #import +#import "ACustomAnnotationView.h" +#import "AMapNavSDKHeader.h" +#import "ACustomPointAnnotation.h" +#import "ATripCalcResponse.h" +#import "AMapNavCommonUtil.h" + NS_ASSUME_NONNULL_BEGIN @interface ARoutePlaneController : ABaseViewController diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m index 4a09f4a..6c7dc49 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m @@ -18,14 +18,21 @@ #import "AMapPrivacyUtility.h" +#import "AStationDetailPopupController.h" + #define kRouteIndicatorViewHeight 64.f #import "AMapHyStationModel.h" #import "AMapNavHttpUtil.h" +#import "ACustomStepView.h" +#import "ABottomBarView.h" -@interface ARoutePlaneController () +@interface ARoutePlaneController () @property (nonatomic, strong) UITextField *textField; +/// 底部搜索+规划路线栏 +@property (nonatomic, strong) ABottomBarView *bottomBarView; + @property (nonatomic, strong) MAMapView *mapView; @property (nonatomic,strong) AMapLocationManager *locationService; //定位服务 @@ -42,6 +49,7 @@ @property (nonatomic, strong) AMapPOI *startPoi; @property (nonatomic, strong) AMapPOI *dstPoi; +@property (nonatomic, strong) AMapPOI *defaultDstPoi; //默认的附近点 @property (nonatomic, strong) AMapNaviCompositeManager *compositeManager;//nav @property (nonatomic, assign) BOOL calRouteSuccess; @@ -54,6 +62,14 @@ @property (nonatomic , strong)NSArray * hyStationArr;//站点数据 @property (nonatomic , assign)BOOL startQueryCurrnetNodeFlag;//开始查询当前节点; +@property (nonatomic , strong)ACustomStepView * stepView; + +/// 当前弹出的站点详情弹框 +@property (nonatomic , strong)AStationDetailPopupController * stationDetailPopup; +@property (nonatomic, strong) ANavPointModel *pointModel; //当前选的目的点 +@property (nonatomic, strong) ATripCalcDataModel * tjdPathInfoModel;//途经点信息 + +@property (nonatomic, strong) CLLocationManager * locationManager; @end @implementation ARoutePlaneController @@ -89,14 +105,14 @@ #pragma mark - request -(void)requestHyListWithParms:(NSDictionary*)dic { - NSString * url = @"https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation"; + NSString * url = kGetStationListUrl; /** //汽车公园有数据 "longitude": "121.30461400", "latitude": "31.17321100" */ -// NSDictionary * dic = @{@"longitude":@"121.16661700" , @"latitude":@"31.27981600"}; + NSDictionary * dic2 = @{@"longitude":@"121.16661700" , @"latitude":@"31.27981600"}; [AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) { @@ -120,7 +136,7 @@ } -(void)requestHyDetailWithParms:(NSDictionary*)dic { - NSString * url = @"https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea"; + NSString * url = kGetStationDetailtUrl; [AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) { AMapHyResponse * resp = [AMapHyResponse mj_objectWithKeyValues:data]; @@ -135,6 +151,58 @@ } failureHandler:^(NSError * _Nonnull error) { NSLog(@">>>>>>>请求站点err:%@" ,error.debugDescription); }]; + +} + + +-(void)requestRoutePathWithParms:(NSDictionary*)dic completeHandle:(void(^)(ATripCalcDataModel * tjd))blk { + + NSString * token = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.token"]; + NSString * carNo = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.plateNumber"]; + if (stringIsEmpty(token) || stringIsEmpty(carNo)) { + [AMapNavCommonUtil showMsg:@"车牌或token为空,请重新登录"]; return; + } + + if (stringIsEmpty(self.pointModel.stationID)) { + [AMapNavCommonUtil showMsg:@"站点ID不能为空"]; return; + } + + NSMutableDictionary * dic2 = [NSMutableDictionary dictionary]; + dic2[@"longitude"] = [NSString stringWithFormat:@"%f" , self.pointModel.coordinate.longitude]; + dic2[@"latitude"] = [NSString stringWithFormat:@"%f" , self.pointModel.coordinate.latitude]; + dic2[@"plateNumber"] = carNo; + dic2[@"hydrogenSiteId"] = [NSString stringWithFormat:@"%@" , self.pointModel.stationID]; + + NSDictionary * headDic = @{ + @"Content-Type":@"application/json; charset=UTF-8", + @"asoco-token" : token + }; + + + + [AMapNavCommonUtil showLoadingWithMsg:@""]; + + NSString * url = kGetRoutePointtUrl; + [AMapNavHttpUtil postRequestWithURL:url parameters:dic2 requestHeader:headDic successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) { + + ATripCalcResponse * resp = [ATripCalcResponse mj_objectWithKeyValues:data]; + if (resp.code == 200 && resp.data) { + self.tjdPathInfoModel = resp.data; + + if (blk) { + blk(resp.data); + } + }else { + [AMapNavCommonUtil showMsg:data[@"message"]]; + } + + [AMapNavCommonUtil dismiss]; + + } failureHandler:^(NSError * _Nonnull error) { + NSLog(@">>>>>>>请求途经点:%@" ,error.debugDescription); + [AMapNavCommonUtil dismiss]; + [AMapNavCommonUtil showMsg:error.debugDescription]; + }]; } @@ -145,15 +213,15 @@ aoi.location = [AMapGeoPoint locationWithLatitude:[model.latitude doubleValue] longitude:[model.longitude doubleValue]]; aoi.name = model.name; + aoi.address = model.address; + aoi.uid = model.ID; self.dstPoi = aoi; + self.defaultDstPoi = [aoi copy]; ///地址栏 [self updateUIWithData:aoi textField:self.dstTf]; - - ///地图显示 - [self updateMapAnnotationWithData:@[model]]; } -(void)updateMapAnnotationWithData:(NSArray *)dataArr { @@ -165,13 +233,16 @@ ///添加标注 NSMutableArray * points = [NSMutableArray arrayWithCapacity:dataArr.count]; for (AMapHyStationModel * model in dataArr) { - MAPointAnnotation *pointAnnotation = [[MAPointAnnotation alloc] init]; + ACustomPointAnnotation *pointAnnotation = [[ACustomPointAnnotation alloc] init]; if (!(model.latitude && model.longitude)) { continue; } pointAnnotation.coordinate = CLLocationCoordinate2DMake([model.latitude doubleValue], [model.longitude doubleValue]); pointAnnotation.title = model.name; + pointAnnotation.subtitle = model.address; + pointAnnotation.stationID = model.ID; + [points addObject:pointAnnotation]; } @@ -192,95 +263,89 @@ } -#pragma mark - +#pragma mark - init -(void)initSubview { - UITextField * startTf = [[UITextField alloc] init]; - startTf.borderStyle = UITextBorderStyleRoundedRect; - startTf.placeholder = @"起点"; + + // ── 地图全屏 ───────────────────────────────────────────── + [self.mapView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.view); + }]; + + // ── 底部栏(搜索框 + 规划路线按钮) ────────────────────── + ABottomBarView *bottomBar = [[ABottomBarView alloc] init]; + bottomBar.delegate = self; + [self.view addSubview:bottomBar]; + self.bottomBarView = bottomBar; + + [bottomBar mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.view); + make.bottom.equalTo(self.view); + }]; + + // ── 兼容旧逻辑:保留 startTf / dstTf 属性(隐藏,不再显示) ── + // startTf/dstTf 只用作数据载体,不加入视图层级 + UITextField *startTf = [[UITextField alloc] init]; startTf.tag = 100; - startTf.delegate = self; - startTf.font = [UIFont systemFontOfSize:13]; - [self.view addSubview:startTf]; - - [startTf mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.mas_equalTo(self.view).offset(kRoutePlanStatusBarHeight + 35); - make.left.mas_equalTo(self.view).offset(5); - make.width.mas_equalTo(@120); - make.height.mas_equalTo(@32); - }]; - self.startTf = startTf; - - UITextField * dstTf = [[UITextField alloc] init]; - dstTf.borderStyle = UITextBorderStyleRoundedRect; - dstTf.placeholder = @"终点"; + + UITextField *dstTf = [[UITextField alloc] init]; dstTf.tag = 200; - dstTf.delegate = self; - dstTf.font = [UIFont systemFontOfSize:13]; - - [self.view addSubview:dstTf]; - - [dstTf mas_makeConstraints:^(MASConstraintMaker *make) { - make.centerY.mas_equalTo(startTf); - make.left.mas_equalTo(startTf.mas_right).offset(15); -// make.right.mas_equalTo(self.view).offset(-5); - make.width.height.mas_equalTo(startTf); - }]; self.dstTf = dstTf; - - UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; - [btn setTitle:@"规划线路" forState:UIControlStateNormal]; - btn.backgroundColor = [UIColor whiteColor]; - btn.titleLabel.font = [UIFont systemFontOfSize:14]; - - btn.layer.borderColor = [UIColor blueColor].CGColor; - btn.layer.borderWidth = 1; - btn.layer.cornerRadius = 5; - - [btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; - [btn addTarget:self action:@selector(calRoutePath) forControlEvents:UIControlEventTouchUpInside]; - [self.view addSubview:btn]; - [btn mas_makeConstraints:^(MASConstraintMaker *make) { - make.left.equalTo(dstTf.mas_right).offset(12); - make.top.mas_equalTo(startTf); - make.right.mas_equalTo(self.view).offset(-5); - make.height.mas_equalTo(@30); - }]; - - - UIButton * navBtn = [UIButton buttonWithType:UIButtonTypeCustom]; - [navBtn setTitle:@"导航>" forState:UIControlStateNormal]; - navBtn.backgroundColor = [UIColor whiteColor]; - navBtn.titleLabel.font = [UIFont systemFontOfSize:14]; - - navBtn.layer.borderColor = [UIColor blueColor].CGColor; - navBtn.layer.borderWidth = 1; - navBtn.layer.cornerRadius = 6; - - [navBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + + // ── 旧版导航按钮(保留,hidden 状态,供兼容逻辑使用) ───── + UIButton *navBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + navBtn.hidden = YES; [navBtn addTarget:self action:@selector(navAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:navBtn]; [navBtn mas_makeConstraints:^(MASConstraintMaker *make) { -// make.left.equalTo(self.view).offset(12); -// make.centerX.equalTo(self.view); make.right.equalTo(self.view).offset(-15); make.bottom.equalTo(self.view).offset(-118); make.height.mas_equalTo(@30); make.width.mas_equalTo(@60); }]; + + [self.view bringSubviewToFront:bottomBar]; + + // ── 放大缩小控件 ────────────────────────────────────────── + ACustomStepView *stepView = [[ACustomStepView new] initWithValue:self.mapView.zoomLevel maxValue:18.5 min:3.5]; + [self.view addSubview:stepView]; + [stepView mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.view).offset(-15); + make.width.equalTo(@40); + make.height.equalTo(@81); + make.top.equalTo(self.view).offset(100); + }]; + + [stepView addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil]; + self.stepView = stepView; + + ///当前位置按钮 + UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; + [btn setImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal]; + btn.backgroundColor = [UIColor lightGrayColor]; + btn.titleLabel.font = [UIFont systemFontOfSize:14]; + btn.layer.cornerRadius = 20; - [self.mapView mas_makeConstraints:^(MASConstraintMaker *make) { - make.left.right.equalTo(self.view); -// make.top.equalTo(startTf.mas_bottom).offset(5); - make.top.equalTo(self.view).offset(0); -// make.bottom.equalTo(navBtn.mas_top).offset(-3); - make.bottom.equalTo(self.view).offset(0); + [btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside]; + + [self.view addSubview:btn]; + [btn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.view).offset(-10); + make.width.height.equalTo(@40); + make.bottom.equalTo(bottomBar.mas_top).offset(-85); }]; - [self.view bringSubviewToFront:navBtn]; } +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if ([keyPath isEqualToString:@"value"]) { + self.mapView.zoomLevel = [change[NSKeyValueChangeNewKey] doubleValue]; + } + +} + + - (void)initDriveManager { //请在 dealloc 函数中执行 [AMapNaviDriveManager destroyInstance] 来销毁单例 @@ -299,19 +364,9 @@ self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度 _mapView.showsScale= YES; - CGFloat ze = self.mapView.zoomLevel; - self.mapView.zoomLevel = 9; - - // 2. 禁用所有不必要的动画和自动调整 -// self.mapView.autoresizesSubviews = NO; -// [self.mapView setShowsWorldMap:NO]; // 不显示世界地图 - - // 3. 固定缩放级别 -// [self.mapView setMinZoomLevel:6.0]; -// [self.mapView setMaxZoomLevel:20.0]; -// [self.mapView setZoomLevel:10.0 animated:NO]; + _mapView.logoCenter = CGPointMake(CGRectGetWidth(self.view.bounds)-55, 450); + self.mapView.zoomLevel = 11; - // 4. 禁用自动调整 // [self.mapView setAutoCheckMapBoundary:NO]; @@ -325,34 +380,6 @@ } } - ///TEST -// MAPointAnnotation *pointAnnotation = [[MAPointAnnotation alloc] init]; -// pointAnnotation.coordinate = CLLocationCoordinate2DMake(31.19, 121.32); -// pointAnnotation.title = @"嘉兴经开站"; -// [_mapView addAnnotation:pointAnnotation]; -// -// MAPointAnnotation *pointAnnotation2 = [[MAPointAnnotation alloc] init]; -// pointAnnotation2.coordinate = CLLocationCoordinate2DMake(30.81669400, 120.94291800); -// pointAnnotation2.title = @"测试站点1"; -// [_mapView addAnnotation:pointAnnotation2]; - - - - UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; - [btn setImage:[AMapNavCommonUtil imageWithName:@"icon_local"] forState:UIControlStateNormal]; - btn.backgroundColor = [UIColor lightGrayColor]; - btn.titleLabel.font = [UIFont systemFontOfSize:14]; - btn.layer.cornerRadius = 20; - - [btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside]; - - [self.view addSubview:btn]; - [btn mas_makeConstraints:^(MASConstraintMaker *make) { - make.right.equalTo(self.view).offset(-10); - make.width.height.equalTo(@40); - make.top.equalTo(self.view).offset(150); - }]; - } } @@ -394,9 +421,20 @@ if (!_locationService) { _locationService = [[AMapLocationManager alloc] init]; _locationService.delegate = self; - _locationService.desiredAccuracy = kCLLocationAccuracyBest; // 最高精度模式 + _locationService.desiredAccuracy = kCLLocationAccuracyBestForNavigation; // 最高精度模式 _locationService.distanceFilter = 5; _locationService.locatingWithReGeocode = YES; + +// CLLocationManager * mgr; +// // 2. 检查是否为模糊定位(iOS 14+) +// if (@available(iOS 14.0, *)) { +// if (mgr.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) { +// // 弹窗申请临时精确权限(需配置 purposeKey) +// [mgr requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"YourPurposeKey" completion:nil]; +// +// } +// } + } return _locationService; } @@ -405,7 +443,8 @@ - (void)dealloc { [self.locationService stopUpdatingLocation]; - + [self.stepView removeObserver:self forKeyPath:@"value"]; + } - (AMapNaviCompositeManager *)compositeManager { @@ -450,125 +489,123 @@ } } -#pragma mark - Action -///选择方式 --(void)navAction { - [self showSelectNavType]; -} - --(void)showSelectNavType { - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"选择导航类型" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - UIAlertAction *sure = [UIAlertAction actionWithTitle:@"SDK导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [self navigationType_sdk]; - }]; - UIAlertAction *sure2 = [UIAlertAction actionWithTitle:@"高德地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - - [self navigationType_app]; - }]; - - UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { - }]; - - [alert addAction:sure]; - [alert addAction:sure2]; - [alert addAction:cancel]; - - [self presentViewController:alert animated:YES completion:nil]; -} - --(void)navigationType_app { - - NSURL* scheme = [NSURL URLWithString:@"iosamap://"]; - BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:scheme]; - if (!canOpen) { - [self showAlertWithMessage:@"请先安装高德地图客户端"]; return; - } - - NSString *myLocationScheme = [NSString stringWithFormat:@"iosamap://navi?sourceApplication=ANavDemo&lat=31.2304&lon=121.4737&t=0&dev=1"]; - - NSString *encodedUrlString = [myLocationScheme stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; - - NSURL *gaodeUrl = [NSURL URLWithString:encodedUrlString]; - - - [[UIApplication sharedApplication] openURL:gaodeUrl options:@{} completionHandler:^(BOOL res) { - - }]; - -} - --(void)navigationType_sdk { - id delegate = [AMapNaviDriveManager sharedInstance].delegate; - if (!delegate) { - [AMapNaviDriveManager sharedInstance].delegate = self; - } - - - NSDictionary * routes = [AMapNaviDriveManager sharedInstance].naviRoutes; - if (!routes) { - NSLog(@"暂无路线信息!!!!!!!!!"); - self.isStartNav = YES; - [self calRoutePath]; - - return; - } - - - AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init]; - -// [config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeEnd location:[AMapNaviPoint locationWithLatitude:32.21 longitude:121.34] name:@"故宫22" POIId:nil]; - - [config setStartNaviDirectly:YES]; //直接进入导航界面 - [config setNeedCalculateRouteWhenPresent:NO];//不在算路 - [config setMultipleRouteNaviMode:NO];//直接单线路径导航 -// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; - - self.isStartNav = NO; - - [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; - -} - - #pragma mark - 计算线路 ///计算线路 --(void)calRoutePath { -// [self.mapView removeOverlays:self.mapView.overlays]; -// self.startTf.text = @"click calpath"; -// return; - - [self initAnnotations]; - +-(void)calRoutePathWithWayPonts:(NSArray *) naviList { AMapNaviPoint * startPoint = [AMapNaviPoint locationWithLatitude:self.startPoi.location.latitude longitude:self.startPoi.location.longitude]; - AMapNaviPoint * endPoint = [AMapNaviPoint locationWithLatitude:self.dstPoi.location.latitude longitude:self.dstPoi.location.longitude]; + + AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi; + AMapNaviPoint * endPoint = [AMapNaviPoint locationWithLatitude:_dstPoi.location.latitude longitude:_dstPoi.location.longitude]; + + if (!(self.startPoi && _dstPoi)) { + [AMapNavCommonUtil showMsg:@"计算线路,起始点缺失"]; + return; + } AMapNaviDrivingStrategy strategy = ConvertDrivingPreferenceToDrivingStrategy(0, 0, 0, 0, 0); + strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略 id delegate = [AMapNaviDriveManager sharedInstance].delegate; if (!delegate) { [AMapNaviDriveManager sharedInstance].delegate = self; } + NSArray *wayPoints = [self getWayPointWithPoint:naviList]; + + [[AMapNaviDriveManager sharedInstance] setVehicleInfo:[self getCarInfo]]; [[AMapNaviDriveManager sharedInstance] calculateDriveRouteWithStartPoints:@[startPoint] endPoints:@[endPoint] - wayPoints:nil + wayPoints:wayPoints drivingStrategy:strategy]; } - -- (void)driveManagerOnCalculateRouteSuccess:(AMapNaviDriveManager *)driveManager -{ - NSLog(@"onCalculateRouteSuccess"); - //算路成功后显示路径 - [self showNaviRoutes]; +-(NSArray *)getWayPointWithPoint:(NSArray *) naviList { + NSMutableArray *wayPoints = [NSMutableArray array]; + + for (int i = 0; i < naviList.count; i++) { + ANaviPathInfoModel * item = naviList[i]; + + AMapNaviPoint * res = [AMapNaviPoint locationWithLatitude:[item.latitude doubleValue] longitude:[item.longitude doubleValue]]; + [wayPoints addObject:res]; + } + + return wayPoints; } +-(AMapNaviVehicleInfo*)getCarInfo { + AMapNaviVehicleInfo * car = [AMapNaviVehicleInfo new]; + + ATruckModel * truckInfo = self.tjdPathInfoModel.truckDto; + if (!truckInfo) { + return car; + } + + // 车牌号 + if (truckInfo.mcarNumber.length > 0) { + car.vehicleId = truckInfo.mcarNumber; + } + + // 是否躲避限行 + car.isETARestriction = truckInfo.isRestriction; + + // 车辆类型(mcarType 与高德 type 定义一致) + car.type = truckInfo.mcarType; + + // 货车大小分类(mvehicleSize:4 = 重型货车,对应高德 size:4) + car.size = truckInfo.mvehicleSize; + + // 轴数 + car.axisNums = truckInfo.mvehicleAxis; + + // 车身宽度(单位:米) + if (truckInfo.mvehicleWidth.length > 0) { + car.width = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleWidth] floatValue]; + } + + // 车身高度(单位:米) + if (truckInfo.mvehicleHeight.length > 0) { + car.height = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleHeight] floatValue]; + } + + // 车身长度(单位:米) + if (truckInfo.mvehicleLength.length > 0) { + car.length = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleLength] floatValue]; + } + + //总重 + if (truckInfo.mvehicleLoad.length > 0) { + car.load = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleLoad] floatValue]; + } + + // 核定载重 + if (truckInfo.mvehicleWeight.length > 0) { + car.weight = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleWeight] floatValue]; + } + + return car; +} + +///算路成功后回调 +- (void)driveManagerOnCalculateRouteSuccess:(AMapNaviDriveManager *)driveManager +{ + NSDictionary * lines = [AMapNaviDriveManager sharedInstance].naviRoutes ; + NSLog(@"onCalculateRouteSuccess:%@" , lines); + //算路成功后显示路径 + [self gd_navWithCalulatedPath]; +} + +- (void)driveManager:(AMapNaviDriveManager *)driveManager error:(NSError *)error { + ///算路失败,直接去高德规划页面 + [self gd_calPathWithNoStationId:self.pointModel]; +} + +#pragma mark 显示线路[废弃] - (void)showNaviRoutes { if ([[AMapNaviDriveManager sharedInstance].naviRoutes count] <= 0) @@ -600,10 +637,9 @@ coords[i].longitude = [coordinate longitude]; } - MAPolyline *polyline = [MAPolyline polylineWithCoordinates:coords count:count]; - - SelectableOverlay *selectablePolyline = [[SelectableOverlay alloc] initWithOverlay:polyline]; - [selectablePolyline setRouteID:[aRouteID integerValue]]; + // SelectableOverlay 继承 MAPolyline,直接用坐标初始化,避免 renderer overlay 不匹配警告 + SelectableOverlay *selectablePolyline = [SelectableOverlay overlayWithCoordinates:coords count:count]; + selectablePolyline.routeID = [aRouteID integerValue]; [self.mapView addOverlay:selectablePolyline]; free(coords); @@ -623,9 +659,9 @@ [self selectNaviRouteWithID:routeId]; ///如果已开始导航,直接进入导航 - if (self.isStartNav) { - [self navigationType_sdk]; - } +// if (self.isStartNav) { +// [self gd_navWithCalulatedPath]; +// } } @@ -678,6 +714,92 @@ }]; } +#pragma mark - 导航 +///选择方式 +-(void)navAction { + [self gd_navWithCalulatedPath]; //直接导航 +} + +-(void)showSelectNavType { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"选择导航类型" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; + UIAlertAction *sure = [UIAlertAction actionWithTitle:@"SDK导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [self gd_navWithCalulatedPath]; + }]; + UIAlertAction *sure2 = [UIAlertAction actionWithTitle:@"高德地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + + [self navigationType_app]; + }]; + + UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + }]; + + [alert addAction:sure]; + [alert addAction:sure2]; + [alert addAction:cancel]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +-(void)navigationType_app { + + NSURL* scheme = [NSURL URLWithString:@"iosamap://"]; + BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:scheme]; + if (!canOpen) { + [self showAlertWithMessage:@"请先安装高德地图客户端"]; return; + } + + NSString *myLocationScheme = [NSString stringWithFormat:@"iosamap://navi?sourceApplication=ANavDemo&lat=31.2304&lon=121.4737&t=0&dev=1"]; + + NSString *encodedUrlString = [myLocationScheme stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + + NSURL *gaodeUrl = [NSURL URLWithString:encodedUrlString]; + + + [[UIApplication sharedApplication] openURL:gaodeUrl options:@{} completionHandler:^(BOOL res) { + + }]; + +} + +///使用算好的路,直接导航 +-(void)gd_navWithCalulatedPath { + id delegate = [AMapNaviDriveManager sharedInstance].delegate; + if (!delegate) { + [AMapNaviDriveManager sharedInstance].delegate = self; + } + + AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init]; + + [config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeStart location:[AMapNaviPoint locationWithLatitude:self.startPoi.location.latitude longitude:self.startPoi.location.longitude] name:self.startPoi.name POIId:nil]; + + ///车辆信息 + [config setVehicleInfo:[self getCarInfo]]; + + //直接进入导航,不在算路 + [config setStartNaviDirectly:YES]; //直接进入导航界面 + [config setNeedCalculateRouteWhenPresent:NO];//不在算路 + [config setMultipleRouteNaviMode:NO];//直接单线路径导航 +// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; + + [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; +} + +///SDK计算线路 +-(void)gd_calPathWithNoStationId: (ANavPointModel *) dst { + + AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init]; + + [config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeEnd location:[AMapNaviPoint locationWithLatitude:dst.coordinate.latitude longitude:dst.coordinate.longitude] name:dst.name POIId:nil]; + [config setVehicleInfo:[self getCarInfo]]; + +// [config setStartNaviDirectly:YES]; //直接进入导航界面 + [config setNeedCalculateRouteWhenPresent:NO];//不在算路 +// [config setMultipleRouteNaviMode:NO];//直接单线路径导航 +// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO]; + + [self.compositeManager presentRoutePlanViewControllerWithOptions:config]; +} + #pragma mark - AMapLocationManagerDelegate - (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode { @@ -702,6 +824,8 @@ #ifdef kAMapSDKDebugFlag aoi.location = [AMapGeoPoint locationWithLatitude:31.23 longitude:121.48 ]; aoi.name =@"人民大道185号"; + self.latitude = 31.23; + self.longitude = 121.48 ; #else aoi.location = [AMapGeoPoint locationWithLatitude:self.latitude longitude:self.longitude ]; aoi.name = reGeocode.POIName; @@ -735,6 +859,24 @@ - (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id)annotation { + // 当前位置:用 car 图标替换系统默认蓝点 + if ([annotation isKindOfClass:[MAUserLocation class]]) + { + static NSString *userLocationIdentifier = @"UserLocationCarIdentifier"; + MAAnnotationView *userView = [mapView dequeueReusableAnnotationViewWithIdentifier:userLocationIdentifier]; + if (userView == nil) + { + userView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:userLocationIdentifier]; + userView.canShowCallout = NO; + } + else + { + userView.annotation = annotation; + } + userView.image = [AMapNavCommonUtil imageWithName:@"car"]; + return userView; + } + if ([annotation isKindOfClass:[NaviPointAnnotation class]]) { static NSString *annotationIdentifier = @"NaviPointAnnotationIdentifier"; @@ -764,20 +906,25 @@ return pointAnnotationView; } - if ( [annotation isMemberOfClass:[MAPointAnnotation class]]) + // 处理普通点标注(排除用户定位点) + if ([annotation isKindOfClass:[ACustomPointAnnotation class]] && + ![annotation isKindOfClass:[MAUserLocation class]]) { - MAUserLocation *user = (MAUserLocation *)annotation; - static NSString *pointReuseIndentifier = @"pointReuseIndentifier"; - MAPinAnnotationView*annotationView = (MAPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier]; + ACustomAnnotationView *annotationView = (ACustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier]; if (annotationView == nil) { - annotationView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier]; + annotationView = [[ACustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier]; } - annotationView.canShowCallout= YES; //设置气泡可以弹出,默认为NO - annotationView.animatesDrop = NO; //设置标注动画显示,默认为NO - annotationView.draggable = NO; //设置标注可以拖动,默认为NO - annotationView.pinColor = MAPinAnnotationColorPurple; + else + { + // 复用时必须更新 annotation,否则可能不刷新/不显示 + annotationView.annotation = annotation; + } +// annotationView.canShowCallout= YES; //设置气泡可以弹出,默认为NO +// annotationView.animatesDrop = NO; //设置标注动画显示,默认为NO +// annotationView.draggable = NO; //设置标注可以拖动,默认为NO +// annotationView.pinColor = MAPinAnnotationColorPurple; // 设置自定义的气泡背景色 if (@available(iOS 14.0, *)) { @@ -798,12 +945,13 @@ { if ([overlay isKindOfClass:[SelectableOverlay class]]) { - SelectableOverlay * selectableOverlay = (SelectableOverlay *)overlay; - id actualOverlay = selectableOverlay.overlay; + SelectableOverlay *selectableOverlay = (SelectableOverlay *)overlay; - MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:actualOverlay]; + // SelectableOverlay 继承自 MAPolyline,直接用自身初始化 renderer + // renderer.overlay == overlay,避免 MAMapKit 的 overlay 不匹配警告 + MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:selectableOverlay]; - polylineRenderer.lineWidth = 8.f; + polylineRenderer.lineWidth = 8.f; polylineRenderer.strokeColor = selectableOverlay.isSelected ? selectableOverlay.selectedColor : selectableOverlay.regularColor; return polylineRenderer; @@ -818,7 +966,7 @@ # if 0 for (MAAnnotationView *view in views) { // 检查是否为需要的标注类型,例如大头针标注 - if ([view.annotation isMemberOfClass:[MAPointAnnotation class]]) { + if ([view.annotation isMemberOfClass:[ACustomPointAnnotation class]]) { // 延迟零点几秒执行,以确保视图添加动画完成(可选,但可使效果更平滑) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 选中该标注,从而使其气泡弹出 @@ -830,24 +978,45 @@ } - (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view { - NSLog(@"didSelectAnnotationView: %s" , __func__); + + id pointAnnotation = view.annotation; + if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) { + ACustomPointAnnotation *point = (ACustomPointAnnotation *)view.annotation; + + NSLog(@"point: %@" , point.title); + + AMapPOI * aoi = [[AMapPOI alloc] init]; + aoi.location = [AMapGeoPoint locationWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude]; + aoi.name = point.title; + aoi.address = point.subtitle; + aoi.uid = point.stationID; + + self.dstPoi = aoi; + + [self updateUIWithData:aoi textField:self.dstTf]; + + + // 同步更新底部栏目的地文字 + self.bottomBarView.destinationText = aoi.name; + } } - // 当标注被取消选中时调用 - (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view { - if ([view.annotation isMemberOfClass:[MAPointAnnotation class]]) { - // 可以立即或稍作延迟后重新选中 -// [mapView selectAnnotation:view.annotation animated:NO]; + if ([view.annotation isMemberOfClass:[ACustomPointAnnotation class]]) { + // 清空目的地信息 & 底部栏 + self.dstPoi = nil; + self.dstTf.text = nil; + self.bottomBarView.destinationText = nil; } } //选中一个点 - (void)mapView:(MAMapView *)mapView didAnnotationViewCalloutTapped:(MAAnnotationView *)view { id pointAnnotation = view.annotation; - if ([pointAnnotation isMemberOfClass:MAPointAnnotation.class]) { - MAPointAnnotation *point = (MAPointAnnotation *)view.annotation; + if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) { + ACustomPointAnnotation *point = (ACustomPointAnnotation *)view.annotation; NSLog(@"point: %@" , point.title); @@ -880,26 +1049,113 @@ } -#pragma mark - UITextFieldDelegate -- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { +#pragma mark - 弹框 +-(void)willRequestTJDInfo { + ///调用接口获取途经点 + /// + + AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi; + if (!_dstPoi) { + return; + } + + AMapGeoPoint * point = _dstPoi.location; + ANavPointModel *navPoint = [ANavPointModel instanceWithCoordinate:CLLocationCoordinate2DMake(point.latitude, point.longitude) + name:_dstPoi.name + address:_dstPoi.address]; + navPoint.stationID = _dstPoi.uid; + self.pointModel = navPoint; + + ///有_stationID 请求接口;无:不走接口,直接调整高德规划路线; + if (!navPoint.stationID) { + [self gd_calPathWithNoStationId:navPoint]; + return; + }else { + __weak typeof(self) weakSelf = self; + [self requestRoutePathWithParms:nil completeHandle:^(ATripCalcDataModel *tjd) { + [weakSelf showDstInfoPop:navPoint]; + }]; + + } + +} - ASearchAddressController * vc = [[ASearchAddressController alloc] init]; +-(void)showDstInfoPop:(ANavPointModel *) navPoint { - UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:vc]; - //UIModalPresentationOverFullScreen/UIModalPresentationFullScreen触发离开 - nav.modalPresentationStyle = UIModalPresentationOverFullScreen; - nav.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + // --- 弹出站点详情弹框 --- + if (!self.stationDetailPopup) { + AStationDetailPopupController *popup = [[AStationDetailPopupController alloc] init]; + popup.delegate = self; + self.stationDetailPopup = popup; + } + + self.stationDetailPopup.pointModel = navPoint; - __weak typeof(self)weakSelf = self; - vc.selectAddressBlk = ^(AMapPOI * _Nonnull poi) { - [weakSelf updateUIWithData:poi textField:textField]; + ///费用 + self.stationDetailPopup.estimatedCost = self.tjdPathInfoModel.algorithmPath.hydrogenCost; + ///时间 + self.stationDetailPopup.estimatedTime = [NSString stringWithFormat:@"%.f" , self.tjdPathInfoModel.pathDto.duration / 60.0]; + + ///距离 + self.stationDetailPopup.driveDistance = [NSString stringWithFormat:@"%.1f" , self.tjdPathInfoModel.pathDto.distance / 1000.0] ; + ///油费 + self.stationDetailPopup.tollFee = self.tjdPathInfoModel.pathDto.tolls; + + [self.stationDetailPopup presentInViewController:self]; + +} + +#pragma mark - AStationDetailPopupDelegate + +- (void)stationDetailPopupDidTapStartNavi:(AStationDetailPopupController *)popup { + self.stationDetailPopup = nil; + ///点击开始导航: + ///1、有途经点,计算路线,然后再直接导航 + ///2、没有途经点,不用计算路线,直接跳转高德规划页面,然后规划页面中点击导航; + ATripCalcDataModel * tjd = self.tjdPathInfoModel; + if (tjd && tjd.pathDto && tjd.pathDto.naviList) { + NSArray * arr = tjd.pathDto.naviList; + if ([arr isKindOfClass:NSArray.class] && arr.count > 0) { + [self calRoutePathWithWayPonts:arr]; + }else { + [self gd_calPathWithNoStationId:self.pointModel]; + } + + }else { + [self gd_calPathWithNoStationId:self.pointModel]; + } +} + +- (void)stationDetailPopupDidTapClose:(AStationDetailPopupController *)popup { + self.stationDetailPopup = nil; +} + +#pragma mark - ABottomBarViewDelegate + +- (void)bottomBarViewDidTapCalRoute:(ABottomBarView *)barView { + + //详情弹框 + [self willRequestTJDInfo]; + +} + +- (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView { + // 弹出地址搜索页,选中后更新目的地输入框 + ASearchAddressController *vc = [[ASearchAddressController alloc] init]; + UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; + nav.modalPresentationStyle = UIModalPresentationFullScreen; + + __weak typeof(self) weakSelf = self; + vc.selectAddressBlk = ^(AMapPOI *poi) { + __strong typeof(weakSelf) strongSelf = weakSelf; + // 更新底部栏显示文字 + strongSelf.bottomBarView.destinationText = poi.name; + // 同步旧属性(供 calRoutePath 使用) + poi.uid = nil; + [strongSelf updateUIWithData:poi textField:strongSelf.dstTf]; }; - - [self presentViewController:nav animated:YES completion:^{ - - }]; - return NO; + [self presentViewController:nav animated:YES completion:nil]; } -(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf { diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m index eb87923..c0ce3a8 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m @@ -45,7 +45,10 @@ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - [self.inputAddressTf becomeFirstResponder]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.inputAddressTf becomeFirstResponder]; + }); + } -(void)initSubview { diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h new file mode 100644 index 0000000..ce2a216 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.h @@ -0,0 +1,55 @@ +// +// AStationDetailPopupController.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/22. +// + +#import +#import "ANavPointModel.h" +#import "AMapNavSDKHeader.h" + +NS_ASSUME_NONNULL_BEGIN + +@class AStationDetailPopupController; + +@protocol AStationDetailPopupDelegate + +@optional +/// 点击"开始导航" +- (void)stationDetailPopupDidTapStartNavi:(AStationDetailPopupController *)popup; +/// 点击关闭 +- (void)stationDetailPopupDidTapClose:(AStationDetailPopupController *)popup; + +@end + +@interface AStationDetailPopupController : UIViewController + +@property (nonatomic, strong, nullable) ANavPointModel *pointModel; + +/// 预计加氢费用(元),可由外部传入;若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *estimatedCost; + +/// 预计时间,如 @"15分钟";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *estimatedTime; + +/// 行驶里程,如 @"23.5公里";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *driveDistance; + +/// 过路费,如 @"30元";若 nil 则隐藏 +@property (nonatomic, copy, nullable) NSString *tollFee; + +@property (nonatomic, weak, nullable) id delegate; + +/// 以半透明蒙层方式弹出在目标控制器上 +- (void)presentInViewController:(UIViewController *)parentVC; + +/// 关闭弹框 +- (void)dismiss; + +/// 关闭弹框,动画结束后执行 completion(用于关闭后再 present 其他页面) +- (void)dismissWithCompletion:(nullable void(^)(void))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m new file mode 100644 index 0000000..9ba560a --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AStationDetailPopupController.m @@ -0,0 +1,485 @@ +// +// AStationDetailPopupController.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/22. +// + +#import "AStationDetailPopupController.h" +#import "ABaseViewController.h" +#import "AMapNavCommonUtil.h" +#import + +// 主题绿色(开始导航按钮背景) +static inline UIColor *AStationThemeGreen(void) { + return [UIColor colorWithRed:0x1A/255.0 green:0x7C/255.0 blue:0x43/255.0 alpha:1.0]; +} + +@interface AStationDetailPopupController () + +/// 背景蒙层 +@property (nonatomic, strong) UIControl *maskControl; + +/// 弹框卡片容器 +@property (nonatomic, strong) UIView *cardView; + +/// 站点名称 +@property (nonatomic, strong) UILabel *stationNameLabel; + +/// 预计加氢费用(名称右侧) +@property (nonatomic, strong) UIImageView *costIconView; +@property (nonatomic, strong) UILabel *costLabel; + +/// 地址 +@property (nonatomic, strong) UILabel *addressLabel; + +/// 分割线 +@property (nonatomic, strong) UIView *separator; + +/// 预计时间行 +@property (nonatomic, strong) UIImageView *timeIconView; +@property (nonatomic, strong) UILabel *timeLabel; + +/// 行驶里程 +@property (nonatomic, strong) UIImageView *distanceIconView; +@property (nonatomic, strong) UILabel *distanceLabel; + +/// 过路费 +@property (nonatomic, strong) UIImageView *tollIconView; +@property (nonatomic, strong) UILabel *tollLabel; + +/// 关闭按钮 +@property (nonatomic, strong) UIButton *closeButton; + +/// 开始导航按钮 +@property (nonatomic, strong) UIButton *startNaviButton; + +/// 卡片 bottom constraint(动画用) +@property (nonatomic, strong) MASConstraint *cardBottomConstraint; + +@end + +@implementation AStationDetailPopupController + +#pragma mark - Life Cycle + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor clearColor]; + [self _buildUI]; + [self _setupMasonryConstraints]; + [self _updateUI]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [self _playShowAnimation]; +} + +#pragma mark - Public + +- (void)presentInViewController:(UIViewController *)parentVC { + self.modalPresentationStyle = UIModalPresentationOverCurrentContext; + self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + [parentVC presentViewController:self animated:NO completion:nil]; +} + +- (void)dismiss { + [self dismissWithCompletion:nil]; +} + +- (void)dismissWithCompletion:(void(^)(void))completion { + [self _playDismissAnimationWithCompletion:^{ + [self dismissViewControllerAnimated:NO completion:completion]; + }]; +} + +#pragma mark - Setter Override(弹出前赋值 或 弹出后动态更新) + +- (void)setPointModel:(ANavPointModel *)pointModel { + _pointModel = pointModel; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setEstimatedCost:(NSString *)estimatedCost { + _estimatedCost = [estimatedCost copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setEstimatedTime:(NSString *)estimatedTime { + _estimatedTime = [estimatedTime copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setDriveDistance:(NSString *)driveDistance { + _driveDistance = [driveDistance copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +- (void)setTollFee:(NSString *)tollFee { + _tollFee = [tollFee copy]; + if (self.isViewLoaded) [self _updateUI]; +} + +#pragma mark - Build UI + +/** + 卡片结构: + ┌──────────────────────────────────── [✕] ┐ + │ 站点名称(加粗) 预计加氢费用:--元 │ ← 同行,间距20pt + │ 地址(灰色小字,多行) │ + │ ──────────────────────────────────────── │ + │ [icon] 预计时间:-- 分钟 │ + │ [icon] 行驶里程:-- 公里 [icon] 过路费:-- 元 │ + │ ╔════════════════════════════════════╗ │ + │ ║ 开始导航 ║ │ + │ ╚════════════════════════════════════╝ │ + │ (距底部30pt) │ + └─────────────────────────────────────────┘ +*/ +- (void)_buildUI { + // ── 蒙层 ── + UIControl *mask = [[UIControl alloc] init]; + mask.backgroundColor = [UIColor colorWithWhite:0 alpha:0.35]; + [mask addTarget:self action:@selector(_onMaskTapped) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:mask]; + self.maskControl = mask; + + // ── 卡片 ── + UIView *card = [[UIView alloc] init]; + card.backgroundColor = [UIColor whiteColor]; + card.layer.cornerRadius = 16; + card.layer.masksToBounds = NO; + card.layer.shadowColor = [UIColor blackColor].CGColor; + card.layer.shadowOpacity = 0.15; + card.layer.shadowRadius = 12; + card.layer.shadowOffset = CGSizeMake(0, -4); + [self.view addSubview:card]; + self.cardView = card; + + // ── 关闭按钮 ── + UIButton *closeBtn = [UIButton buttonWithType:UIButtonTypeCustom]; +// [closeBtn setTitle:@"✕" forState:UIControlStateNormal]; + [closeBtn setImage: [AMapNavCommonUtil imageWithName:@"icon_close"] forState:UIControlStateNormal]; + + [closeBtn setTitleColor:[UIColor colorWithWhite:0.5 alpha:1] forState:UIControlStateNormal]; + closeBtn.titleLabel.font = [UIFont systemFontOfSize:16]; + [closeBtn addTarget:self action:@selector(_onCloseTapped) forControlEvents:UIControlEventTouchUpInside]; + [card addSubview:closeBtn]; + self.closeButton = closeBtn; + + // ── 站点名称 ── + UILabel *nameLabel = [[UILabel alloc] init]; + nameLabel.font = [UIFont boldSystemFontOfSize:18]; + nameLabel.textColor = [UIColor colorWithWhite:0.1 alpha:1]; + nameLabel.numberOfLines = 2; +// nameLabel.adjustsFontSizeToFitWidth = YES; + nameLabel.minimumScaleFactor = 0.8; + [card addSubview:nameLabel]; + self.stationNameLabel = nameLabel; + + // ── 预计加氢费用(名称右侧,间距20pt) ── + UILabel *costLabel = [[UILabel alloc] init]; + costLabel.font = [UIFont systemFontOfSize:14]; + costLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + costLabel.numberOfLines = 1; + costLabel.textAlignment = NSTextAlignmentLeft; +// [costLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; +// [costLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; + [card addSubview:costLabel]; + self.costLabel = costLabel; + + // ── 地址 ── + UILabel *addrLabel = [[UILabel alloc] init]; + addrLabel.font = [UIFont systemFontOfSize:13]; + addrLabel.textColor = [UIColor colorWithWhite:0.5 alpha:1]; + addrLabel.numberOfLines = 2; + [card addSubview:addrLabel]; + self.addressLabel = addrLabel; + + UIImageView *costIcon = [[UIImageView alloc] init]; + costIcon.contentMode = UIViewContentModeScaleAspectFit; + costIcon.image = [AMapNavCommonUtil imageWithName3x:@"ic_fuel"]; + [card addSubview:costIcon]; + self.costIconView = costIcon; + + // ── 分割线 ── + UIView *sep = [[UIView alloc] init]; + sep.backgroundColor = [UIColor colorWithWhite:0.88 alpha:1]; + [card addSubview:sep]; + self.separator = sep; + + // ── 预计时间图标 ── + UIImageView *timeIcon = [[UIImageView alloc] init]; + timeIcon.contentMode = UIViewContentModeScaleAspectFit; + timeIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_time_icon"]; + [card addSubview:timeIcon]; + self.timeIconView = timeIcon; + + // ── 预计时间文字 ── + UILabel *timeLabel = [[UILabel alloc] init]; + timeLabel.font = [UIFont systemFontOfSize:14]; + timeLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + [card addSubview:timeLabel]; + self.timeLabel = timeLabel; + + // ── 行驶里程图标 ── + UIImageView *distIcon = [[UIImageView alloc] init]; + distIcon.contentMode = UIViewContentModeScaleAspectFit; + distIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_distance_icon"]; + [card addSubview:distIcon]; + self.distanceIconView = distIcon; + + // ── 行驶里程文字 ── + UILabel *distLabel = [[UILabel alloc] init]; + distLabel.font = [UIFont systemFontOfSize:14]; + distLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + [card addSubview:distLabel]; + self.distanceLabel = distLabel; + + // ── 过路费图标 ── + UIImageView *tollIcon = [[UIImageView alloc] init]; + tollIcon.contentMode = UIViewContentModeScaleAspectFit; + tollIcon.image = [AMapNavCommonUtil imageWithName3x:@"pre_cost_icon"]; + [card addSubview:tollIcon]; + self.tollIconView = tollIcon; + + // ── 过路费文字 ── + UILabel *tollLabel = [[UILabel alloc] init]; + tollLabel.font = [UIFont systemFontOfSize:14]; + tollLabel.textColor = [UIColor colorWithWhite:0.2 alpha:1]; + [card addSubview:tollLabel]; + self.tollLabel = tollLabel; + + // ── 开始导航按钮 ── + UIButton *naviBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + [naviBtn setTitle:@"开始导航" forState:UIControlStateNormal]; + [naviBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + naviBtn.titleLabel.font = [UIFont boldSystemFontOfSize:17]; + naviBtn.backgroundColor = AStationThemeGreen(); + naviBtn.layer.cornerRadius = 24; + [naviBtn addTarget:self action:@selector(_onStartNaviTapped) forControlEvents:UIControlEventTouchUpInside]; + [card addSubview:naviBtn]; + self.startNaviButton = naviBtn; +} + +#pragma mark - Masonry Constraints + +- (void)_setupMasonryConstraints { + UIView *card = self.cardView; + CGFloat iconSize = 16; + + // ── 蒙层:铺满父视图 ── + [self.maskControl mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.view); + }]; + + // ── 卡片:左右各16,底部距 safeArea 30pt ── + // 初始状态卡片在屏幕下方(动画起点),top 留空,先用 bottom 约束做弹入 + [card mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.view).offset(16); + make.right.equalTo(self.view).offset(-16); + // 动画起点:卡片顶部 = 父视图底部(完全隐藏在屏幕外) + make.top.equalTo(self.view.mas_bottom).offset(0); + }]; + + // ── 关闭按钮:右上角 ── + [self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(card).offset(8); + make.right.equalTo(card).offset(-15); + make.width.height.mas_equalTo(40); + }]; + + // ── 第一行:站点名称(左,内容自适应)+ 预计加氢费用(紧跟nameLabel右侧20pt) ── + // nameLabel:内容有多宽占多宽,宽度上限55%,防止过长把费用挤掉 + [self.stationNameLabel setContentHuggingPriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [self.stationNameLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(card).offset(25); + make.left.equalTo(card).offset(16); +// make.width.lessThanOrEqualTo(card).multipliedBy(0.45); + make.right.equalTo(self.closeButton.mas_left).offset(-12); + }]; + + // ── 地址(名称下方,6pt间距) ── + [self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.stationNameLabel.mas_bottom).offset(10); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + }]; + + // ── 分割线(地址下方,12pt间距) ── + [self.separator mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.addressLabel.mas_bottom).offset(15); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(0.5); + }]; + + // ── 预计时间行(分割线下方,14pt) ── + [self.timeIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.separator.mas_bottom).offset(15); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.timeIconView); + make.left.equalTo(self.timeIconView.mas_right).offset(6); +// make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(24); + }]; + + ///cost + [self.costIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.timeIconView); + make.left.equalTo(self.timeLabel.mas_right).offset(30); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.costLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.costIconView); + make.left.equalTo(self.costIconView.mas_right).offset(6); + make.right.lessThanOrEqualTo(card).offset(-10); + }]; + + + // ── 行驶里程 + 过路费行(时间行下方,12pt) ── + [self.distanceIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.timeIconView.mas_bottom).offset(15); + make.left.equalTo(card).offset(16); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.distanceLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.distanceIconView.mas_right).offset(6); + // 宽度约为可用区域的一半(另一半留给过路费) + make.width.mas_lessThanOrEqualTo(130); + make.height.mas_equalTo(24); + }]; + + [self.tollIconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.costIconView.mas_left); + make.width.height.mas_equalTo(iconSize); + }]; + + [self.tollLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.distanceIconView); + make.left.equalTo(self.tollIconView.mas_right).offset(6); +// make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(24); + }]; + + // ── 开始导航按钮(里程行下方18pt,距卡片底部30pt) ── + [self.startNaviButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.distanceIconView.mas_bottom).offset(50); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(48); + make.bottom.equalTo(card).offset(-AMP_TabbarSafeBottomMargin); // 卡片底部内间距30pt + }]; +} + +#pragma mark - Data Update + +- (void)_updateUI { + self.stationNameLabel.text = (self.pointModel.name.length > 0) + ? self.pointModel.name : @"--"; + + self.costLabel.text = (self.estimatedCost.length > 0) + ? [NSString stringWithFormat:@"预计加氢费用:%@元", self.estimatedCost] + : @"预计加氢费用:--元"; + + self.addressLabel.text = (self.pointModel.address.length > 0) + ? self.pointModel.address : @"--"; + + // ── 预计时间(始终显示,无值显示"-- 分钟") ── + self.timeLabel.text = (self.estimatedTime.length > 0) + ? [NSString stringWithFormat:@"预计时间:%@分钟", self.estimatedTime] + : @"预计时间:--分钟"; + + // ── 行驶里程(始终显示,无值显示"-- 公里") ── + self.distanceLabel.text = (self.driveDistance.length > 0) + ? [NSString stringWithFormat:@"行驶里程:%@公里", self.driveDistance] + : @"行驶里程:--公里"; + + // ── 过路费(始终显示,无值显示"-- 元") ── + self.tollLabel.text = (self.tollFee.length > 0) + ? [NSString stringWithFormat:@"过路费:%@元", self.tollFee] + : @"过路费:--元"; +} + +#pragma mark - Animation + +/** + 弹入动画:更新 top 约束将卡片滑入至距底部 30pt(含 safeArea) +*/ +- (void)_playShowAnimation { + // 目标状态:卡片底部紧贴 safeArea 底部,再往上留 30pt + [self.cardView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.view).offset(0); + make.right.equalTo(self.view).offset(-0); + make.bottom.equalTo(self.view).offset(0); + }]; + + self.maskControl.alpha = 0; + [UIView animateWithDuration:0.36 + delay:0 + usingSpringWithDamping:0.82 + initialSpringVelocity:0.5 + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + self.maskControl.alpha = 1; + [self.view layoutIfNeeded]; + } completion:nil]; +} + +- (void)_playDismissAnimationWithCompletion:(void(^)(void))completion { + [self.cardView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.view).offset(16); + make.right.equalTo(self.view).offset(-16); + make.top.equalTo(self.view.mas_bottom).offset(20); + }]; + + [UIView animateWithDuration:0.25 + delay:0 + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + self.maskControl.alpha = 0; + [self.view layoutIfNeeded]; + } completion:^(BOOL finished) { + if (completion) completion(); + }]; +} + +#pragma mark - Actions + +- (void)_onMaskTapped { + if ([self.delegate respondsToSelector:@selector(stationDetailPopupDidTapClose:)]) { + [self.delegate stationDetailPopupDidTapClose:self]; + } + [self dismiss]; +} + +- (void)_onCloseTapped { + if ([self.delegate respondsToSelector:@selector(stationDetailPopupDidTapClose:)]) { + [self.delegate stationDetailPopupDidTapClose:self]; + } + [self dismiss]; +} + +- (void)_onStartNaviTapped { + // 先关闭弹框(等动画完全结束),再通知 delegate 弹出导航页 + // 避免两个 presentViewController 同时进行导致导航页面无法显示 + __weak typeof(self) weakSelf = self; + [self dismissWithCompletion:^{ + __strong typeof(weakSelf) strongSelf = weakSelf; + if ([strongSelf.delegate respondsToSelector:@selector(stationDetailPopupDidTapStartNavi:)]) { + [strongSelf.delegate stationDetailPopupDidTapStartNavi:strongSelf]; + } + }]; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.h new file mode 100644 index 0000000..fa7c6e0 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.h @@ -0,0 +1,67 @@ +// +// AAlgorithmPathModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AAlgorithmPathModel : NSObject + +/// 单程 +@property (nonatomic, copy, nullable) NSString *tripRecommendationId; +@property (nonatomic, copy, nullable) NSString *staId; +@property (nonatomic, copy, nullable) NSString *tripOneWayPathId; +@property (nonatomic, copy, nullable) NSString *tripReturnPathId; + +/// 里程(公里) +@property (nonatomic, copy, nullable) NSString *oneWayDis; +@property (nonatomic, copy, nullable) NSString *returnDis; +@property (nonatomic, copy, nullable) NSString *roundTripDis; + +/// 时长(分钟) +@property (nonatomic, copy, nullable) NSString *oneWayTime; +@property (nonatomic, copy, nullable) NSString *returnTime; +@property (nonatomic, copy, nullable) NSString *roundTripTime; + +/// 总成本(元) +@property (nonatomic, copy, nullable) NSString *oneWayCost; +@property (nonatomic, copy, nullable) NSString *returnCost; +@property (nonatomic, copy, nullable) NSString *roundTripCost; + +/// 人工成本(元) +@property (nonatomic, copy, nullable) NSString *oneWayLaborCost; +@property (nonatomic, copy, nullable) NSString *returnLaborCost; +@property (nonatomic, copy, nullable) NSString *roundTripLaborCost; + +/// 高速成本(元) +@property (nonatomic, copy, nullable) NSString *oneWayChargerouteCost; +@property (nonatomic, copy, nullable) NSString *returnChargerouteCost; +@property (nonatomic, copy, nullable) NSString *roundTripChargerouteCost; + +/// 氢耗(公斤) +@property (nonatomic, copy, nullable) NSString *oneWayHydrogenConsumption; +@property (nonatomic, copy, nullable) NSString *returnLaborHydrogenConsumption; +@property (nonatomic, copy, nullable) NSString *roundTripHydrogenConsumption; + +/// 氢气成本(元) +@property (nonatomic, copy, nullable) NSString *oneWayHydrogenCost; +@property (nonatomic, copy, nullable) NSString *returnLaborHydrogenCost; +@property (nonatomic, copy, nullable) NSString *roundTripHydrogenCost; + +/// 加氢站相关 +@property (nonatomic, copy, nullable) NSString *hydrogenCost; // 氢气总成本(元) +@property (nonatomic, copy, nullable) NSString *hydrogenStaServiceTime; // 站服务总时长(分钟) +@property (nonatomic, copy, nullable) NSString *hydrogenStaRefuelingTime;// 实际加油时长(分钟) +@property (nonatomic, copy, nullable) NSString *hydrogenStaQueueTime; // 排队时长(分钟) +@property (nonatomic, copy, nullable) NSString *hydrogenStaServiceTimeCost; // 站服务时间成本(元) +@property (nonatomic, copy, nullable) NSString *hydrogenStaRefuelingTimeCost;// 加油时间成本(元) +@property (nonatomic, copy, nullable) NSString *hydrogenStaQueueTimeCost; // 排队时间成本(元) + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.m new file mode 100644 index 0000000..e328cc7 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AAlgorithmPathModel.m @@ -0,0 +1,12 @@ +// +// AAlgorithmPathModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "AAlgorithmPathModel.h" + +@implementation AAlgorithmPathModel + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.h new file mode 100644 index 0000000..8bd3f82 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.h @@ -0,0 +1,17 @@ +// +// ACustomPointAnnotation.h +// Pods +// +// Created by admin on 2026/3/25. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ACustomPointAnnotation : MAPointAnnotation +@property (nonatomic, copy, nullable) NSString *stationID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.m new file mode 100644 index 0000000..11cae88 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ACustomPointAnnotation.m @@ -0,0 +1,12 @@ +// +// ACustomPointAnnotation.m +// Pods +// +// Created by admin on 2026/3/25. +// + +#import "ACustomPointAnnotation.h" + +@implementation ACustomPointAnnotation + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.h similarity index 95% rename from ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h rename to ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.h index 2c1b0cc..e02ae96 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.h @@ -34,6 +34,8 @@ NS_ASSUME_NONNULL_BEGIN */ @interface AMapHyStationModel : NSObject +@property (nonatomic, copy, nullable) NSString *ID; +@property (nonatomic, copy, nullable) NSString *hydrogenId; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy, nullable) NSString *shortName; @property (nonatomic, copy, nullable) NSString *siteNo; diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.m similarity index 78% rename from ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m rename to ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.m index b6c161f..fcf3f84 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/AMapHyStationModel.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/AMapHyStationModel.m @@ -8,6 +8,10 @@ #import "AMapHyStationModel.h" @implementation AMapHyStationModel ++ (NSDictionary *)mj_replacedKeyFromPropertyName +{ + return @{ @"ID" : @"id"}; +} @end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.h new file mode 100644 index 0000000..d4ae31f --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.h @@ -0,0 +1,26 @@ +// +// ANavPointModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ANavPointModel : NSObject +@property (nonatomic, copy, nullable) NSString *name; +@property (nonatomic, copy, nullable) NSString *address; +@property (nonatomic, copy, nullable) NSString *stationID; + +///经纬度 +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; + +///初始化 ++ (instancetype)instanceWithCoordinate:(CLLocationCoordinate2D)coordinate name:(NSString *)name address:(NSString *)address; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.m new file mode 100644 index 0000000..8a328a1 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANavPointModel.m @@ -0,0 +1,22 @@ +// +// ANavPointModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ANavPointModel.h" + +@implementation ANavPointModel +///初始化 ++ (instancetype)instanceWithCoordinate:(CLLocationCoordinate2D)coordinate name:(NSString *)name address:(NSString *)address { + ANavPointModel *instance = [[ANavPointModel alloc] init]; + if (instance) { + instance.coordinate = coordinate; + instance.name = name; + instance.address = address; + } + return instance; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.h new file mode 100644 index 0000000..56408a9 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.h @@ -0,0 +1,32 @@ +// +// ANaviPathInfoModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + { + "name": "浙江省嘉兴市平湖市乍浦镇滨海大道中国石化滨海大道加油加气站", + "poiId": "", + "coordinate": { + "longitude": "121.070434", + "latitude": "30.596124" + } + } + */ +@interface ANaviPathInfoModel : NSObject + +@property (nonatomic, copy, nullable) NSString *name; +@property (nonatomic, copy, nullable) NSString *poiId; +@property (nonatomic, copy, nullable) NSString *longitude; +@property (nonatomic, copy, nullable) NSString *latitude; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.m new file mode 100644 index 0000000..0138b10 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ANaviPathInfoModel.m @@ -0,0 +1,20 @@ +// +// ANaviPathInfoModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ANaviPathInfoModel.h" + +@implementation ANaviPathInfoModel + ++ (NSDictionary *)mj_replacedKeyFromPropertyName { + // JSON 中 coordinate 是嵌套对象,展开为 longitude/latitude + return @{ + @"longitude": @"coordinate.longitude", + @"latitude": @"coordinate.latitude" + }; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.h new file mode 100644 index 0000000..75ae288 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.h @@ -0,0 +1,29 @@ +// +// APathModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import +#import "ANaviPathInfoModel.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ANaviPathInfoModel; + +@interface APathModel : NSObject + +@property (nonatomic, assign) CGFloat distance; // 总距离(米) +@property (nonatomic, assign) CGFloat duration; // 总时长(秒) +@property (nonatomic, copy, nullable) NSString *strategy; // 路线策略,如"避免拥堵" +@property (nonatomic, copy, nullable) NSString *tolls; // 高速费(元) +@property (nonatomic, assign) CGFloat toll_distance; // 高速里程(米) +@property (nonatomic, assign) NSInteger restriction; // 限行标志,-1 无 +@property (nonatomic, assign) NSInteger traffic_lights; // 红绿灯数量 +@property (nonatomic, strong) NSArray *naviList; // 途经点列表 + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.m new file mode 100644 index 0000000..a9c26ca --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/APathModel.m @@ -0,0 +1,17 @@ +// +// APathModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "APathModel.h" +#import "ANaviPathInfoModel.h" + +@implementation APathModel + ++ (NSDictionary *)mj_objectClassInArray { + return @{@"naviList": [ANaviPathInfoModel class]}; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h new file mode 100644 index 0000000..942ec0f --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.h @@ -0,0 +1,64 @@ +// +// ASiteModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + { + "innerSiteId": "202304241822210001", + "name": "滨海大道加油加气站", + "shortName": "滨海", + "siteNo": "000001", + "city": "浙江省-嘉兴市", + "address": "嘉兴市平湖市滨海大道1515号", + "contact": "陆平", + "phone": "18666666666", + "type": "", + "coOpMode": "签约", + "booking": "无需预约", + "siteStatus": "0", + "siteStatusName": "营运中", + "startBusiness": "08:00:00", + "endBusiness": "20:00:00", + "billingMethod": "月付款", + "term": "1703952000000", + "remark": "", + "longitude": "121.07112700", + "latitude": "30.59577700", + "distance": "" + } + */ +@interface ASiteModel : NSObject + +@property (nonatomic, copy, nullable) NSString *innerSiteId; +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy, nullable) NSString *shortName; +@property (nonatomic, copy, nullable) NSString *siteNo; +@property (nonatomic, copy, nullable) NSString *city; +@property (nonatomic, copy, nullable) NSString *address; +@property (nonatomic, copy, nullable) NSString *contact; +@property (nonatomic, copy, nullable) NSString *phone; +@property (nonatomic, copy, nullable) NSString *type; +@property (nonatomic, copy, nullable) NSString *coOpMode; +@property (nonatomic, copy, nullable) NSString *booking; +@property (nonatomic, copy, nullable) NSString *siteStatus; +@property (nonatomic, copy, nullable) NSString *siteStatusName; +@property (nonatomic, copy, nullable) NSString *startBusiness; +@property (nonatomic, copy, nullable) NSString *endBusiness; +@property (nonatomic, copy, nullable) NSString *billingMethod; +@property (nonatomic, copy, nullable) NSString *term; +@property (nonatomic, copy, nullable) NSString *remark; +@property (nonatomic, copy, nullable) NSString *longitude; +@property (nonatomic, copy, nullable) NSString *latitude; +@property (nonatomic, copy, nullable) NSString *distance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.m new file mode 100644 index 0000000..d805fbf --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ASiteModel.m @@ -0,0 +1,12 @@ +// +// ASiteModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ASiteModel.h" + +@implementation ASiteModel + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.h new file mode 100644 index 0000000..c996fb2 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.h @@ -0,0 +1,65 @@ +// +// ATripCalcResponse.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +#import "AAlgorithmPathModel.h" +#import "APathModel.h" +#import "ASiteModel.h" +#import "ANaviPathInfoModel.h" +#import "ATruckModel.h" + + +NS_ASSUME_NONNULL_BEGIN + +@class ATruckModel; +@class ASiteModel; +@class APathModel; +@class AAlgorithmPathModel; + +#pragma mark - data 节点 + +/** + { + "truckDto": { ... }, + "truckDtoStr": null, + "destinationSite": { ... }, + "pathDto": { ... }, + "algorithmPath": { ... }, + "isInvokeAlgorithm": true + } + */ +@interface ATripCalcDataModel : NSObject + +@property (nonatomic, strong, nullable) ATruckModel *truckDto; +@property (nonatomic, copy, nullable) NSString *truckDtoStr; +@property (nonatomic, strong, nullable) ASiteModel *destinationSite; +@property (nonatomic, strong, nullable) APathModel *pathDto; +@property (nonatomic, strong, nullable) AAlgorithmPathModel *algorithmPath; +@property (nonatomic, assign) BOOL isInvokeAlgorithm; + +@end + +#pragma mark - 根响应 + +/** + { + "code": 200, + "msg": "操作成功!", + "data": { ... } + } + */ +@interface ATripCalcResponse : NSObject + +@property (nonatomic, assign) NSInteger code; +@property (nonatomic, copy, nullable) NSString *msg; +@property (nonatomic, strong, nullable) ATripCalcDataModel *data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.m new file mode 100644 index 0000000..2d0aaf7 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATripCalcResponse.m @@ -0,0 +1,33 @@ +// +// ATripCalcResponse.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ATripCalcResponse.h" +#import "ATruckModel.h" +#import "ASiteModel.h" +#import "APathModel.h" +#import "AAlgorithmPathModel.h" + +@implementation ATripCalcDataModel + ++ (NSDictionary *)mj_objectClassInArray { + return @{ + @"truckDto": [ATruckModel class], + @"destinationSite": [ASiteModel class], + @"pathDto": [APathModel class], + @"algorithmPath": [AAlgorithmPathModel class] + }; +} + +@end + +@implementation ATripCalcResponse + ++ (NSDictionary *)mj_objectClassInArray { + return @{@"data":[ATripCalcDataModel class]}; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.h new file mode 100644 index 0000000..6c2705f --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.h @@ -0,0 +1,58 @@ +// +// ATruckModel.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + { + "isRestriction": true, + "mvehicleSizeName": "重型货车", + "mvehicleAxisUnit": "轴", + "mcarNumber": "浙F32111F", + "mcarType": 0, + "mvehicleHeight": "3.8", + "mvehicleHeightUnit": "M", + "mvehicleWeight": null, + "mvehicleWeightUnit": "T", + "mvehicleLoad": "49.0", + "mvehicleLoadUnit": "T", + "mvehicleLoadSwitch": false, + "mvehicleWidth": "0.0", + "mvehicleWidthUnit": "M", + "mvehicleLength": "7.6", + "mvehicleLengthUnit": "M", + "mvehicleSize": 4, + "mvehicleAxis": 5 + } + */ +@interface ATruckModel : NSObject + +@property (nonatomic, assign) BOOL isRestriction; +@property (nonatomic, copy, nullable) NSString *mvehicleSizeName; +@property (nonatomic, copy, nullable) NSString *mvehicleAxisUnit; +@property (nonatomic, copy, nullable) NSString *mcarNumber; +@property (nonatomic, assign) NSInteger mcarType; +@property (nonatomic, copy, nullable) NSString *mvehicleHeight; +@property (nonatomic, copy, nullable) NSString *mvehicleHeightUnit; +@property (nonatomic, copy, nullable) NSString *mvehicleWeight; +@property (nonatomic, copy, nullable) NSString *mvehicleWeightUnit; +@property (nonatomic, copy, nullable) NSString *mvehicleLoad; +@property (nonatomic, copy, nullable) NSString *mvehicleLoadUnit; +@property (nonatomic, assign) BOOL mvehicleLoadSwitch; +@property (nonatomic, copy, nullable) NSString *mvehicleWidth; +@property (nonatomic, copy, nullable) NSString *mvehicleWidthUnit; +@property (nonatomic, copy, nullable) NSString *mvehicleLength; +@property (nonatomic, copy, nullable) NSString *mvehicleLengthUnit; +@property (nonatomic, assign) NSInteger mvehicleSize; +@property (nonatomic, assign) NSInteger mvehicleAxis; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.m new file mode 100644 index 0000000..be75452 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Model/ATruckModel.m @@ -0,0 +1,12 @@ +// +// ATruckModel.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ATruckModel.h" + +@implementation ATruckModel + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h index fb0e2ca..e1f7894 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.h @@ -6,13 +6,33 @@ // #import +#import NS_ASSUME_NONNULL_BEGIN @interface AMapNavCommonUtil : NSObject -+(UIImage *)imageWithName:(NSString *)name; +/// 显示加载转圈(nil 消息时不显示文字) ++ (void)showLoadingWithMsg:(nullable NSString *)msg; +/// 关闭所有 MBProgressHUD ++ (void)dismiss; + +/// 显示提示,自动 2.0s 后消失 ++ (void)showMsg:(NSString *)msg; + + +/// 获取图片(2x) ++ (UIImage *)imageWithName:(NSString *)name; + +/// 获取图片(3x) ++ (UIImage *)imageWithName3x:(NSString *)name; + +/// 判断字符串是否为空 +BOOL stringIsEmpty(NSString *str); + +/// 判断字符串是否非空 +BOOL stringIsNotEmpty(NSString *str); @end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m index 585f05b..2d34da4 100644 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/AMapNavCommonUtil.m @@ -6,9 +6,117 @@ // #import "AMapNavCommonUtil.h" +#import + +/// 共享 HUD 实例 +static MBProgressHUD *_sharedHUD = nil; @implementation AMapNavCommonUtil +#pragma mark - MBProgressHUD + ++ (UIWindow *)_keyWindow { + if (@available(iOS 13.0, *)) { + for (UIWindowScene *scene in [UIApplication sharedApplication].connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive) { + for (UIWindow *window in scene.windows) { + if (window.isKeyWindow) return window; + } + } + } + } + return [UIApplication sharedApplication].keyWindow; +} + ++ (void)showLoadingWithMsg:(NSString *)msg { + dispatch_async(dispatch_get_main_queue(), ^{ +// [self dismiss]; + + UIWindow *window = [self _keyWindow]; + if (!window) return; + + MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES]; + hud.bezelView.style = MBProgressHUDBackgroundStyleSolidColor; + hud.bezelView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.75]; + hud.contentColor = [UIColor whiteColor]; + + if (msg.length > 0) { + hud.label.text = msg; + hud.label.font = [UIFont systemFontOfSize:14]; + } + + hud.removeFromSuperViewOnHide = YES; + _sharedHUD = hud; + }); +} + ++ (void)dismiss { + dispatch_async(dispatch_get_main_queue(), ^{ + if (_sharedHUD) { + [_sharedHUD hideAnimated:YES]; + _sharedHUD = nil; + } else { + //兜底:隐藏所有 HUD(防止有遗漏) + UIWindow *window = [self _keyWindow]; + if (window) { + [MBProgressHUD hideHUDForView:window animated:YES]; + } + } + }); +} + ++ (void)showMsg:(NSString *)msg { + if (msg.length == 0) return; + + dispatch_async(dispatch_get_main_queue(), ^{ + UIWindow *window = [self _keyWindow]; + if (!window) return; + + MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES]; + hud.mode = MBProgressHUDModeText; + hud.bezelView.style = MBProgressHUDBackgroundStyleSolidColor; + hud.bezelView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.75]; + hud.contentColor = [UIColor whiteColor]; + hud.label.text = msg; + hud.label.font = [UIFont systemFontOfSize:14]; + hud.removeFromSuperViewOnHide = YES; + + // 2.0s 后自动消失 + [hud hideAnimated:YES afterDelay:2.0]; + }); +} + +#pragma mark - 字符串判断 + + +BOOL stringIsEmpty (NSString *str) +{ + if (str == nil || str == NULL) + { + return YES; + } + if ([str isKindOfClass:[NSNull class]]) + { + return YES; + } + if ([str isKindOfClass:[NSString class]]) + { + NSString * newStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSSet *emptySet = [NSSet setWithObjects:@"", @"null", @"(null)", @"", @"NULL", @"无",@"kZero", nil]; + if ([emptySet containsObject:str] || [emptySet containsObject:newStr]) { + return YES; + } else { + return [newStr length] == 0; + } + } + return NO; +} + +BOOL stringIsNotEmpty (NSString *str) +{ + return ! stringIsEmpty(str); +} + #pragma mark - 获取图片 +(UIImage *)imageWithName:(NSString *)name { @@ -22,6 +130,15 @@ return arrowImage; } - ++(UIImage *)imageWithName3x:(NSString *)name { + NSURL * url = [[NSBundle mainBundle] URLForResource:@"AMapNavIOSSDK" withExtension:@"bundle"]; + NSBundle *containnerBundle = [NSBundle bundleWithURL:url]; + + NSString * path = [containnerBundle pathForResource:[NSString stringWithFormat:@"%@@3x.png" , name] ofType:nil]; + + UIImage * arrowImage = [[UIImage imageWithContentsOfFile:path] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + return arrowImage; +} @end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h index 37c4b10..3b631ad 100755 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.h @@ -9,16 +9,16 @@ #import #import -@interface SelectableOverlay : MABaseOverlay +/// 继承 MAPolyline,自身就是 Polyline,renderer 用 self 初始化不会产生 overlay 不匹配警告 +@interface SelectableOverlay : MAPolyline @property (nonatomic, assign) NSInteger routeID; @property (nonatomic, assign, getter = isSelected) BOOL selected; -@property (nonatomic, strong) UIColor * selectedColor; -@property (nonatomic, strong) UIColor * regularColor; +@property (nonatomic, strong) UIColor *selectedColor; +@property (nonatomic, strong) UIColor *regularColor; -@property (nonatomic, strong) id overlay; - -- (id)initWithOverlay:(id) overlay; +/// 用坐标数组和数量初始化(对应原来的 MAPolyline polylineWithCoordinates:count:) ++ (instancetype)overlayWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; @end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m index 9c2aea9..a8d0789 100755 --- a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Tools/SelectableOverlay.m @@ -10,32 +10,14 @@ @implementation SelectableOverlay -#pragma mark - MAOverlay Protocol - -- (CLLocationCoordinate2D)coordinate ++ (instancetype)overlayWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count { - return [self.overlay coordinate]; -} - -- (MAMapRect)boundingMapRect -{ - return [self.overlay boundingMapRect]; -} - -#pragma mark - Life Cycle - -- (id)initWithOverlay:(id)overlay -{ - self = [super init]; - if (self) - { - self.overlay = overlay; - self.selected = NO; - self.selectedColor = [UIColor colorWithRed:0.05 green:0.39 blue:0.9 alpha:0.8]; - self.regularColor = [UIColor colorWithRed:0.5 green:0.6 blue:0.9 alpha:0.8]; - } - - return self; + // MAPolyline 的指定工厂方法,返回 SelectableOverlay 实例 + SelectableOverlay *overlay = (SelectableOverlay *)[super polylineWithCoordinates:coords count:count]; + overlay.selected = NO; + overlay.selectedColor = [UIColor colorWithRed:0.05 green:0.39 blue:0.9 alpha:0.8]; + overlay.regularColor = [UIColor colorWithRed:0.5 green:0.6 blue:0.9 alpha:0.8]; + return overlay; } @end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.h new file mode 100644 index 0000000..dede542 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.h @@ -0,0 +1,32 @@ +// +// ABottomBarView.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import +#import "AMapNavSDKHeader.h" + +NS_ASSUME_NONNULL_BEGIN + +@class ABottomBarView; + +@protocol ABottomBarViewDelegate +/// 点击「规划路线」按钮 +- (void)bottomBarViewDidTapCalRoute:(ABottomBarView *)barView; +/// 输入框开始编辑(外部弹起搜索页) +- (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView; +@end + +/// 底部搜索+规划路线栏 +@interface ABottomBarView : UIView + +@property (nonatomic, weak) id delegate; + +/// 目的地文本(外部赋值后自动更新输入框) +@property (nonatomic, copy, nullable) NSString *destinationText; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m new file mode 100644 index 0000000..047e079 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ABottomBarView.m @@ -0,0 +1,204 @@ +// +// ABottomBarView.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/25. +// + +#import "ABottomBarView.h" +#import "AMapNavCommonUtil.h" +#import + +// 主题绿 +static inline UIColor *ABottomBarThemeGreen(void) { + return [UIColor colorWithRed:0x1A/255.0 green:0x6E/255.0 blue:0x45/255.0 alpha:1.0]; +} + +@interface ABottomBarView () + +/// 白色圆角背景卡片 +@property (nonatomic, strong) UIView *cardView; + +/// 搜索图标 +@property (nonatomic, strong) UIImageView *searchIconView; + +/// 目的地输入框 +@property (nonatomic, strong) UITextField *searchField; + +/// 规划路线按钮 +@property (nonatomic, strong) UIButton *calRouteButton; + +@end + +@implementation ABottomBarView + +#pragma mark - Init + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + [self _buildUI]; + } + return self; +} + +- (instancetype)init { + return [self initWithFrame:CGRectZero]; +} + +#pragma mark - Build UI + +- (void)_buildUI { + // ── 背景卡片 ────────────────────────────────────────── + UIView *card = [[UIView alloc] init]; +// card.backgroundColor = [UIColor colorWithRed:0.96 green:0.97 blue:0.98 alpha:0.96]; + card.backgroundColor = [UIColor whiteColor]; + card.layer.cornerRadius = 16; + // 顶部阴影 + card.layer.shadowColor = [UIColor blackColor].CGColor; + card.layer.shadowOpacity = 0.10; + card.layer.shadowRadius = 10; + card.layer.shadowOffset = CGSizeMake(0, -3); + card.layer.masksToBounds = NO; + [self addSubview:card]; + self.cardView = card; + + [card mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + // ── 搜索框容器(白色圆角行) ────────────────────────── + UIView *searchRow = [[UIView alloc] init]; + searchRow.backgroundColor = [UIColor whiteColor]; + searchRow.layer.cornerRadius = 5; + searchRow.layer.masksToBounds = YES; + searchRow.layer.borderColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1].CGColor; + searchRow.layer.borderWidth = 1; + [card addSubview:searchRow]; + + [searchRow mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(card).offset(-18); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(50); + }]; + + // ── 搜索图标 ────────────────────────────────────────── + UIImageView *searchIcon = [[UIImageView alloc] init]; + searchIcon.contentMode = UIViewContentModeScaleAspectFit; + searchIcon.image = [AMapNavCommonUtil imageWithName3x:@"search_icon"]; + [searchRow addSubview:searchIcon]; + self.searchIconView = searchIcon; + + [searchIcon mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(searchRow); + make.left.equalTo(searchRow).offset(12); + make.width.height.mas_equalTo(18); + }]; + + // ── 目的地输入框 ────────────────────────────────────── + UITextField *field = [[UITextField alloc] init]; + field.placeholder = @"请输入目的地,不输入则自动匹配附近成本最低加氢站"; + field.font = [UIFont systemFontOfSize:14]; + field.textColor = [UIColor colorWithWhite:0.1 alpha:1]; + field.borderStyle = UITextBorderStyleNone; + field.backgroundColor = [UIColor clearColor]; + field.delegate = self; + // placeholder 颜色 + if (field.placeholder) { + field.attributedPlaceholder = [[NSAttributedString alloc] + initWithString:field.placeholder + attributes:@{NSForegroundColorAttributeName: + [UIColor colorWithWhite:0.65 alpha:1], + NSFontAttributeName: + [UIFont systemFontOfSize:13]}]; + } + [searchRow addSubview:field]; + self.searchField = field; + + [field mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(searchRow); + make.left.equalTo(searchIcon.mas_right).offset(8); + make.right.equalTo(searchRow).offset(-12); + make.top.bottom.equalTo(searchRow); + }]; + + // ── 规划路线按钮 ────────────────────────────────────── + UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; + btn.backgroundColor = ABottomBarThemeGreen(); + btn.layer.cornerRadius = 24; + btn.layer.masksToBounds = YES; + + // 左侧图标 + UIImageView *routeIcon = [[UIImageView alloc] init]; + routeIcon.contentMode = UIViewContentModeScaleAspectFit; + routeIcon.image = [AMapNavCommonUtil imageWithName3x:@"cal_ruoute_icon"]; + routeIcon.userInteractionEnabled = NO; + [btn addSubview:routeIcon]; + + // 标题 + UILabel *titleLbl = [[UILabel alloc] init]; + titleLbl.text = @"规划路线"; + titleLbl.textColor = [UIColor whiteColor]; + titleLbl.font = [UIFont boldSystemFontOfSize:16]; + titleLbl.userInteractionEnabled = NO; + [btn addSubview:titleLbl]; + + // 图标和文字水平居中整体 + [routeIcon mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(btn); + make.right.equalTo(titleLbl.mas_left).offset(-8); + make.width.height.mas_equalTo(22); + }]; + + [titleLbl mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(btn); + // 两者整体水平居中:titleLbl 向右偏移 (22+8)/2 = 15pt + make.centerX.equalTo(btn).offset(15); + }]; + + [btn addTarget:self action:@selector(_onCalRouteTapped) forControlEvents:UIControlEventTouchUpInside]; + [card addSubview:btn]; + self.calRouteButton = btn; + + CGFloat off_y = AMP_TabbarHeight; +#ifdef kAMapSDKDebugFlag + off_y = 0; +#endif + + [btn mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(searchRow.mas_bottom).offset(20); + make.left.equalTo(card).offset(16); + make.right.equalTo(card).offset(-16); + make.height.mas_equalTo(48); + make.bottom.equalTo(card).offset(-40 - off_y); + }]; +} + +#pragma mark - Public + +- (void)setDestinationText:(NSString *)destinationText { + _destinationText = destinationText; + self.searchField.text = destinationText; +} + +#pragma mark - Actions + +- (void)_onCalRouteTapped { + if ([self.delegate respondsToSelector:@selector(bottomBarViewDidTapCalRoute:)]) { + [self.delegate bottomBarViewDidTapCalRoute:self]; + } +} + +#pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + // 不弹起键盘,直接通知外部展示搜索页 + if ([self.delegate respondsToSelector:@selector(bottomBarViewDidTapSearchField:)]) { + [self.delegate bottomBarViewDidTapSearchField:self]; + } + return NO; +} + +@end diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.h b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.h new file mode 100644 index 0000000..b1d3a8d --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.h @@ -0,0 +1,21 @@ +// +// ACustomStepView.h +// AMapNavIOSSDK +// +// Created by admin on 2026/3/11. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ACustomStepView : UIView + +@property (nonatomic, readonly , assign) CGFloat value; // 当前值 + + +- (instancetype)initWithValue:(CGFloat)currentValue maxValue:(CGFloat)maxValue min:(CGFloat)minValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.m b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.m new file mode 100644 index 0000000..0625ec6 --- /dev/null +++ b/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/ACustomStepView.m @@ -0,0 +1,121 @@ +// +// ACustomStepView.m +// AMapNavIOSSDK +// +// Created by admin on 2026/3/11. +// + +#import "ACustomStepView.h" +#import + +#define kStepValue 0.5 + +@interface ACustomStepView () +@property CGFloat value; +@property CGFloat maxValue; +@property CGFloat minValue; +@end + +@implementation ACustomStepView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor whiteColor]; + self.layer.cornerRadius = 4; + self.layer.masksToBounds = YES; + self.clipsToBounds = YES; + self.layer.borderColor = [UIColor colorWithRed:225/255.0 green:225/255.0 blue:225/255.0 alpha:1].CGColor; + self.layer.borderWidth = 1; + + [self setupSubviews]; + + self.value = 0; // 初始值 + } + return self; +} + +- (instancetype)initWithValue:(CGFloat)currentValue maxValue:(CGFloat)maxValue min:(CGFloat)minValue { +// self = [super initWithFrame:CGRectZero]; + + if (self) { + _value = currentValue; + _maxValue = maxValue; + _minValue = minValue; + } + + + return self; +} + +- (void)setupSubviews { + // 减按钮 + UIButton *minusButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [minusButton setTitle:@"-" forState:UIControlStateNormal]; + minusButton.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [minusButton addTarget:self action:@selector(decrement:) forControlEvents:UIControlEventTouchUpInside]; + [minusButton setTintColor:[UIColor colorWithRed:0x35/255.0 green:0x35/255.0 blue:0x35/255.0 alpha:1]]; + [self addSubview:minusButton]; + + // 加按钮 + UIButton *plusButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [plusButton setTitle:@"+" forState:UIControlStateNormal]; + plusButton.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [plusButton setTintColor:[UIColor colorWithRed:0x35/255.0 green:0x35/255.0 blue:0x35/255.0 alpha:1]]; + + [plusButton addTarget:self action:@selector(increment:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:plusButton]; + + [plusButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(self); + make.height.equalTo(@40); + }]; + + UIView * line = [[UIView alloc] init]; + line.backgroundColor = [UIColor colorWithRed:230/255.0 green:230/255.0 blue:230/255.0 alpha:1]; + [self addSubview:line]; + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.top.equalTo(plusButton.mas_bottom); + make.height.equalTo(@1); + }]; + + + [minusButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.top.equalTo(plusButton.mas_bottom); + make.height.equalTo(plusButton); + }]; + + +} + +// 减1操作 +- (void)decrement:(UIButton *)sender { + if (self.value <= self.minValue) { + return; + } + if (self.value - kStepValue < self.minValue) { + self.value = self.minValue; + return; + } + + self.value = self.value - kStepValue; +} + +// 加1操作 +- (void)increment:(UIButton *)sender { + if (self.value >= self.maxValue) { + return; + } + if (self.value + kStepValue > self.maxValue) { + self.value = self.maxValue; + return; + } + + self.value = self.value + kStepValue; + +} + + +@end diff --git a/ln_jq_app/ios/Podfile b/ln_jq_app/ios/Podfile index 42199c1..3cfdd14 100644 --- a/ln_jq_app/ios/Podfile +++ b/ln_jq_app/ios/Podfile @@ -35,6 +35,8 @@ target 'Runner' do use_frameworks! :linkage => :static pod 'AMapNavIOSSDK' , :path => './AMapNavIOSSDK' + ## 本地仓库 +# pod 'AMapNavIOSSDK' , :path => '../../../../demo/ANavDemo' flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index f26e170..26bdefa 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -17,6 +17,7 @@ PODS: - AMapNavi-NO-IDFA - AMapSearch-NO-IDFA - Masonry + - MBProgressHUD - MJExtension - AMapSearch-NO-IDFA (9.7.4): - AMapFoundation-NO-IDFA (>= 1.8.0) @@ -42,6 +43,7 @@ PODS: - image_picker_ios (0.0.1): - Flutter - Masonry (1.1.0) + - MBProgressHUD (1.2.0) - MJExtension (3.4.2) - mobile_scanner (7.0.0): - Flutter @@ -49,9 +51,6 @@ PODS: - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - shared_preferences_foundation (0.0.1): @@ -73,7 +72,6 @@ DEPENDENCIES: - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -90,6 +88,7 @@ SPEC REPOS: - AMapNavi-NO-IDFA - AMapSearch-NO-IDFA - Masonry + - MBProgressHUD - MJExtension - OrderedSet @@ -118,8 +117,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/mobile_scanner/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" shared_preferences_foundation: @@ -131,30 +128,30 @@ SPEC CHECKSUMS: AlicloudELS: fbf821383330465a5af84a033f36f263ae46ca41 AlicloudPush: 52cbf38ffc20c07f039cbc72d5738745fd986215 AlicloudUTDID: 5d2f22d50e11eecd38f30bc7a48c71925ea90976 - aliyun_push_flutter: 0fc2f048a08687ef256c0cfdd72dd7a550ef3347 + aliyun_push_flutter: ab0bf7112ef3797f506770a7a9f47f004635a9f6 AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05 AMapLocation-NO-IDFA: 590fd42af0c8ea9eac26978348221bbc16be4ef9 AMapNavi-NO-IDFA: 22edfa7d6a81d75c91756e31b6c26b7746152233 - AMapNavIOSSDK: ca325c9ac3378daea6a6be4bd8c34fe48d3ac896 + AMapNavIOSSDK: 092382d55290f43b282ffcc522c274996794e2bc AMapSearch-NO-IDFA: 53b2193244be8f07f3be0a4d5161200236960587 - connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd - device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 + connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d + device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 - flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf - flutter_pdfview: 32bf27bda6fd85b9dd2c09628a824df5081246cf - geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e - image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29 + flutter_pdfview: 2e4d13ffb774858562ffbdfdb61b40744b191adc + geolocator_apple: 66b711889fd333205763b83c9dcf0a57a28c7afd + image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 + MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406 MJExtension: e97d164cb411aa9795cf576093a1fa208b4a8dd8 - mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 + mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 - permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 + url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa -PODFILE CHECKSUM: 97188da9dab9d4b3372eb4c16e872fbd555fdbea +PODFILE CHECKSUM: b4931d4490f04261e0fda802d44e275ab3619244 COCOAPODS: 1.16.2 diff --git a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj index 27a8385..6ed39fa 100644 --- a/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj +++ b/ln_jq_app/ios/Runner.xcodeproj/project.pbxproj @@ -357,14 +357,10 @@ 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", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; diff --git a/ln_jq_app/lib/common/token_interceptor.dart b/ln_jq_app/lib/common/token_interceptor.dart index dbb5562..70414f7 100644 --- a/ln_jq_app/lib/common/token_interceptor.dart +++ b/ln_jq_app/lib/common/token_interceptor.dart @@ -24,6 +24,7 @@ class TokenInterceptor extends Interceptor { if (!options.headers.containsKey(tokenKey)) { // 使用我们自定义的 key 添加 token options.headers[tokenKey] = token; + print("head.token: $token"); } } diff --git a/ln_jq_app/pubspec.lock b/ln_jq_app/pubspec.lock index 33eec3f..53e8a81 100644 --- a/ln_jq_app/pubspec.lock +++ b/ln_jq_app/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: aliyun_push_flutter sha256: fd1a13ab37f30274e1eaa9c0f68001bf268f8f2e1c83730b4520aa4dff46ce70 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.6" ansicolor: @@ -14,7 +14,7 @@ packages: description: name: ansicolor sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.3" archive: @@ -22,7 +22,7 @@ packages: description: name: archive sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.9" args: @@ -30,7 +30,7 @@ packages: description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" asn1lib: @@ -38,23 +38,23 @@ packages: description: name: asn1lib sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.6.5" async: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.flutter-io.cn" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.13.1" badges: dependency: transitive description: name: badges sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.2" boolean_selector: @@ -62,7 +62,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" characters: @@ -70,7 +70,7 @@ packages: description: name: characters sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.0" clock: @@ -78,15 +78,23 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" collection: dependency: transitive description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.19.1" connectivity_plus: @@ -94,7 +102,7 @@ packages: description: name: connectivity_plus sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5" connectivity_plus_platform_interface: @@ -102,7 +110,7 @@ packages: description: name: connectivity_plus_platform_interface sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.1" convert: @@ -110,7 +118,7 @@ packages: description: name: convert sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.2" cross_file: @@ -118,7 +126,7 @@ packages: description: name: cross_file sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.3.5+2" crypto: @@ -126,7 +134,7 @@ packages: description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.7" csslib: @@ -134,23 +142,23 @@ packages: description: name: csslib sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.flutter-io.cn" + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" + url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" dbus: dependency: transitive description: name: dbus sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.12" decimal: @@ -158,7 +166,7 @@ packages: description: name: decimal sha256: fc706a5618b81e5b367b01dd62621def37abc096f2b46a9bd9068b64c1fa36d0 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.4" device_info_plus: @@ -166,7 +174,7 @@ packages: description: name: device_info_plus sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "10.1.2" device_info_plus_platform_interface: @@ -174,7 +182,7 @@ packages: description: name: device_info_plus_platform_interface sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.3" dio: @@ -182,7 +190,7 @@ packages: description: name: dio sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.9.2" dio_web_adapter: @@ -190,7 +198,7 @@ packages: description: name: dio_web_adapter sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" dropdown_button2: @@ -198,7 +206,7 @@ packages: description: name: dropdown_button2 sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.9" encrypt: @@ -206,7 +214,7 @@ packages: description: name: encrypt sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.3" event_bus: @@ -214,7 +222,7 @@ packages: description: name: event_bus sha256: "1a55e97923769c286d295240048fc180e7b0768902c3c2e869fe059aafa15304" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.1" extended_image: @@ -222,7 +230,7 @@ packages: description: name: extended_image sha256: "69d4299043334ecece679996e47d0b0891cd8c29d8da0034868443506f1d9a78" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.1" extended_image_library: @@ -230,7 +238,7 @@ packages: description: name: extended_image_library sha256: e61dafd94400fff6ef7ed1523d445ff3af137f198f3228e4a3107bc5b4bec5d1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.6" fake_async: @@ -238,7 +246,7 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.3" ffi: @@ -246,7 +254,7 @@ packages: description: name: ffi sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" file: @@ -254,7 +262,7 @@ packages: description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.1" file_selector_linux: @@ -262,7 +270,7 @@ packages: description: name: file_selector_linux sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.4" file_selector_macos: @@ -270,7 +278,7 @@ packages: description: name: file_selector_macos sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.5" file_selector_platform_interface: @@ -278,7 +286,7 @@ packages: description: name: file_selector_platform_interface sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" file_selector_windows: @@ -286,7 +294,7 @@ packages: description: name: file_selector_windows sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.3+5" fixnum: @@ -294,7 +302,7 @@ packages: description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" flutter: @@ -307,7 +315,7 @@ packages: description: name: flutter_easyloading sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.5" flutter_inappwebview: @@ -315,7 +323,7 @@ packages: description: name: flutter_inappwebview sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5" flutter_inappwebview_android: @@ -323,7 +331,7 @@ packages: description: name: flutter_inappwebview_android sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.3" flutter_inappwebview_internal_annotations: @@ -331,7 +339,7 @@ packages: description: name: flutter_inappwebview_internal_annotations sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0" flutter_inappwebview_ios: @@ -339,7 +347,7 @@ packages: description: name: flutter_inappwebview_ios sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_macos: @@ -347,7 +355,7 @@ packages: description: name: flutter_inappwebview_macos sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_platform_interface: @@ -355,7 +363,7 @@ packages: description: name: flutter_inappwebview_platform_interface sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0+1" flutter_inappwebview_web: @@ -363,7 +371,7 @@ packages: description: name: flutter_inappwebview_web sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_windows: @@ -371,7 +379,7 @@ packages: description: name: flutter_inappwebview_windows sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.6.0" flutter_lints: @@ -379,7 +387,7 @@ packages: description: name: flutter_lints sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.0" flutter_localizations: @@ -392,7 +400,7 @@ packages: description: name: flutter_native_splash sha256: "4fb9f4113350d3a80841ce05ebf1976a36de622af7d19aca0ca9a9911c7ff002" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.7" flutter_pdfview: @@ -400,23 +408,23 @@ packages: description: name: flutter_pdfview sha256: c0b2cc4ebf461a5a4bb9312a165222475a7d93845c7a0703f4abb7f442eb6d54 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.3" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 - url: "https://pub.flutter-io.cn" + sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" + url: "https://pub.dev" source: hosted - version: "2.0.33" + version: "2.0.34" flutter_screenutil: dependency: transitive description: name: flutter_screenutil sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.9.3" flutter_spinkit: @@ -424,7 +432,7 @@ packages: description: name: flutter_spinkit sha256: "77850df57c00dc218bfe96071d576a8babec24cf58b2ed121c83cca4a2fdce7f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.2.2" flutter_svg: @@ -432,7 +440,7 @@ packages: description: name: flutter_svg sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.4" flutter_test: @@ -450,7 +458,7 @@ packages: description: name: geoclue sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.1.1" geolocator: @@ -458,7 +466,7 @@ packages: description: name: geolocator sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "14.0.2" geolocator_android: @@ -466,7 +474,7 @@ packages: description: name: geolocator_android sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.2" geolocator_apple: @@ -474,7 +482,7 @@ packages: description: name: geolocator_apple sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.13" geolocator_linux: @@ -482,7 +490,7 @@ packages: description: name: geolocator_linux sha256: c4e966f0a7a87e70049eac7a2617f9e16fd4c585a26e4330bdfc3a71e6a721f3 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.3" geolocator_platform_interface: @@ -490,7 +498,7 @@ packages: description: name: geolocator_platform_interface sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.2.6" geolocator_web: @@ -498,7 +506,7 @@ packages: description: name: geolocator_web sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.1.3" geolocator_windows: @@ -506,7 +514,7 @@ packages: description: name: geolocator_windows sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.5" get: @@ -514,7 +522,7 @@ packages: description: name: get sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.7.3" get_storage: @@ -522,7 +530,7 @@ packages: description: name: get_storage sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.1" getx_scaffold: @@ -530,23 +538,39 @@ packages: description: name: getx_scaffold sha256: caf11b370c20840352230f50221bcef1454b30ec56cce10ba25741fbbdf0a806 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" gsettings: dependency: transitive description: name: gsettings sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.8" + hooks: + dependency: transitive + description: + name: hooks + sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + url: "https://pub.dev" + source: hosted + version: "1.0.2" html: dependency: transitive description: name: html sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.15.6" http: @@ -554,7 +578,7 @@ packages: description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.6.0" http_client_helper: @@ -562,7 +586,7 @@ packages: description: name: http_client_helper sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.0" http_parser: @@ -570,7 +594,7 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.1.2" image: @@ -578,7 +602,7 @@ packages: description: name: image sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.8.0" image_picker: @@ -586,39 +610,39 @@ packages: description: name: image_picker sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156 - url: "https://pub.flutter-io.cn" + sha256: "9eae0cbd672549dacc18df855c2a23782afe4854ada5190b7d63b30ee0b0d3fd" + url: "https://pub.dev" source: hosted - version: "0.8.13+14" + version: "0.8.13+15" image_picker_for_web: dependency: transitive description: name: image_picker_for_web sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.1" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" - url: "https://pub.flutter-io.cn" + sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + url: "https://pub.dev" source: hosted - version: "0.8.13+3" + version: "0.8.13+6" image_picker_linux: dependency: transitive description: name: image_picker_linux sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" image_picker_macos: @@ -626,7 +650,7 @@ packages: description: name: image_picker_macos sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2+1" image_picker_platform_interface: @@ -634,7 +658,7 @@ packages: description: name: image_picker_platform_interface sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.11.1" image_picker_windows: @@ -642,7 +666,7 @@ packages: description: name: image_picker_windows sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" intl: @@ -650,7 +674,7 @@ packages: description: name: intl sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.19.0" js: @@ -658,7 +682,7 @@ packages: description: name: js sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.2" leak_tracker: @@ -666,7 +690,7 @@ packages: description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -674,7 +698,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.10" leak_tracker_testing: @@ -682,7 +706,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.2" lints: @@ -690,15 +714,23 @@ packages: description: name: lints sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" lottie: dependency: transitive description: name: lottie sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.3.2" matcher: @@ -706,7 +738,7 @@ packages: description: name: matcher sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.12.17" material_color_utilities: @@ -714,23 +746,23 @@ packages: description: name: material_color_utilities sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.flutter-io.cn" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.0" mobile_scanner: @@ -738,7 +770,7 @@ packages: description: name: mobile_scanner sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.2.0" modal_bottom_sheet: @@ -746,23 +778,39 @@ packages: description: name: modal_bottom_sheet sha256: eac66ef8cb0461bf069a38c5eb0fa728cee525a531a8304bd3f7b2185407c67e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + url: "https://pub.dev" + source: hosted + version: "0.17.6" nm: dependency: transitive description: name: nm sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.5.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" package_info_plus: dependency: transitive description: name: package_info_plus sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.1" package_info_plus_platform_interface: @@ -770,7 +818,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.1" path: @@ -778,7 +826,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.9.1" path_parsing: @@ -786,7 +834,7 @@ packages: description: name: path_parsing sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.0" path_provider: @@ -794,31 +842,31 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.flutter-io.cn" + sha256: "149441ca6e4f38193b2e004c0ca6376a3d11f51fa5a77552d8bd4d2b0c0912ba" + url: "https://pub.dev" source: hosted - version: "2.2.22" + version: "2.2.23" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" - url: "https://pub.flutter-io.cn" + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.0" path_provider_linux: dependency: transitive description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -826,7 +874,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" path_provider_windows: @@ -834,7 +882,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.0" permission_handler: @@ -842,7 +890,7 @@ packages: description: name: permission_handler sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.4.0" permission_handler_android: @@ -850,7 +898,7 @@ packages: description: name: permission_handler_android sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "12.1.0" permission_handler_apple: @@ -858,7 +906,7 @@ packages: description: name: permission_handler_apple sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "9.4.7" permission_handler_html: @@ -866,7 +914,7 @@ packages: description: name: permission_handler_html sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.1.3+5" permission_handler_platform_interface: @@ -874,7 +922,7 @@ packages: description: name: permission_handler_platform_interface sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.3.0" permission_handler_windows: @@ -882,7 +930,7 @@ packages: description: name: permission_handler_windows sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.1" petitparser: @@ -890,7 +938,7 @@ packages: description: name: petitparser sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.2" photo_view: @@ -898,7 +946,7 @@ packages: description: name: photo_view sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.15.0" platform: @@ -906,7 +954,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.6" plugin_platform_interface: @@ -914,7 +962,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.8" pointycastle: @@ -922,7 +970,7 @@ packages: description: name: pointycastle sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.9.1" posix: @@ -930,15 +978,23 @@ packages: description: name: posix sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" pull_to_refresh: dependency: "direct main" description: name: pull_to_refresh sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.0" rational: @@ -946,31 +1002,31 @@ packages: description: name: rational sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.3" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.flutter-io.cn" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41" - url: "https://pub.flutter-io.cn" + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + url: "https://pub.dev" source: hosted - version: "2.4.21" + version: "2.4.23" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.6" shared_preferences_linux: @@ -978,23 +1034,23 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.flutter-io.cn" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.3" shared_preferences_windows: @@ -1002,7 +1058,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" sky_engine: @@ -1015,7 +1071,7 @@ packages: description: name: slider_captcha sha256: "0fc2e0e8af7bf0e7ece23b8213e6becf841dd7839a40ad4b2a5071eaf5135774" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.2" source_span: @@ -1023,7 +1079,7 @@ packages: description: name: source_span sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.10.2" stack_trace: @@ -1031,7 +1087,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.12.1" stream_channel: @@ -1039,7 +1095,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.4" string_scanner: @@ -1047,7 +1103,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.1" term_glyph: @@ -1055,23 +1111,23 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" - url: "https://pub.flutter-io.cn" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.7" typed_data: dependency: transitive description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.0" universal_io: @@ -1079,7 +1135,7 @@ packages: description: name: universal_io sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.1" url_launcher: @@ -1087,31 +1143,31 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.2" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.flutter-io.cn" + sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" + url: "https://pub.dev" source: hosted - version: "6.3.28" + version: "6.3.29" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.flutter-io.cn" + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + url: "https://pub.dev" source: hosted - version: "6.3.6" + version: "6.4.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.2" url_launcher_macos: @@ -1119,7 +1175,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -1127,23 +1183,23 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.flutter-io.cn" + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" url_launcher_windows: dependency: transitive description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.5" uuid: @@ -1151,23 +1207,23 @@ packages: description: name: uuid sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.5.3" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.flutter-io.cn" + sha256: "7076216a10d5c390315fbe536a30f1254c341e7543e6c4c8a815e591307772b1" + url: "https://pub.dev" source: hosted - version: "1.1.19" + version: "1.1.20" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.13" vector_graphics_compiler: @@ -1175,7 +1231,7 @@ packages: description: name: vector_graphics_compiler sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.0" vector_math: @@ -1183,7 +1239,7 @@ packages: description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" vm_service: @@ -1191,7 +1247,7 @@ packages: description: name: vm_service sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "15.0.2" web: @@ -1199,7 +1255,7 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" win32: @@ -1207,7 +1263,7 @@ packages: description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.15.0" win32_registry: @@ -1215,7 +1271,7 @@ packages: description: name: win32_registry sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.5" xdg_directories: @@ -1223,7 +1279,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.0" xml: @@ -1231,7 +1287,7 @@ packages: description: name: xml sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.6.1" yaml: @@ -1239,9 +1295,9 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.3" sdks: - dart: ">=3.9.0 <4.0.0" - flutter: ">=3.35.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" From 8748a60f7ff68e6eb4f1deeccb0558c0d76a5ce6 Mon Sep 17 00:00:00 2001 From: userGyl Date: Mon, 30 Mar 2026 16:13:22 +0800 Subject: [PATCH 19/19] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AE=97=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/main/AndroidManifest.xml | 6 + .../java/com/lnkj/ln_jq_app/MainActivity.java | 59 --- .../com/lnkj/ln_jq_app/NativeMapView.java | 233 ++++++---- .../lnkj/ln_jq_app/NavigationActivity.java | 407 ++++++++++++++++++ 4 files changed, 573 insertions(+), 132 deletions(-) create mode 100644 ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NavigationActivity.java diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml index c7cf8d3..38e0df1 100644 --- a/ln_jq_app/android/app/src/main/AndroidManifest.xml +++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml @@ -40,6 +40,12 @@ android:name="com.amap.api.navi.AmapRouteActivity" android:theme="@android:style/Theme.NoTitleBar" android:configChanges="orientation|keyboardHidden|screenSize|navigation" /> + + { - switch (call.method) { - case "requestPermissions": - requestPermissions(); - result.success(null); - break; - case "onResume": - if (mapView != null) { - mapView.onResume(); - } - result.success(null); - break; - case "onPause": - if (mapView != null) { - mapView.onPause(); - } - result.success(null); - break; - case "onDestroy": - if (mapView != null) { - mapView.dispose(); - mapView = null; - } - result.success(null); - break; - default: - result.notImplemented(); - break; - } - }); } /** @@ -133,23 +98,6 @@ public class MainActivity extends FlutterActivity { this.mapView = mapView; } - @Override - protected void onResume() { - super.onResume(); - // 注意:高德SDK合规检查通过后再进行定位相关操作 - // 这里仅保留地图生命周期调用,权限建议在Flutter端或按需触发 - if (mapView != null) { - mapView.onResume(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (mapView != null) { - mapView.onPause(); - } - } @Override protected void onDestroy() { @@ -160,13 +108,6 @@ public class MainActivity extends FlutterActivity { } } - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - if (mapView != null) { - mapView.onSaveInstanceState(outState); - } - } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java index 720435a..c46c020 100644 --- a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NativeMapView.java @@ -2,6 +2,7 @@ package com.lnkj.ln_jq_app; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -35,6 +36,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -60,7 +62,6 @@ import com.amap.api.navi.AmapNaviPage; import com.amap.api.navi.AmapNaviParams; import com.amap.api.navi.AmapNaviType; import com.amap.api.navi.AmapPageType; -import com.amap.api.navi.enums.PathPlanningStrategy; import com.amap.api.navi.model.AMapCarInfo; import com.amap.api.navi.model.NaviPoi; import com.amap.api.services.core.AMapException; @@ -150,6 +151,8 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation // 存储货车路线算法接口返回的数据 private TruckRouteData truckRouteData; + //当前定位信息 + private AMapLocation mLoc; public NativeMapView(Context context, int id, Object args) { @@ -171,6 +174,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation container.addView(mapView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + initLoadingView(context); initData(context); initServices(context); initOverlays(context); @@ -194,6 +198,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } private LinearLayout bottomContainer; + private void initOverlays(Context context) { // --- 底部主容器 (包含两个互斥显示的面板) --- bottomContainer = new LinearLayout(context); @@ -392,6 +397,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation //最后调用监听函数 addKeyboardListener(); } + private void addKeyboardListener() { container.getViewTreeObserver().addOnGlobalLayoutListener(() -> { Rect r = new Rect(); @@ -412,6 +418,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } }); } + private void updateBottomMargin(int bottomPx) { if (bottomContainer != null) { FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) bottomContainer.getLayoutParams(); @@ -422,6 +429,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } } } + private LinearLayout createDetailPanel(Context context) { LinearLayout panel = new LinearLayout(context); panel.setOrientation(LinearLayout.VERTICAL); @@ -516,12 +524,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return; } - // 开始规划前隐藏输入框面板 - searchArea.setVisibility(View.GONE); - - RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude)); - RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, ""); - routeSearch.calculateDriveRouteAsyn(query); + fetchTruckRouteAlgorithm(mLoc); } @Override @@ -603,11 +606,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation } //确定目的地坐标和名称 - // 优先级:用户手动选择 > truckRouteData (接口返回的精准点) > endPoint (地图点击/搜索的点) LatLng finalDestinationLatLng = null; String finalDestinationName = endName; - // 如果用户手动选择了目的地,直接使用用户选择的地址 + // 优先级:用户手动选择 > truckRouteData (接口返回的精准点) > endPoint (地图点击/搜索的点) if (isUserSelectedDestination && endPoint != null) { finalDestinationLatLng = endPoint; finalDestinationName = endName; @@ -619,8 +621,10 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation //防止 parseDouble 崩溃 if (latStr != null && !latStr.isEmpty() && lngStr != null && !lngStr.isEmpty()) { try { - finalDestinationLatLng = new LatLng(Double.parseDouble(latStr), Double.parseDouble(lngStr)); - if (truckRouteData.destinationSite.name != null && !truckRouteData.destinationSite.name.isEmpty()) { + finalDestinationLatLng = new LatLng(Double.parseDouble(latStr), + Double.parseDouble(lngStr)); + if (truckRouteData.destinationSite.name != null && + !truckRouteData.destinationSite.name.isEmpty()) { finalDestinationName = truckRouteData.destinationSite.name; } } catch (NumberFormatException e) { @@ -640,64 +644,83 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation return; } - //构造起点和终点 POI - Poi start = new Poi(startName, startPoint, ""); - Poi end = new Poi(finalDestinationName, finalDestinationLatLng, ""); - - //配置导航参数 - AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); - - try { - AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); - - // 设置车辆信息 (只有在数据完整时设置) - if (truckRouteData != null && truckRouteData.truckDto != null) { - AMapCarInfo carInfo = new AMapCarInfo(); - carInfo.setCarNumber(plateNumber); // 使用初始化时获取的车牌 - carInfo.setCarType(String.valueOf(truckRouteData.truckDto.mcarType)); - carInfo.setVehicleAxis(String.valueOf(truckRouteData.truckDto.mvehicleAxis)); - carInfo.setVehicleHeight(truckRouteData.truckDto.mvehicleHeight); - carInfo.setVehicleLength(truckRouteData.truckDto.mvehicleLength); - carInfo.setVehicleWidth(truckRouteData.truckDto.mvehicleWidth); - carInfo.setVehicleSize(String.valueOf(truckRouteData.truckDto.mvehicleSize)); - carInfo.setVehicleLoad(truckRouteData.truckDto.mvehicleLoad); - carInfo.setVehicleWeight(truckRouteData.truckDto.mvehicleWeight); - carInfo.setRestriction(truckRouteData.truckDto.isRestriction); - carInfo.setVehicleLoadSwitch(truckRouteData.truckDto.mvehicleLoadSwitch); - - params.setCarInfo(carInfo); - mAMapNavi.setCarInfo(carInfo); - } - - //处理途径点 (如果接口返回了 naviList) - if (truckRouteData != null && truckRouteData.pathDto != null && truckRouteData.pathDto.naviList != null) { - NaviPoi startNaviPoi = new NaviPoi(startName, startPoint, ""); - NaviPoi endNaviPoi = new NaviPoi(finalDestinationName, finalDestinationLatLng, ""); - - List waysPoiIds = new ArrayList<>(); - for (NaviPoint np : truckRouteData.pathDto.naviList) { - if (np.coordinate != null && !TextUtils.isEmpty(np.coordinate.latitude) && !TextUtils.isEmpty(np.coordinate.longitude)) { - try { - double lat = Double.parseDouble(np.coordinate.latitude); - double lng = Double.parseDouble(np.coordinate.longitude); - waysPoiIds.add(new NaviPoi(np.name, new LatLng(lat, lng), np.poiId)); - } catch (Exception e) { - Log.e(TAG, "途径点坐标解析错误: " + np.name); - } + //获取途径点 + List waysPoiIds = new ArrayList<>(); + if (truckRouteData != null && truckRouteData.pathDto != null && truckRouteData.pathDto.naviList != + null) { + for (NaviPoint np : truckRouteData.pathDto.naviList) { + if (np.coordinate != null && !TextUtils.isEmpty(np.coordinate.latitude) && + !TextUtils.isEmpty(np.coordinate.longitude)) { + try { + double lat = Double.parseDouble(np.coordinate.latitude); + double lng = Double.parseDouble(np.coordinate.longitude); + waysPoiIds.add(new NaviPoi(np.name, new LatLng(lat, lng), np.poiId)); + } catch (Exception e) { + Log.e(TAG, "途径点坐标解析错误: " + np.name); } } - - // 如果有途径点,主动触发算路逻辑 - if (!waysPoiIds.isEmpty()) { - mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, waysPoiIds, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); - } } - } catch (Exception e) { - Log.e(TAG, "配置导航参数出错: " + e.getMessage()); } + //车辆信息 + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber(plateNumber); + carInfo.setCarType(String.valueOf(truckRouteData.truckDto.mcarType)); + carInfo.setVehicleAxis(String.valueOf(truckRouteData.truckDto.mvehicleAxis)); + carInfo.setVehicleHeight(truckRouteData.truckDto.mvehicleHeight); + carInfo.setVehicleLength(truckRouteData.truckDto.mvehicleLength); + carInfo.setVehicleWidth(truckRouteData.truckDto.mvehicleWidth); + carInfo.setVehicleSize(String.valueOf(truckRouteData.truckDto.mvehicleSize)); + carInfo.setVehicleLoad(truckRouteData.truckDto.mvehicleLoad); + carInfo.setVehicleWeight(truckRouteData.truckDto.mvehicleWeight); + carInfo.setRestriction(truckRouteData.truckDto.isRestriction); + carInfo.setVehicleLoadSwitch(truckRouteData.truckDto.mvehicleLoadSwitch); - //启动高德 - AmapNaviPage.getInstance().showRouteActivity(mActivity, params, null); + // 检查途径点数量,决定使用哪种导航方式 + int wayPointsCount = waysPoiIds.size(); + Log.d(TAG, "途经点数量: " + wayPointsCount); + if (wayPointsCount > 3) { + // 途经点超过3个,跳转到 NavigationActivity + Intent intent = new Intent(mContext, NavigationActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // 设置起点和终点 POI + NaviPoi startNaviPoi = new NaviPoi("", startPoint, ""); + NaviPoi endNaviPoi = new NaviPoi("", finalDestinationLatLng, ""); + intent.putExtra("startPoi", startNaviPoi); + intent.putExtra("endPoi", endNaviPoi); + + // 设置车辆信息 + if (truckRouteData != null && truckRouteData.truckDto != null) { + intent.putExtra("carInfo", carInfo); + } + + // 设置途径点 + if (!waysPoiIds.isEmpty()) {// 必须转换为 ArrayList 才能调用 putParcelableArrayListExtra + ArrayList wayPointsArrayList = new ArrayList<>(waysPoiIds); + intent.putParcelableArrayListExtra("wayPoints", wayPointsArrayList); + } + + mContext.startActivity(intent); + + } else { + Poi start = new Poi(startName, startPoint, ""); + Poi end = new Poi(finalDestinationName, finalDestinationLatLng, ""); + AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, + AmapPageType.ROUTE); + + try { + AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); + // 设置车辆信息 + if (truckRouteData != null && truckRouteData.truckDto != null) { + params.setCarInfo(carInfo); + mAMapNavi.setCarInfo(carInfo); + } + params.setNeedDestroyDriveManagerInstanceWhenNaviExit(true); + AmapNaviPage.getInstance().showRouteActivity(mActivity, params, null); + } catch (Exception e) { + Log.e(TAG, "配置导航参数出错: " + e.getMessage()); + } + } } private void initData(Context context) { @@ -721,6 +744,9 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation * 获取货车路线算法信息 */ private void fetchTruckRouteAlgorithm(AMapLocation loc) { + + showLoading(); + if (plateNumber == null || plateNumber.isEmpty()) { return; } @@ -742,6 +768,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.e(TAG, "fetchTruckRouteAlgorithm failed", e); + dismissLoading(); } @Override @@ -756,18 +783,78 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation JSONObject data = res.getJSONObject("data"); truckRouteData = parseTruckRouteData(data); Log.d(TAG, "TruckRouteAlgorithm data loaded"); + + dismissLoading(); + + // 开始规划前隐藏输入框面板 + searchArea.setVisibility(View.GONE); + + RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(new LatLonPoint(startPoint.latitude, startPoint.longitude), new LatLonPoint(endPoint.latitude, endPoint.longitude)); + RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DRIVING_SINGLE_DEFAULT, null, null, ""); + routeSearch.calculateDriveRouteAsyn(query); + } else { + dismissLoading(); } } catch (Exception e) { Log.e(TAG, "parseTruckRouteAlgorithm error", e); } + } else { + dismissLoading(); } } }); } catch (Exception e) { Log.e(TAG, "fetchTruckRouteAlgorithm error", e); + dismissLoading(); } } + private ProgressBar progressBar; + private FrameLayout loadingOverlay; + + private void initLoadingView(Context context) { + // 创建遮罩层 (全屏透明,拦截点击) + loadingOverlay = new FrameLayout(context); + loadingOverlay.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + loadingOverlay.setClickable(true); // 拦截点击 + loadingOverlay.setFocusable(true); + loadingOverlay.setVisibility(View.GONE); // 默认隐藏 + + progressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleLarge); + FrameLayout.LayoutParams progressParams = new FrameLayout.LayoutParams( + dp2px(45), dp2px(45)); + progressParams.gravity = Gravity.CENTER; // 居中显示 + + // 把进度条加到遮罩层 + loadingOverlay.addView(progressBar, progressParams); + + // 最后把整个遮罩层添加到主容器的最顶层 + container.addView(loadingOverlay); + } + + private void showLoading() { + if (mActivity == null) + return; + mActivity.runOnUiThread(() -> { + if (loadingOverlay != null) { + loadingOverlay.setVisibility(View.VISIBLE); + } + // 如果想在加载时给用户文字提示,可以动态加一个 TextView 在 ProgressBar 下方 + }); + } + + private void dismissLoading() { + if (mActivity == null) + return; + mActivity.runOnUiThread(() -> { + if (loadingOverlay != null) { + loadingOverlay.setVisibility(View.GONE); + } + }); + } + private void setupMapUi() { aMap.setLocationSource(this); aMap.setMyLocationEnabled(true); @@ -829,6 +916,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation mlocationClient = new AMapLocationClient(mContext); AMapLocationClientOption option = new AMapLocationClientOption(); mlocationClient.setLocationListener(this); + option.setNeedAddress(true); option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); mlocationClient.setLocationOption(option); mlocationClient.startLocation(); @@ -840,19 +928,19 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation @Override public void onLocationChanged(AMapLocation loc) { - if (loc != null && loc.getErrorCode() == 0) { - currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude()); + mLoc = loc; + if (mLoc != null && mLoc.getErrorCode() == 0) { + currentLatLng = new LatLng(mLoc.getLatitude(), mLoc.getLongitude()); if (mListener != null) - mListener.onLocationChanged(loc); + mListener.onLocationChanged(mLoc); if (isFirstLocation) { isFirstLocation = false; startPoint = currentLatLng; aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f)); getAddressByLatlng(currentLatLng); - fetchRecommendStation(loc); - fetchNearbyStations(loc); - // 获取货车路线算法信息 - fetchTruckRouteAlgorithm(loc); + fetchRecommendStation(mLoc); + fetchNearbyStations(mLoc); + } } } @@ -1234,7 +1322,6 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation private void switchMode(String mode) { // 处理模式切换逻辑 - Toast.makeText(mContext, "切换到:" + mode, Toast.LENGTH_SHORT).show(); modeMenu.setVisibility(View.GONE); } @@ -1252,7 +1339,7 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation GradientDrawable gd = new GradientDrawable(); gd.setColor(color); // 顺序:左上x2, 右上x2, 右下x2, 左下x2 - gd.setCornerRadii(new float[]{r, r, r, r, 0, 0, 0, 0}); + gd.setCornerRadii(new float[]{r, r, r, r, r, r, r, r}); return gd; } diff --git a/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NavigationActivity.java b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NavigationActivity.java new file mode 100644 index 0000000..65db261 --- /dev/null +++ b/ln_jq_app/android/app/src/main/java/com/lnkj/ln_jq_app/NavigationActivity.java @@ -0,0 +1,407 @@ +package com.lnkj.ln_jq_app; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.util.Log; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.Toast; + +import com.amap.api.maps.AMapException; +import com.amap.api.navi.AMapNavi; +import com.amap.api.navi.AMapNaviListener; +import com.amap.api.navi.AMapNaviView; +import com.amap.api.navi.AMapNaviViewListener; +import com.amap.api.navi.AMapNaviViewOptions; +import com.amap.api.navi.enums.NaviType; +import com.amap.api.navi.enums.PathPlanningStrategy; +import com.amap.api.navi.model.AMapCalcRouteResult; +import com.amap.api.navi.model.AMapCarInfo; +import com.amap.api.navi.model.AMapLaneInfo; +import com.amap.api.navi.model.AMapModelCross; +import com.amap.api.navi.model.AMapNaviCameraInfo; +import com.amap.api.navi.model.AMapNaviCross; +import com.amap.api.navi.model.AMapNaviLocation; +import com.amap.api.navi.model.AMapNaviRouteNotifyData; +import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo; +import com.amap.api.navi.model.AMapServiceAreaInfo; +import com.amap.api.navi.model.AimLessModeCongestionInfo; +import com.amap.api.navi.model.AimLessModeStat; +import com.amap.api.navi.model.NaviInfo; +import com.amap.api.navi.model.NaviPoi; + +import java.util.List; + +import androidx.activity.ComponentActivity; +import androidx.activity.OnBackPressedCallback; +import androidx.annotation.NonNull; + +/** + * 导航 + */ +public class NavigationActivity extends ComponentActivity implements AMapNaviListener { + + private static final String TAG = "NavigationActivity"; + + private AMapNavi mAMapNavi; + private AMapNaviView naviView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // 创建导航视图 + naviView = new AMapNaviView(this); + naviView.onCreate(savedInstanceState); + naviView.setAMapNaviViewListener(new AMapNaviViewListener() { + @Override + public void onNaviSetting() { + + } + + @Override + public void onNaviCancel() { + finish(); + } + + @Override + public boolean onNaviBackClick() { + return false; + } + + @Override + public void onNaviMapMode(int i) { + + } + + @Override + public void onNaviTurnClick() { + + } + + @Override + public void onNextRoadClick() { + + } + + @Override + public void onScanViewButtonClick() { + + } + + @Override + public void onLockMap(boolean b) { + + } + + @Override + public void onNaviViewLoaded() { + + } + + @Override + public void onMapTypeChanged(int i) { + + } + + @Override + public void onNaviViewShowMode(int i) { + + } + }); + + AMapNaviViewOptions aMapNaviViewOptions = new AMapNaviViewOptions(); + Bitmap carBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.car); + aMapNaviViewOptions.setCarBitmap(carBitmap); + aMapNaviViewOptions.setSettingMenuEnabled(false); + naviView.setViewOptions(aMapNaviViewOptions); + + // 创建 AMapNavi 实例 + try { + mAMapNavi = AMapNavi.getInstance(this); + mAMapNavi.addAMapNaviListener(this); + } catch (AMapException e) { + Log.e(TAG, "初始化导航失败", e); + Toast.makeText(this, "初始化导航失败", Toast.LENGTH_SHORT).show(); + finish(); + return; + } + + // 添加到容器 + FrameLayout container = new FrameLayout(this); + container.addView(naviView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + setContentView(container); + + // 获取 Intent 中的参数 + processIntent(getIntent()); + + // 处理返回键 + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + finish(); + } + }); + + Log.d(TAG, "NavigationActivity created"); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + processIntent(intent); + } + + /** + * 处理 Intent 参数并启动导航 + */ + @SuppressWarnings("unchecked") + private void processIntent(Intent intent) { + if (intent == null) { + Log.w(TAG, "Intent is null"); + return; + } + + try { + // 获取起点、终点和途经点 + NaviPoi startNaviPoi = (NaviPoi) intent.getParcelableExtra("startPoi"); + NaviPoi endNaviPoi = (NaviPoi) intent.getParcelableExtra("endPoi"); + List wayPoints = intent.getParcelableArrayListExtra("wayPoints"); + + if (wayPoints != null) { + Log.d("Navi", "获取到途径点数量: " + wayPoints.size()); + } + + + if (startNaviPoi == null || endNaviPoi == null) { + Log.e(TAG, "Missing start or end point"); + return; + } + + // 设置车辆信息 + AMapCarInfo carInfo = (AMapCarInfo) intent.getParcelableExtra("carInfo"); + if (carInfo != null) { + mAMapNavi.setCarInfo(carInfo); + } + + // 计算并启动导航 + mAMapNavi.calculateDriveRoute(startNaviPoi, endNaviPoi, wayPoints, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + + Log.d(TAG, "Navigation started from: " + startNaviPoi.getName() + " - " + endNaviPoi.getName()); + + } catch (Exception e) { + Log.e(TAG, "Process intent error", e); + Toast.makeText(this, "导航启动失败", Toast.LENGTH_SHORT).show(); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (naviView != null) { + naviView.onResume(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (naviView != null) { + naviView.onPause(); + } + } + + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + if (naviView != null) { + naviView.onSaveInstanceState(outState); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + // 停止导航 + if (mAMapNavi != null) { + mAMapNavi.stopNavi(); + mAMapNavi.removeAMapNaviListener(this); + } + if (naviView != null) { + naviView.onDestroy(); + } + Log.d(TAG, "NavigationActivity destroyed"); + } + + private int dp2px(float dp) { + float density = getResources().getDisplayMetrics().density; + return (int) (dp * density + 0.5f); + } + + // ============ AMapNaviListener 回调实现 ============ + + + @Override + public void onInitNaviFailure() { + Log.e(TAG, "onInitNaviFailure"); + } + + @Override + public void onInitNaviSuccess() { + Log.d(TAG, "onInitNaviSuccess"); + } + + @Override + public void onStartNavi(int i) { + Log.d(TAG, "onStartNavi: " + i); + } + + @Override + public void onTrafficStatusUpdate() { + } + + @Override + public void onLocationChange(AMapNaviLocation aMapNaviLocation) { + } + + @Override + public void onGetNavigationText(int i, String s) { + } + + @Override + public void onGetNavigationText(String s) { + } + + @Override + public void onEndEmulatorNavi() { + } + + @Override + public void onArriveDestination() { + Log.d(TAG, "onArriveDestination"); + } + + @Override + public void onCalculateRouteFailure(int i) { + Log.e(TAG, "onCalculateRouteFailure: " + i); + Toast.makeText(this, "路径计算失败: " + i, Toast.LENGTH_SHORT).show(); + } + + @Override + public void updateCameraInfo(AMapNaviCameraInfo[] aMapNaviCameraInfos) { + } + + @Override + public void updateIntervalCameraInfo(AMapNaviCameraInfo aMapNaviCameraInfo, AMapNaviCameraInfo aMapNaviCameraInfo1, int i) { + } + + @Override + public void onServiceAreaUpdate(AMapServiceAreaInfo[] aMapServiceAreaInfos) { + } + + @Override + public void showCross(AMapNaviCross aMapNaviCross) { + } + + @Override + public void hideCross() { + } + + @Override + public void showModeCross(AMapModelCross aMapModelCross) { + } + + @Override + public void hideModeCross() { + } + + @Override + public void showLaneInfo(AMapLaneInfo[] aMapLaneInfos, byte[] bytes, byte[] bytes1) { + } + + @Override + public void showLaneInfo(AMapLaneInfo aMapLaneInfo) { + } + + @Override + public void hideLaneInfo() { + } + + @Override + public void onCalculateRouteSuccess(int[] ints) { + Log.d(TAG, "onCalculateRouteSuccess"); + if (mAMapNavi != null) { + mAMapNavi.startNavi(NaviType.GPS); + } + } + + @Override + public void notifyParallelRoad(int i) { + } + + @Override + public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo[] aMapNaviTrafficFacilityInfos) { + } + + @Override + public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo) { + } + + @Override + public void updateAimlessModeStatistics(AimLessModeStat aimLessModeStat) { + } + + @Override + public void updateAimlessModeCongestionInfo(AimLessModeCongestionInfo aimLessModeCongestionInfo) { + } + + @Override + public void onPlayRing(int i) { + } + + @Override + public void onCalculateRouteSuccess(AMapCalcRouteResult aMapCalcRouteResult) { + Log.d(TAG, "onCalculateRouteSuccess (result)"); + if (mAMapNavi != null) { + mAMapNavi.startNavi(NaviType.GPS); + } + } + + @Override + public void onCalculateRouteFailure(AMapCalcRouteResult aMapCalcRouteResult) { + Log.e(TAG, "onCalculateRouteFailure: " + aMapCalcRouteResult.getErrorCode()); + Toast.makeText(this, "路径计算失败", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onNaviRouteNotify(AMapNaviRouteNotifyData aMapNaviRouteNotifyData) { + } + + @Override + public void onGpsSignalWeak(boolean b) { + } + + @Override + public void onReCalculateRouteForYaw() { + Log.d(TAG, "onReCalculateRouteForYaw"); + } + + @Override + public void onReCalculateRouteForTrafficJam() { + } + + @Override + public void onArrivedWayPoint(int i) { + } + + @Override + public void onGpsOpenStatus(boolean b) { + } + + @Override + public void onNaviInfoUpdate(NaviInfo naviInfo) { + } +}