172 Commits

Author SHA1 Message Date
8e79d8039c fix 2026-04-16 13:43:11 +08:00
2523899ec4 路径更换线上 2026-04-16 11:29:51 +08:00
853a9135c8 线上配置 2026-04-16 11:10:35 +08:00
ec96a96be2 Merge branch 'dev_map' into dev
version 1.2.5
# Conflicts:
#	ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ASearchAddressController.m
#	ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/View/AStationDetailPopupView.m
2026-04-16 10:50:57 +08:00
xiaogg
0ba9547992 fix:优化完善; 2026-04-15 20:03:37 +08:00
c6e7616be2 fix 2026-04-15 10:06:58 +08:00
eae654c47e fix 2026-04-14 14:04:19 +08:00
f01875abb9 调整 2026-04-14 11:50:33 +08:00
881da166d1 调整 2026-04-13 17:48:37 +08:00
14b2e6b35c Merge branch 'dev_map' into dev 2026-04-13 16:54:07 +08:00
20c39a4a12 样式调整 2026-04-13 16:38:46 +08:00
xiaogg
5c74c7ccc0 fix:优化完善; 2026-04-13 16:13:23 +08:00
23fc0da5c8 新增字段 2026-04-13 15:05:29 +08:00
7efd933416 新增字段 2026-04-09 14:05:27 +08:00
2b33dac384 语音 2026-04-08 10:59:43 +08:00
ef60b8ed62 Merge branch 'map_dev' into dev 2026-04-03 10:25:53 +08:00
bec6952707 Merge branch 'dev_map' into map_dev 2026-04-02 09:11:14 +08:00
f68349a208 Merge branch 'dev_map' into dev 2026-04-01 17:38:48 +08:00
xiaogg
08dcc64ef4 fix:优化完善; 2026-04-01 15:12:54 +08:00
9242dcaf70 优化 2026-04-01 15:06:04 +08:00
95fdfe6269 增加演示账号 2026-04-01 11:41:44 +08:00
ee88b3ada9 优化 2026-04-01 11:34:32 +08:00
ba27799c41 显示问题 2026-03-31 17:12:00 +08:00
c527732532 Merge branch 'main' into dev
# Conflicts:
#	ln_jq_app/android/app/src/main/AndroidManifest.xml
#	ln_jq_app/pubspec.lock
同步线上
2026-03-31 15:07:16 +08:00
cd223fa9bf Merge branch 'map_dev' into dev
# Conflicts:
#	ln_jq_app/android/app/src/main/AndroidManifest.xml
#	ln_jq_app/ios/Runner/Info.plist
2026-03-31 13:49:42 +08:00
fdd6653fce Merge branch 'dev_map' into map_dev
# Conflicts:
#	ln_jq_app/ios/Podfile.lock
#	ln_jq_app/lib/pages/c_page/base_widgets/view.dart
地图导航相关
2026-03-31 10:07:43 +08:00
8748a60f7f 优化算路 2026-03-30 16:13:22 +08:00
xiaogg
5843ef6e87 feat:增加途经点,完善规划,导航; 2026-03-27 15:39:36 +08:00
0123025296 优化搜索 2026-03-27 13:23:10 +08:00
587dd48896 调整地址输入 2026-03-27 11:45:07 +08:00
569780ffb4 样式 2026-03-27 09:37:52 +08:00
3aac4e7330 调整地图选点 2026-03-26 18:01:05 +08:00
b275c66383 ui 2026-03-26 16:58:57 +08:00
bf80931f37 bugfix 2026-03-25 17:56:37 +08:00
67c36f436c bugfix 2026-03-25 17:18:06 +08:00
c10c92afdc 增加token 2026-03-25 11:02:15 +08:00
d3edf95df3 单独缓存车牌 2026-03-24 09:38:16 +08:00
930953780d 路径接口 2026-03-20 10:23:45 +08:00
a497bc6469 清理插件 2026-03-19 17:41:28 +08:00
3f282d15c1 协议修改 2026-03-19 16:37:57 +08:00
03b35f660c 协议前置 2026-03-19 14:41:32 +08:00
9b6f93ca95 隐私调整 2026-03-17 13:31:58 +08:00
eb41ecaec4 更新插件 2026-03-16 16:00:38 +08:00
384de27f2c Merge branch 'dev' 2026-03-13 17:18:43 +08:00
84b174c4a5 协议通知后注册推送 2026-03-13 17:09:30 +08:00
cd14469d79 调整定位 2026-03-12 13:27:08 +08:00
b846d352a2 android 地图 2026-03-10 17:31:27 +08:00
xiaogg
a24f41a8d5 fix:添加本地库 2026-03-09 09:38:22 +08:00
xiaogg
65b4a3ac34 接入地图SDK 2026-03-09 08:53:34 +08:00
02e1946319 文字边界 2026-03-05 11:20:14 +08:00
d5083c1939 Merge branch 'dev'
v1.2.4
2026-03-04 14:58:45 +08:00
fe44848529 号码 2026-03-04 14:50:21 +08:00
572c416827 枪号回填,v1.2.4 2026-03-04 13:38:26 +08:00
8df16f0787 pdf查看 2026-03-03 17:51:06 +08:00
ce6bd3edd2 bugfix 2026-03-03 13:09:10 +08:00
6997b4ac9e 调整权限和库 2026-03-02 11:28:44 +08:00
a26d2478f3 样式 2026-02-28 17:31:28 +08:00
0dded3b928 ocr识别,历史新增类型 2026-02-28 17:15:42 +08:00
b7caf58adf 加氢站-查看证件 2026-02-28 15:00:56 +08:00
0df1902df2 无预约 2026-02-28 11:59:07 +08:00
a8314d8a7a 关闭弹窗 2026-02-27 10:55:55 +08:00
39cae906e9 加氢站-预约 2026-02-27 10:54:55 +08:00
14fd6c75d0 fix 2026-02-25 15:35:33 +08:00
1724852a39 司机-可上传证件 2026-02-25 15:35:02 +08:00
a05d4ebb9b 调整 2026-02-12 18:01:56 +08:00
600cea4379 进度条 2026-02-12 17:34:06 +08:00
3dfc1dfc2c 样式调整 2026-02-12 16:54:50 +08:00
909dc95771 增加 提示 2026-02-11 17:41:30 +08:00
cf0896453b 样式 2026-02-11 11:28:49 +08:00
dce9718320 显示周边加氢站 2026-02-11 09:35:42 +08:00
4491aa9b91 ui调整 2026-02-10 16:35:02 +08:00
5364612a6f 更新样式 2026-02-10 13:37:24 +08:00
10867178fa 筛选框样式 2026-02-10 13:35:22 +08:00
a5e2a89e4f 预约列表样式 2026-02-10 11:51:47 +08:00
26c5f9d67a 消息样式修改 2026-02-09 17:57:00 +08:00
9cd87b0535 规则和历史 2026-02-09 17:28:12 +08:00
45e45d8160 积分兑换 2026-02-09 15:10:00 +08:00
87e890f97e 积分兑换首页 2026-02-06 17:37:43 +08:00
dcf925b8c1 商场页 2026-02-06 15:13:33 +08:00
c45863eda6 增加商城页面 2026-02-06 15:11:12 +08:00
756bf53cf5 司机预约时间调整 2026-02-06 14:16:26 +08:00
f68c2d0938 未车辆显示 2026-02-05 14:50:03 +08:00
211d0225e4 车辆图片动态 2026-02-05 13:54:10 +08:00
7d9b4d99e8 应用更新 2026-02-05 10:30:31 +08:00
3dd583a278 401增加节流 2026-02-03 10:59:05 +08:00
35bd3a78a5 Merge branch 'dev' 2026-01-30 17:33:15 +08:00
1278c38b7e 地图样式调整 2026-01-30 17:32:54 +08:00
032e60d362 Merge branch 'dev'
ui调整
# Conflicts:
#	ln_jq_app/lib/pages/login/view.dart
2026-01-30 17:08:49 +08:00
171f556b40 viersion 1.2.3 2026-01-30 16:06:58 +08:00
55eade54b6 问题修改 2026-01-30 16:02:35 +08:00
bc99ffd691 增加参数 2026-01-30 13:01:50 +08:00
aa52a56bcf 地图相关的修改 2026-01-30 11:36:33 +08:00
73343ca297 调整 2026-01-30 10:01:31 +08:00
d09faac1d2 调整 2026-01-29 19:26:59 +08:00
1177be821a 样式调整 2026-01-29 17:01:21 +08:00
e59b89c225 Merge branch 'dev_feature' into dev
ui调整
# Conflicts:
#	ln_jq_app/lib/pages/b_page/reservation/controller.dart
#	ln_jq_app/lib/pages/b_page/site/controller.dart
#	ln_jq_app/lib/pages/b_page/site/view.dart
#	ln_jq_app/lib/pages/c_page/mine/view.dart
#	ln_jq_app/lib/pages/c_page/reservation/controller.dart
#	ln_jq_app/lib/pages/c_page/reservation/view.dart
#	ln_jq_app/lib/pages/login/view.dart
2026-01-29 11:45:17 +08:00
79fe3257b5 状态样式 2026-01-28 17:59:26 +08:00
55569839a7 搜索框 2026-01-28 16:27:37 +08:00
7112d70aba 站点样式 2026-01-28 15:00:30 +08:00
f8a8ecb0ed 司机 预约 样式修改 2026-01-27 17:35:37 +08:00
18c04272e2 车辆信息的部分 2026-01-27 13:57:14 +08:00
14e7fb3d78 首页ui 2026-01-27 13:15:53 +08:00
5ffaf81223 欢迎页 登录 2026-01-27 09:21:36 +08:00
907983a1d1 登录修改 2026-01-26 14:07:58 +08:00
9fdca9136d 导航栏 2026-01-23 17:00:17 +08:00
16bae6a1e9 车辆信息 ui 2026-01-23 15:02:16 +08:00
aabfbfae0c 车辆样式调整 2026-01-23 10:49:02 +08:00
5236670e7c ui修改 2026-01-23 09:22:07 +08:00
cf3ad579d3 新ui调整 2026-01-22 17:29:54 +08:00
70a752b6e5 协议同意 2026-01-21 14:29:03 +08:00
45f5035d1b 更换logo 2026-01-19 10:13:37 +08:00
f792915429 bugfix 2026-01-16 17:47:53 +08:00
edbacc502b 线上域名修改 2026-01-16 17:25:52 +08:00
5722e3ace0 ios build 2026-01-16 15:00:45 +08:00
d41b21654a 改用账号推送 2026-01-16 14:35:11 +08:00
2eb059defd 定时器黄字2位小数 2026-01-16 13:35:38 +08:00
fbcc85af2a 站点增加消息入口 2026-01-16 13:06:35 +08:00
9a97b56505 定时器显示调整 2026-01-15 17:55:07 +08:00
8302d7c179 优化问题修改 2026-01-15 16:28:59 +08:00
e7a9e4483a 优化定时器 弹窗 2026-01-15 13:29:02 +08:00
9b64fdfa52 优化定时器 2026-01-15 13:24:02 +08:00
d8f335eb4e 优化 2026-01-15 09:30:47 +08:00
d1b7a9eb76 v1.2.2 version 2026-01-14 13:21:54 +08:00
f25feaa55a 联调修改结构 2026-01-14 13:18:22 +08:00
16639e2384 站点增加广播 2026-01-12 17:52:08 +08:00
20ef495571 非营业状态 增加时间选择 2026-01-12 16:41:36 +08:00
285a20f070 地址切换 2026-01-12 09:13:37 +08:00
baee5dba83 消息中心,待测试 2026-01-08 15:33:40 +08:00
7d9c879a4e 消息中心 2026-01-07 17:43:22 +08:00
953e5e773c 消息入口 2026-01-07 16:02:10 +08:00
8a4bc1d1ab 取消预约按钮 2026-01-07 09:59:12 +08:00
c57c849073 样式交互修改 2026-01-06 17:57:56 +08:00
6cc123f272 更换导航栏位置 2026-01-05 14:09:15 +08:00
5168b23609 增加请求头 2026-01-04 16:59:08 +08:00
c5299dd655 增加版本号 2026-01-04 10:27:39 +08:00
4bedd8c04b 优化 2025-12-31 17:37:07 +08:00
295b71c819 推送配置,测试 2025-12-31 17:22:13 +08:00
6629c8047f Merge branch 'dev' 2025-12-25 10:41:04 +08:00
bfa615a7f4 扫码无权限优化,司机预约多弹窗 2025-12-25 10:40:26 +08:00
288d629f99 bugfix 2025-12-24 10:53:34 +08:00
15fdbc7043 v1.2.1 2025-12-23 10:43:12 +08:00
f2f2348b54 逆地理编码 2025-12-23 10:18:44 +08:00
9ba152b3c3 v1.2.1 待发布 2025-12-22 16:15:32 +08:00
21a528d6d1 调整和修改 2025-12-19 13:18:04 +08:00
62ca3888d3 历史统计数据,错误提示 2025-12-18 15:20:54 +08:00
3ec56a925c 修改搜索条件 2025-12-18 10:33:24 +08:00
95c08818cb 取消dark主题 2025-12-18 09:03:08 +08:00
42355bd1ef 站点-新增历史记录 2025-12-17 17:40:02 +08:00
fe2ce75cec 修改绑定车辆接口
登录后查询车辆信息
2025-12-17 09:18:34 +08:00
98cac8a0a5 预约列表增加筛选条件 2025-12-16 16:18:28 +08:00
9ce46a0c7d 加氢站默认选择,演示账号数据
附件默认显示,详情
2025-12-16 11:58:00 +08:00
266a43c09d 主题色 2025-12-16 09:54:32 +08:00
8434301d1f 版本号 2025-12-12 10:34:24 +08:00
adfe3bf34e 版本号修改 2025-12-11 15:50:25 +08:00
6a3c6db7a8 Merge branch 'dev'
司机端-加氢预约  预约时间段修改  1、开始结束时间整合成一个  2、时间只开放当日和次日
司机端-加氢预约  提交预约不可提交限制 1、非营业站点 2、预约时间不可重复
司机端-预约列表 1、新增到站时间、氢量修改 2、显示拒绝加氢原因
加氢站-加氢预约  1、新增当日预约加车牌/手机号筛选  2、新增加氢总量 未加氢量  3、 确认拒绝流程优化:完成可填写具体加氢量,新增拒绝原因
# Conflicts:
#	ln_jq_app/lib/common/styles/theme.dart
2025-12-11 15:48:10 +08:00
4ace3c9f27 刷新条件 2025-12-11 13:45:26 +08:00
b52659df6c 司机预约 显示拒绝原因 2025-12-11 13:27:28 +08:00
20877a3eb1 增加弹窗限制条件 2025-12-11 10:36:59 +08:00
69875f27ad 搜索字段 2025-12-10 17:51:00 +08:00
829f5e454e 文本处理 2025-12-10 17:37:56 +08:00
1c916a7fad 调整司机预约时间
站点工单状态
2025-12-10 17:34:46 +08:00
f638704fba ios 说明 2025-12-09 11:24:45 +08:00
4c63d5ebf3 bugfix 2025-12-08 17:52:55 +08:00
a3fb0d8018 站点 确认拒绝流程 2025-12-08 09:32:06 +08:00
88b16ca69e 今日预约搜索 2025-12-03 16:00:18 +08:00
ba3467810c 新增数据 2025-12-03 15:04:58 +08:00
0bfedd54cb 可编辑预约 2025-12-03 10:39:34 +08:00
f25d7e4567 增加 加氢站可用标记 2025-12-02 10:36:56 +08:00
4cdedff654 默认时间段修改 2025-12-01 17:03:16 +08:00
4f99ab4164 修改选择器 2025-12-01 15:27:00 +08:00
cdc5af7f45 限制 2025-12-01 13:59:02 +08:00
20e5e58ded 增加提交预约限制 2025-12-01 13:56:17 +08:00
244 changed files with 20026 additions and 3054 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(flutter build apk --debug 2>&1 | tail -15)",
"Bash(flutter build apk --debug 2>&1 | tail -10)"
]
}
}

View File

@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(./gradlew assembleDebug --stacktrace)"
]
}
}

View File

@@ -1,3 +1,6 @@
import java.util.Properties
import java.io.FileInputStream
plugins {
id("com.android.application")
id("kotlin-android")
@@ -5,6 +8,14 @@ plugins {
id("dev.flutter.flutter-gradle-plugin")
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystorePropertiesFile.inputStream().use { input ->
keystoreProperties.load(input.reader(Charsets.UTF_8))
}
}
android {
namespace = "com.lnkj.ln_jq_app"
compileSdk = flutter.compileSdkVersion
@@ -26,15 +37,30 @@ android {
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
versionCode = 8
versionName = "1.2.5"
}
signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String?
keyPassword = keystoreProperties["keyPassword"] as String?
val storeFilePath = keystoreProperties["storeFile"] as String?
storeFile = if (storeFilePath != null) file(storeFilePath) else null
storePassword = keystoreProperties["storePassword"] as String?
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
getByName("release") {
// 使用上面定义的 release 签名
signingConfig = signingConfigs.getByName("release")
// 修复混淆规则引用语法
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
@@ -42,3 +68,9 @@ 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")
implementation("androidx.appcompat:appcompat:1.7.1")
}

View File

@@ -0,0 +1,88 @@
# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
# 忽略 Google Play Core 相关的缺失警告(解决你目前的报错)
-dontwarn com.google.android.play.core.**
# Flutter 基础规则
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-dontwarn com.huawei.android.os.BuildEx$VERSION
-dontwarn com.huawei.hianalytics.process.HiAnalyticsConfig$Builder
-dontwarn com.huawei.hianalytics.process.HiAnalyticsConfig
-dontwarn com.huawei.hianalytics.process.HiAnalyticsInstance$Builder
-dontwarn com.huawei.hianalytics.process.HiAnalyticsInstance
-dontwarn com.huawei.hianalytics.process.HiAnalyticsManager
-dontwarn com.huawei.hianalytics.util.HiAnalyticTools
-dontwarn com.huawei.hms.availableupdate.UpdateAdapterMgr
-dontwarn com.huawei.libcore.io.ExternalStorageFile
-dontwarn com.huawei.libcore.io.ExternalStorageFileInputStream
-dontwarn com.huawei.libcore.io.ExternalStorageFileOutputStream
-dontwarn com.huawei.libcore.io.ExternalStorageRandomAccessFile
-dontwarn org.android.netutil.PingEntry
-dontwarn org.android.netutil.PingResponse
-dontwarn org.android.netutil.PingTask
-dontwarn org.bouncycastle.crypto.BlockCipher
-dontwarn org.bouncycastle.crypto.engines.AESEngine
-dontwarn org.bouncycastle.crypto.prng.SP800SecureRandom
-dontwarn org.bouncycastle.crypto.prng.SP800SecureRandomBuilder
-keepclasseswithmembernames class ** {
native <methods>;
}
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
-keep class com.taobao.** {*;}
-keep class com.alibaba.** {*;}
-keep class com.alipay.** {*;}
-keep class com.ut.** {*;}
-keep class com.ta.** {*;}
-keep class anet.**{*;}
-keep class anetwork.**{*;}
-keep class org.android.spdy.**{*;}
-keep class org.android.agoo.**{*;}
-keep class android.os.**{*;}
-keep class org.json.**{*;}
-dontwarn com.taobao.**
-dontwarn com.alibaba.**
-dontwarn com.alipay.**
-dontwarn anet.**
-dontwarn org.android.spdy.**
-dontwarn org.android.agoo.**
-dontwarn anetwork.**
-dontwarn com.ut.**
-dontwarn com.ta.**
#3D 地图 V5.0.0之前:
-keep class com.amap.api.maps.**{*;}
-keep class com.autonavi.amap.mapcore.*{*;}
-keep class com.amap.api.trace.**{*;}
#3D 地图 V5.0.0之后:
-keep class com.amap.api.maps.**{*;}
-keep class com.autonavi.**{*;}
-keep class com.amap.api.trace.**{*;}
#定位
-keep class com.amap.api.location.**{*;}
-keep class com.amap.api.fence.**{*;}
-keep class com.autonavi.aps.amapapi.model.**{*;}
#搜索
-keep class com.amap.api.services.**{*;}
#2D地图
-keep class com.amap.api.maps2d.**{*;}
-keep class com.amap.api.mapcore2d.**{*;}
#导航
-keep class com.amap.api.navi.**{*;}
-keep class com.autonavi.**{*;}

View File

@@ -1,45 +1,81 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!--定位权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--用于申请调用A-GPS模块-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission>
<!--如果设置了target >= 28 如果需要启动后台定位则必须声明这个权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!--如果您的应用需要后台定位权限且有可能运行在Android Q设备上,并且设置了target>28必须增加这个权限声明-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:label="小羚羚"
android:requestLegacyExternalStorage="true"
android:name="${applicationName}"
android:icon="@mipmap/logo">
android:icon="@mipmap/logo"
android:label="小羚羚">
<!-- 高德地图Key -->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="92495660f7bc990cb475426c47c03b65" />
<!-- 高德地图定位服务 -->
<service android:name="com.amap.api.location.APSService" />
<!--高德导航-->
<activity
android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />
<!--自定义导航 Activity-->
<activity
android:name="com.lnkj.ln_jq_app.NavigationActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait" />
<!--搜索目的地 Activity-->
<activity
android:name="com.lnkj.ln_jq_app.SearchDestinationActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
@@ -48,6 +84,48 @@
android:name="flutterEmbedding"
android:value="2" />
<!-- 请填写你自己的- appKey -->
<meta-data
android:name="com.alibaba.app.appkey"
android:value="335642645" />
<!-- 请填写你自己的appSecret -->
<meta-data
android:name="com.alibaba.app.appsecret"
android:value="39628204345a4240b5b645b68a5896c7" />
<!-- 接收推送消息 -->
<receiver
android:name="com.aliyun.ams.push.AliyunPushMessageReceiver"
android:exported="false"> <!-- 为保证receiver安全建议设置不可导出如需对其他应用开放可通过androidpermission进行限制 -->
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
</intent-filter>
<intent-filter>
<action android:name="com.alibaba.sdk.android.push.RECEIVE" />
</intent-filter>
</receiver>
<!-- 辅助弹窗Activity -->
<activity
android:name="com.aliyun.ams.push.PushPopupActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="${applicationId}"
android:path="/thirdpush"
android:scheme="agoo" />
</intent-filter>
</activity>
</application>
<!-- Required to query activities that can process text, see:
@@ -57,8 +135,8 @@
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
</queries>
</manifest>

View File

@@ -1,6 +1,161 @@
package com.lnkj.ln_jq_app;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.lnkj.ln_jq_app/map";
private static final String TAG = "MainActivity";
// 权限请求码
private static final int PERMISSION_REQUEST_CODE = 1001;
private NativeMapView mapView;
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
// 注册高德地图导航Platform View
flutterEngine
.getPlatformViewsController()
.getRegistry()
.registerViewFactory(
"NativeFirstPage",
new NativeMapFactory(this)
);
// 设置 Activity 实例到地图
NativeMapFactory.setActivity(this);
}
/**
* 获取当前系统版本需要申请的权限列表
*/
private String[] getRequiredPermissions() {
List<String> 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<String> 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 onDestroy() {
super.onDestroy();
if (mapView != null) {
mapView.dispose();
mapView = null;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 处理从搜索目的地页面返回的结果
if (requestCode == 1000 && resultCode == RESULT_OK && data != null) {
String name = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_NAME);
String address = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_ADDRESS);
double lat = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LAT, 0);
double lon = data.getDoubleExtra(SearchDestinationActivity.EXTRA_RESULT_LON, 0);
String district = data.getStringExtra(SearchDestinationActivity.EXTRA_RESULT_DISTRICT);
if (name != null && lat != 0 && lon != 0) {
// 获取地图实例并设置目的地
NativeMapView mapView = NativeMapFactory.getMapView();
if (mapView != null) {
mapView.setDestination(name, address, lat, lon, district);
}
}
}
}
@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();
}
}
}
}

View File

@@ -0,0 +1,47 @@
package com.lnkj.ln_jq_app;
import android.app.Activity;
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;
}
/**
* 设置 Activity 实例
*/
public static void setActivity(Activity activity) {
if (mapViewInstance != null) {
mapViewInstance.setActivity(activity);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,408 @@
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<NaviPoi> 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.setUseInnerVoice(true);
// 计算并启动导航
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) {
}
}

View File

@@ -0,0 +1,261 @@
package com.lnkj.ln_jq_app;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.InputtipsQuery;
import com.amap.api.services.help.Tip;
import java.util.ArrayList;
import java.util.List;
import androidx.activity.ComponentActivity;
/**
* 搜索目的地页面
*/
public class SearchDestinationActivity extends ComponentActivity implements Inputtips.InputtipsListener {
private static final String TAG = "SearchDestinationActivity";
public static final String EXTRA_RESULT_NAME = "result_name";
public static final String EXTRA_RESULT_ADDRESS = "result_address";
public static final String EXTRA_RESULT_LAT = "result_lat";
public static final String EXTRA_RESULT_LON = "result_lon";
public static final String EXTRA_RESULT_DISTRICT = "result_district";
// 静态回调接口
public interface DestinationCallback {
void onDestinationSelected(String name, String address, double lat, double lon, String district);
}
private static DestinationCallback callback;
public static void setCallback(DestinationCallback callback) {
SearchDestinationActivity.callback = callback;
}
private EditText searchInput;
private ListView suggestionList;
private ImageView backBtn;
private ArrayAdapter<String> suggestionAdapter;
private List<Tip> currentTipList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.activity_search_destination);
initViews();
setupListeners();
// 自动显示键盘
showKeyboard();
} catch (Exception e) {
Log.e(TAG, "Error in onCreate", e);
e.printStackTrace();
finish();
}
}
private void initViews() {
try {
Log.d(TAG, "initViews started");
searchInput = findViewById(R.id.search_input);
suggestionList = findViewById(R.id.suggestion_list);
backBtn = findViewById(R.id.back_btn);
currentTipList = new ArrayList<>();
Log.d(TAG, "initViews completed: searchInput=" + (searchInput != null ? "ok" : "null") + ", suggestionList=" + (suggestionList != null ? "ok" : "null") + ", backBtn=" + (backBtn != null ? "ok" : "null"));
} catch (Exception e) {
Log.e(TAG, "Error in initViews", e);
e.printStackTrace();
}
suggestionAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<>()) {
@Override
public View getView(int position, android.view.View convertView, android.view.ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView text = view.findViewById(android.R.id.text1);
text.setTextColor(Color.parseColor("#333333"));
text.setTextSize(14);
view.setBackgroundColor(Color.TRANSPARENT);
return view;
}
};
suggestionList.setAdapter(suggestionAdapter);
suggestionList.setDivider(new ColorDrawable(Color.LTGRAY));
suggestionList.setDividerHeight(1);
}
private void setupListeners() {
try {
Log.d(TAG, "setupListeners started");
// 返回按钮
backBtn.setOnClickListener(v -> {
Log.d(TAG, "Back button clicked");
hideKeyboard();
finish();
});
// 文本变化监听
searchInput.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) {
Log.d(TAG, "Text changed: " + (s != null ? s.toString() : "null") + ", length=" + (s != null ? s.length() : 0));
if (s.length() > 1) {
searchLocation(s.toString());
} else {
suggestionList.setVisibility(View.GONE);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
// 列表点击
suggestionList.setOnItemClickListener((parent, view, position, id) -> {
Log.d(TAG, "Suggestion clicked at position: " + position);
try {
Tip tip = currentTipList.get(position);
if (tip.getPoint() != null) {
String name = tip.getName();
String address = tip.getAddress();
String district = tip.getDistrict();
double lat = tip.getPoint().getLatitude();
double lon = tip.getPoint().getLongitude();
Log.d(TAG, "Selected destination: " + name + ", lat=" + lat + ", lon=" + lon);
// 优先使用静态回调
if (callback != null) {
callback.onDestinationSelected(name, address, lat, lon, district);
} else {
// 降级使用 Intent 回调
Intent result = new Intent();
result.putExtra(EXTRA_RESULT_NAME, name);
result.putExtra(EXTRA_RESULT_ADDRESS, address);
result.putExtra(EXTRA_RESULT_LAT, lat);
result.putExtra(EXTRA_RESULT_LON, lon);
result.putExtra(EXTRA_RESULT_DISTRICT, district);
setResult(RESULT_OK, result);
}
hideKeyboard();
finish();
}
} catch (Exception e) {
Log.e(TAG, "Error handling suggestion click", e);
e.printStackTrace();
}
});
Log.d(TAG, "setupListeners completed");
} catch (Exception e) {
Log.e(TAG, "Error in setupListeners", e);
e.printStackTrace();
}
}
private void searchLocation(String keyword) {
try {
Log.d(TAG, "Searching for: " + keyword);
InputtipsQuery query = new InputtipsQuery(keyword, "");
query.setCityLimit(false);
Inputtips inputtips = new Inputtips(this, query);
inputtips.setInputtipsListener(this);
inputtips.requestInputtipsAsyn();
} catch (Exception e) {
Log.e(TAG, "Error in searchLocation", e);
e.printStackTrace();
}
}
@Override
public void onGetInputtips(List<Tip> tipList, int rCode) {
Log.d(TAG, "onGetInputtips called, rCode=" + rCode + ", tipList size=" + (tipList != null ? tipList.size() : "null"));
if (rCode == 1000 && tipList != null && !tipList.isEmpty()) {
currentTipList.clear();
currentTipList.addAll(tipList);
List<String> 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);
}
runOnUiThread(() -> {
suggestionAdapter.clear();
suggestionAdapter.addAll(suggestionNames);
suggestionAdapter.notifyDataSetChanged();
if (suggestionNames.size() > 0) {
suggestionList.setVisibility(View.VISIBLE);
} else {
suggestionList.setVisibility(View.GONE);
}
});
} else {
runOnUiThread(() -> {
suggestionList.setVisibility(View.GONE);
});
}
}
private void showKeyboard() {
searchInput.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(searchInput, InputMethodManager.SHOW_IMPLICIT);
}
}
private void hideKeyboard() {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(searchInput.getWindowToken(), 0);
}
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
super.onPointerCaptureChanged(hasCapture);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理回调,避免内存泄漏
callback = null;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 背景颜色:使用浅灰色 -->
<solid android:color="#ffffffff" />
<!-- 圆角8dp左右 -->
<corners android:radius="8dp" />
<!-- 边框:可选,如果需要更清晰的边缘可以加上 -->
<stroke android:width="1dp" android:color="#EAEAEA" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

View File

@@ -0,0 +1,40 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,14.667C10.946,14.667 13.333,12.496 13.333,9.818C13.333,7.192 11.556,4.364 8,1.333C4.444,4.364 2.667,7.192 2.667,9.818C2.667,12.496 5.054,14.667 8,14.667Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"/>
<path
android:strokeWidth="1"
android:pathData="M6.286,6.333L8,8.123L9.714,6.333"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M6,8.719H10"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M6,10.509H10"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,8.719V12"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,41 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M3.667,1.375L2,13.375"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M12.333,1.375L13.988,13.36"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,1.375V3.375"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,11.042V13.375"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8,6.042V8.375"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,0h24v24h-24z"/>
<path
android:pathData="M6.518,10.241C4.181,10.241 2.29,12.135 2.29,14.469C2.29,16.804 6.518,21.684 6.518,21.684C6.518,21.684 10.746,16.806 10.746,14.469C10.746,12.133 8.853,10.241 6.518,10.241ZM6.518,15.616C5.853,15.616 5.313,15.077 5.313,14.411C5.313,13.745 5.853,13.206 6.518,13.206C7.184,13.206 7.723,13.745 7.723,14.411C7.723,15.077 7.181,15.616 6.518,15.616ZM19.676,2.301C18.567,2.301 17.67,3.198 17.67,4.307C17.67,5.416 19.676,7.729 19.676,7.729C19.676,7.729 21.682,5.416 21.682,4.307C21.682,3.198 20.785,2.301 19.676,2.301ZM19.676,4.851C19.36,4.851 19.104,4.595 19.104,4.279C19.104,3.963 19.36,3.707 19.676,3.707C19.992,3.707 20.248,3.963 20.248,4.279C20.246,4.595 19.99,4.851 19.676,4.851ZM18.026,13.185C17.386,12.813 16.629,12.674 15.898,12.538C14.845,12.344 14.196,12.191 14.074,11.72C14.051,11.627 14.037,11.493 14.156,11.291C14.325,11.005 14.855,10.422 16.519,9.735C16.993,9.539 17.449,9.382 17.801,9.27C18.168,9.153 18.393,8.768 18.296,8.395C18.199,8.019 17.812,7.792 17.442,7.909C17.056,8.03 16.543,8.205 15.999,8.43C14.431,9.074 13.404,9.798 12.945,10.579C12.663,11.057 12.584,11.575 12.713,12.077C12.877,12.709 13.303,13.185 13.978,13.485C14.482,13.71 15.073,13.818 15.642,13.923C16.256,14.036 16.889,14.153 17.318,14.402C17.597,14.563 17.888,14.819 17.916,15.487C17.958,16.427 16.88,17.448 14.881,18.367C13.833,18.848 12.764,19.192 12.099,19.385C11.729,19.493 11.5,19.869 11.589,20.244C11.68,20.625 12.064,20.86 12.441,20.752C13.144,20.55 14.295,20.183 15.45,19.654C16.547,19.152 17.424,18.606 18.054,18.032C18.938,17.228 19.364,16.349 19.322,15.426C19.278,14.413 18.842,13.661 18.026,13.185Z"
android:fillColor="#ffffff"/>
</group>
</vector>

View File

@@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,6.042C9.289,6.042 10.333,4.997 10.333,3.708C10.333,2.42 9.289,1.375 8,1.375C6.711,1.375 5.667,2.42 5.667,3.708C5.667,4.997 6.711,6.042 8,6.042Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M2,12.975V13.375H14V12.975C14,11.481 14,10.735 13.709,10.164C13.454,9.663 13.046,9.255 12.544,8.999C11.974,8.708 11.227,8.708 9.733,8.708H6.267C4.773,8.708 4.026,8.708 3.456,8.999C2.954,9.255 2.546,9.663 2.291,10.164C2,10.735 2,11.481 2,12.975Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M5.665,1.937C5.908,1.937 6.131,2.068 6.248,2.28L7.064,3.749C7.171,3.941 7.176,4.174 7.077,4.371L6.292,5.942C6.292,5.942 6.519,7.112 7.472,8.065C8.425,9.018 9.591,9.242 9.591,9.242L11.162,8.456C11.359,8.358 11.592,8.363 11.785,8.47L13.258,9.289C13.469,9.407 13.6,9.63 13.6,9.872V11.563C13.6,12.424 12.8,13.046 11.984,12.771C10.308,12.205 7.707,11.128 6.058,9.479C4.409,7.831 3.332,5.229 2.767,3.553C2.491,2.737 3.113,1.937 3.975,1.937H5.665Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"/>
</vector>

View File

@@ -0,0 +1,40 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,14.042C11.682,14.042 14.667,11.057 14.667,7.375C14.667,3.693 11.682,0.708 8,0.708C4.318,0.708 1.333,3.693 1.333,7.375C1.333,11.057 4.318,14.042 8,14.042Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"/>
<path
android:strokeWidth="1"
android:pathData="M6,6.708H10"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M6,8.708H10"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8.003,6.708V10.708"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M10,4.375L8,6.375L6,4.375"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

View File

@@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:strokeWidth="1"
android:pathData="M7.875,14.5C11.396,14.5 14.25,11.646 14.25,8.125C14.25,4.604 11.396,1.75 7.875,1.75C4.354,1.75 1.5,4.604 1.5,8.125C1.5,11.646 4.354,14.5 7.875,14.5Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#4E5969"/>
<path
android:strokeWidth="1"
android:pathData="M9.997,5.629C9.454,5.086 8.704,4.75 7.875,4.75C7.047,4.75 6.297,5.086 5.754,5.629"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#4E5969"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M12.458,12.707L15.64,15.889"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#4E5969"
android:strokeLineCap="round"/>
</vector>

View File

@@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M8,14.042C11.682,14.042 14.667,11.057 14.667,7.375C14.667,3.693 11.682,0.708 8,0.708C4.318,0.708 1.333,3.693 1.333,7.375C1.333,11.057 4.318,14.042 8,14.042Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"/>
<path
android:strokeWidth="1"
android:pathData="M8.003,3.375L8.003,7.378L10.829,10.204"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

View File

@@ -0,0 +1,37 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M1.333,2.042H3.667C3.667,2.042 4,3.708 5.667,3.708C7.333,3.708 7.667,2.042 7.667,2.042H14.667V12.708H7.667C7.667,12.708 7.333,11.042 5.667,11.042C4,11.042 3.667,12.708 3.667,12.708H1.333V2.042Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M5.667,5.708V6.375"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M5.667,8.375V9.042"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8.333,6.375H12"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
<path
android:strokeWidth="1"
android:pathData="M8.333,8.375H12"
android:fillColor="#00000000"
android:strokeColor="#017137"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners
android:topLeftRadius="24dp"
android:topRightRadius="24dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp" />
</shape>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:gravity="center">
<ImageView
android:id="@+id/back_btn"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="10dp"
android:src="@drawable/back" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="选择地点"
android:textColor="#000000"
android:textSize="18sp" />
</LinearLayout>
<EditText
android:id="@+id/search_input"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="12dp"
android:background="@drawable/bg_search_input"
android:hint="输入地址"
android:imeOptions="actionDone"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:singleLine="true"
android:textColor="#333333"
android:textColorHint="#999999"
android:textSize="14sp" />
<ListView
android:id="@+id/suggestion_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="8dp"
android:visibility="gone" />
</LinearLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -3,6 +3,17 @@ allprojects {
// 使用阿里云镜像
maven("https://maven.aliyun.com/repository/public")
maven("https://maven.aliyun.com/repository/google")
maven(
"https://maven.aliyun.com/nexus/content/repositories/releases/"
)
// 集成华为通道需要配置 HMS Core SDK 的 Maven地址
maven(
"https://developer.huawei.com/repo/"
)
maven(
"https://developer.hihonor.com/repo"
)
google()
mavenCentral()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -21,8 +21,41 @@
.amap-callamap,
.amap-lib-driving-callBtn,
.amap-copyright,
.amap-logo {
display: none !important;
.amap-logo{bottom: 60px}
/* 去除高德默认的 label 边框 and 背景 */
.amap-marker-label {
border: none !important;
background-color: transparent !important;
}
/* 自定义气泡样式 */
.custom-bubble {
position: relative;
background: rgba(51, 51, 51, 0.7);
/* #33333399 对应 rgba(51,51,51,0.7) */
color: #fff;
padding: 6px 15px;
border-radius: 20px;
/* 圆角 */
font-size: 13px;
white-space: nowrap;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
text-align: center;
line-height: 1.4;
}
/* 气泡下方的向下小箭头 */
.custom-bubble::after {
content: '';
position: absolute;
bottom: -6px;
/* 箭头高度 */
left: 50%;
transform: translateX(-50%);
border-width: 6px 6px 0 6px;
border-style: solid;
border-color: rgba(51, 51, 51, 0.7) transparent transparent transparent;
}
#panel .amap-call {
@@ -32,7 +65,7 @@
/* --- 搜索栏样式 --- */
#search-box {
position: absolute;
top: 10px;
top: 40px;
left: 10px;
right: 10px;
z-index: 100;
@@ -63,7 +96,7 @@
button {
padding: 0 15px;
height: 38px;
background: #3366FF;
background: #017143FF;
color: #fff;
border: none;
border-radius: 4px;
@@ -74,7 +107,7 @@
/* --- 导航结果面板 (底部弹出) --- */
#panel {
position: fixed;
bottom: 0;
bottom: 95px;
left: 0;
width: 100%;
height: 35%;
@@ -94,7 +127,7 @@
#location-btn {
position: fixed;
right: 10px;
bottom: 50px;
bottom: 105px;
/* 默认位置 */
width: 44px;
height: 44px;
@@ -121,9 +154,24 @@
fill: #555;
}
/* --- 调整比例尺位置 --- */
.amap-scalecontrol {
/* 初始状态:避开底部的定位按钮或留出安全间距 */
bottom: 110px !important;
left: 10px !important;
transition: bottom 0.3s ease;
/* 增加平滑动画 */
}
/* --- 当路径规划面板显示时,比例尺自动上移 --- */
body.panel-active .amap-scalecontrol {
bottom: 38% !important;
/* 移动到面板上方 (面板高度35% + 3%间距) */
}
/* --- 关键:当 body 有 panel-active 类时,按钮上移 --- */
body.panel-active #location-btn {
bottom: 38%;
bottom: 45%;
/* 对应 #panel 的 height + 一点间距 */
}
</style>
@@ -131,13 +179,13 @@
<!-- 1. 配置安全密钥 -->
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: '0529b72df6bf0c577ff2182cb8b1d970',
securityJsCode: 'aa3a22c19ed76b27f8a587555d6981c8',
}
</script>
<!-- 2. 加载地图和插件 (去掉了 Geolocation 插件,避免弹窗) -->
<script
src="https://webapi.amap.com/maps?v=2.0&key=2cc1d822e313307fe311c3127a1deeb5&plugin=AMap.MoveAnimation,AMap.Driving,AMap.TruckDriving,AMap.AutoComplete,AMap.ToolBar,AMap.Scale">
src="https://webapi.amap.com/maps?v=2.0&key=ecd74ece8cb14c9dad67675f83c3274d&plugin=AMap.MoveAnimation,AMap.Driving,AMap.TruckDriving,AMap.AutoComplete,AMap.ToolBar,AMap.Scale,AMap.Geocoder">
</script>
</head>
@@ -145,10 +193,10 @@
<div id="search-box">
<div class="input-row">
<input id="startInput" placeholder="起点: 请输入当前地点" />
<input id="startInput" placeholder="起点: 请输入当前地点" onfocus="this.select()" />
</div>
<div class="input-row">
<input id="endInput" placeholder="终点: 请输入目的地" />
<input id="endInput" placeholder="终点: 请输入目的地" onfocus="this.select()" />
<button onclick="startRouteSearch()">路径规划</button>
</div>
</div>
@@ -167,17 +215,25 @@
</div>
<script>
var map, marker, driving, truckDriving;
var map, marker, destMarker, driving, truckDriving, geocoder;
var currentLat, currentLng;
var isTruckMode = false;
var isInitialLocationSet = false;
var stationMarkers = []; // 存储所有站点的标记
function initMap() {
map = new AMap.Map('container', {
resizeEnable: true,
zoom: 15,
zoom: 17,
viewMode: '3D'
});
// --- 2. 初始化 geocoder ---
geocoder = new AMap.Geocoder({
city: "全国" // 设置地理编码范围
});
// 通知 Flutter 地图加载完毕
map.on('complete', function () {
console.log("JS->: Map is ready.");
@@ -186,6 +242,11 @@
}
});
// 点击地图空白处重置状态
map.on('click', function() {
resetSearchState();
});
// 添加基础控件
map.addControl(new AMap.Scale());
map.addControl(new AMap.ToolBar({
@@ -227,9 +288,23 @@
});
}
/**
* 重置搜索状态,隐藏面板和路线
*/
function resetSearchState() {
if (document.body.classList.contains('panel-active')) {
console.log("JS->: 重置地图状态");
document.body.classList.remove('panel-active');
var panel = document.getElementById('panel');
panel.style.display = 'none';
if (driving) driving.clear();
}
}
/**
* 核心功能 1: 接收 Flutter 传来的定位数据
* Flutter 端调用: webViewController.evaluateJavascript("updateMyLocation(...)")
* 纬度 经度
*/
function updateMyLocation(lat, lng, angle) {
var rawLat = parseFloat(lat);
@@ -244,18 +319,18 @@
currentLat = mPoint.lat;
var position = [currentLng, currentLat];
// 更新车辆标记位置 (保持不变)
if (!marker) {
marker = new AMap.Marker({
map: map,
position: position,
icon: "https://webapi.amap.com/images/car.png",
offset: new AMap.Pixel(-26, -13),
icon: "car.png",
offset: new AMap.Pixel(-23.5, -15),
autoRotation: true,
angle: isNaN(rawAngle) ? 0 : rawAngle,
});
map.setCenter(position);
map.setZoom(13);
} else {
marker.moveTo(position, {
duration: 1000,
@@ -263,12 +338,230 @@
});
if (!isNaN(rawAngle)) marker.setAngle(rawAngle);
}
// --- 4. 逆地理编码并设置默认起点 ---
// 只有在第一次获取到位置时,才设置默认起点,避免覆盖用户手动输入的起点
if (!isInitialLocationSet) {
geocoder.getAddress(position, function (status, result) {
if (status === 'complete' && result.regeocode) {
let shortAddress = '';
const regeo = result.regeocode;
const addressComponent = regeo.addressComponent;
const pois = regeo.pois;
console.log("地理:" + JSON.stringify(result));
fetchStationInfo(addressComponent.province, addressComponent.city,
addressComponent.district, lat, lng);
fetchStationInfoList(lat, lng);
// 策略1: 优先使用最近的、类型合适的POI的名称
if (pois && pois.length > 0) {
// 查找第一个类型不是“商务住宅”或“地名地址信息”的POI这类POI通常是具体的建筑或地点名
const significantPoi = pois.find(p => p.type.indexOf('商务住宅') === -
1 && p.type.indexOf('地名地址信息') === -1);
if (significantPoi) {
shortAddress = significantPoi.name;
} else {
// 如果找不到就用第一个POI的名字
shortAddress = pois[0].name;
}
}
// 策略2: 如果没有POI使用"道路+门牌号"
else if (addressComponent.street && addressComponent.streetNumber) {
shortAddress = addressComponent.district +
addressComponent.township +
addressComponent.street + addressComponent.streetNumber;
}
// 策略3: 如果还没有,使用"区+乡镇"
else if (addressComponent.district) {
shortAddress = addressComponent.district + (addressComponent
.township || '');
}
// 策略4: 降级到使用完整的、但可能很长的地址
else {
shortAddress = regeo.formattedAddress;
}
// 如果拼接出的地址过长,可以再做一次截断
if (shortAddress.length > 20) {
// 可以在这里添加更复杂的截断逻辑,比如按关键字
shortAddress = regeo.formattedAddress.substring(0, 20) + '...';
}
// 将获取到的地址填充到起点输入框
document.getElementById('startInput').value = shortAddress;
isInitialLocationSet = true; // 标记为已设置,不再更新
} else {
// 如果逆地理编码失败,依然使用“当前位置”作为提示
document.getElementById('startInput').placeholder = "当前位置";
console.error('逆地理编码失败:', result);
}
});
}
}
});
}
/**
* 核心功能 2: 点击按钮回到当前位置
* 调用后端接口获取站点
*/
function fetchStationInfo(province, city, district, lat, lng) {
// 注意:某些直辖市在高德中 city 字段可能为空,需做兼容处理
console.log("JS->: 开始请求." + province + city + district);
var cityName = (typeof city === 'string' && city.length > 0) ? city : province;
fetch('https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
province: province,
city: cityName,
district: district,
longitude: lng,
latitude: lat,
})
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应错误: ' + response.status);
}
return response.json(); // 解析 JSON
})
.then(res => {
// 打印完整的返回结果,方便调试观察结构
console.log("JS->: 接口完整返回:", JSON.stringify(res));
// 安全校验:判断 res.data 是否存在
if (res.code === 0 && res.data) {
if (res.data.address) {
console.log("JS->: 找到地址:", res.data.address);
var destAddress = res.data.address;
document.getElementById('endInput').value = destAddress;
// 标记终点
markDestination(destAddress, res.data.name || "目的地",
res.data.longitude, res.data.latitude
);
} else {
console.log("JS->: 接口请求成功,但该区域暂无站点地址");
}
} else {
console.log("JS->: 业务报错或无数据:", res.message);
}
})
.catch(err => console.error('JS->:获取站点信息失败:', err));
}
/**
* 获取站点列表
*/
function fetchStationInfoList(lat, lng) {
fetch('https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
longitude: lng,
latitude: lat,
})
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应错误: ' + response.status);
}
return response.json(); // 解析 JSON
})
.then(res => {
console.log("JS->:2 接口完整返回:", JSON.stringify(res));
if (res.code === 0 && res.data && Array.isArray(res.data)) {
// 1. 清除旧的站点标记
stationMarkers.forEach(m => m.setMap(null));
stationMarkers = [];
// 2. 循环标记所有加氢站
res.data.forEach(station => {
var stationIcon = new AMap.Icon({
size: new AMap.Size(32, 32),
image: 'ic_tag.png',
imageSize: new AMap.Size(32, 32)
});
var sMarker = new AMap.Marker({
map: map,
position: [station.longitude, station.latitude],
icon: stationIcon,
offset: new AMap.Pixel(-16, -32),
title: station.name,
label: {
content: '<div class="custom-bubble">' + station.name +
'</div>',
direction: 'top'
}
});
// 3. 绑定点击事件:选中即为目的地,并开始规划
sMarker.on('click', function () {
var stationName = station.name || "目的地";
document.getElementById('endInput').value = station.address ||
stationName;
// 更新当前的 destMarker
if (destMarker && destMarker !== sMarker) destMarker.setMap(null);
destMarker = sMarker;
// 直接传入坐标对象,避免关键字搜索失败
var loc = new AMap.LngLat(station.longitude, station.latitude);
startRouteSearch(loc);
});
stationMarkers.push(sMarker);
});
} else {
console.log("JS->: 业务报错或无数据:", res.message);
}
})
.catch(err => console.error('JS->:获取站点信息失败:', err));
}
/**
* 地理编码并在地图标记终点
*/
function markDestination(address, name, longitude, latitude) {
// 1. 清除旧的终点标记
if (destMarker) destMarker.setMap(null);
// 2. 创建自定义图标
var destIcon = new AMap.Icon({
size: new AMap.Size(32, 32), // 图标尺寸
image: 'ic_tag.png', // 本地图片路径
imageSize: new AMap.Size(32, 32) // 图片在图标内拉伸的大小
});
// 3. 创建标记
destMarker = new AMap.Marker({
map: map,
position: [longitude, latitude],
icon: destIcon, // 使用自定义图标
offset: new AMap.Pixel(-16, -32),
title: name,
label: {
content: '<div class="custom-bubble">' + name + '</div>',
direction: 'top'
}
});
console.log("JS->: 终点标记已添加", address);
}
/**
* 点击按钮回到当前位置
*/
function backToLocation() {
if (currentLng && currentLat) {
@@ -283,11 +576,12 @@
}
}
/**
* 核心功能 3: 路径规划
* 路径规划
* @param {AMap.LngLat} [destLoc] 可选的终点坐标
*/
function startRouteSearch() {
// 获取输入框的文字
function startRouteSearch(destLoc) {
var startKw = document.getElementById('startInput').value;
var endKw = document.getElementById('endInput').value;
@@ -295,63 +589,59 @@
alert("请输入起点");
return;
}
if (!endKw) {
alert("请输入终点");
return;
}
// 清除旧路线
if (driving) driving.clear();
// 收起键盘
document.getElementById('startInput').blur();
document.getElementById('endInput').blur();
// --- 构造路径规划的点 (使用数组方式,更灵活) ---
var points = [];
// 1. 处理起点逻辑
// 如果输入框是空的,或者写着 "我的位置",则使用 GPS 坐标
if (!startKw || startKw === '我的位置') {
// 1. 起点逻辑
if (!startKw || startKw === '我的位置' || startKw.includes('当前位置')) {
if (!currentLng || !currentLat) {
// 如果还没获取到定位
if (window.flutter_inappwebview) {
window.flutter_inappwebview.callHandler('requestLocation');
}
if (window.flutter_inappwebview) window.flutter_inappwebview.callHandler('requestLocation');
alert("正在获取定位,请稍后...");
return;
}
// 使用精准坐标对象 (避免高德去猜 '我的位置' 关键词)
points.push({
keyword: '我的位置', // 用于显示的名字
location: new AMap.LngLat(currentLng, currentLat) // 实际导航用的坐标
keyword: '我的位置',
location: new AMap.LngLat(currentLng, currentLat)
});
} else {
// 如果用户手动输入了地点 (例如 "北京南站")
// 直接存入关键词,让高德自己去搜
points.push({
keyword: startKw
});
}
// 2. 处理终点逻辑 (通常是关键词)
points.push({
keyword: endKw
});
// 2. 终点逻辑:如果有传入坐标,则直接使用坐标导航,成功率最高
if (destLoc) {
points.push({
keyword: endKw,
location: destLoc // 关键:使用精确坐标
});
} else {
points.push({
keyword: endKw
});
}
// 3. 发起搜索
// points 数组里现在是一个起点对象和一个终点对象
driving.search(points, function (status, result) {
if (status === 'complete') {
console.log('JS: 规划成功');
var panel = document.getElementById('panel');
panel.style.display = 'block';
document.body.classList.add('panel-active');
} else {
console.log('JS: 规划失败', result);
alert("规划失败,请检查起终点名称");
}
// else {
// console.error('JS: 规划失败', result);
// // 如果坐标规划都失败了,通常是由于起终点距离过近或政策限制(如货车禁行)
// alert("路径规划未成功,请尝试微调起终点");
// }
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

View File

@@ -0,0 +1,51 @@
#
# 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/<TWITTER_USERNAME>'
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'
s.dependency 'MBProgressHUD'
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>0A2A.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More