Compare commits
172 Commits
88b24b5228
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e79d8039c | |||
| 2523899ec4 | |||
| 853a9135c8 | |||
| ec96a96be2 | |||
|
|
0ba9547992 | ||
| c6e7616be2 | |||
| eae654c47e | |||
| f01875abb9 | |||
| 881da166d1 | |||
| 14b2e6b35c | |||
| 20c39a4a12 | |||
|
|
5c74c7ccc0 | ||
| 23fc0da5c8 | |||
| 7efd933416 | |||
| 2b33dac384 | |||
| ef60b8ed62 | |||
| bec6952707 | |||
| f68349a208 | |||
|
|
08dcc64ef4 | ||
| 9242dcaf70 | |||
| 95fdfe6269 | |||
| ee88b3ada9 | |||
| ba27799c41 | |||
| c527732532 | |||
| cd223fa9bf | |||
| fdd6653fce | |||
| 8748a60f7f | |||
|
|
5843ef6e87 | ||
| 0123025296 | |||
| 587dd48896 | |||
| 569780ffb4 | |||
| 3aac4e7330 | |||
| b275c66383 | |||
| bf80931f37 | |||
| 67c36f436c | |||
| c10c92afdc | |||
| d3edf95df3 | |||
| 930953780d | |||
| a497bc6469 | |||
| 3f282d15c1 | |||
| 03b35f660c | |||
| 9b6f93ca95 | |||
| eb41ecaec4 | |||
| 384de27f2c | |||
| 84b174c4a5 | |||
| cd14469d79 | |||
| b846d352a2 | |||
|
|
a24f41a8d5 | ||
|
|
65b4a3ac34 | ||
| 02e1946319 | |||
| d5083c1939 | |||
| fe44848529 | |||
| 572c416827 | |||
| 8df16f0787 | |||
| ce6bd3edd2 | |||
| 6997b4ac9e | |||
| a26d2478f3 | |||
| 0dded3b928 | |||
| b7caf58adf | |||
| 0df1902df2 | |||
| a8314d8a7a | |||
| 39cae906e9 | |||
| 14fd6c75d0 | |||
| 1724852a39 | |||
| a05d4ebb9b | |||
| 600cea4379 | |||
| 3dfc1dfc2c | |||
| 909dc95771 | |||
| cf0896453b | |||
| dce9718320 | |||
| 4491aa9b91 | |||
| 5364612a6f | |||
| 10867178fa | |||
| a5e2a89e4f | |||
| 26c5f9d67a | |||
| 9cd87b0535 | |||
| 45e45d8160 | |||
| 87e890f97e | |||
| dcf925b8c1 | |||
| c45863eda6 | |||
| 756bf53cf5 | |||
| f68c2d0938 | |||
| 211d0225e4 | |||
| 7d9b4d99e8 | |||
| 3dd583a278 | |||
| 35bd3a78a5 | |||
| 1278c38b7e | |||
| 032e60d362 | |||
| 171f556b40 | |||
| 55eade54b6 | |||
| bc99ffd691 | |||
| aa52a56bcf | |||
| 73343ca297 | |||
| d09faac1d2 | |||
| 1177be821a | |||
| e59b89c225 | |||
| 79fe3257b5 | |||
| 55569839a7 | |||
| 7112d70aba | |||
| f8a8ecb0ed | |||
| 18c04272e2 | |||
| 14e7fb3d78 | |||
| 5ffaf81223 | |||
| 907983a1d1 | |||
| 9fdca9136d | |||
| 16bae6a1e9 | |||
| aabfbfae0c | |||
| 5236670e7c | |||
| cf3ad579d3 | |||
| 70a752b6e5 | |||
| 45f5035d1b | |||
| f792915429 | |||
| edbacc502b | |||
| 5722e3ace0 | |||
| d41b21654a | |||
| 2eb059defd | |||
| fbcc85af2a | |||
| 9a97b56505 | |||
| 8302d7c179 | |||
| e7a9e4483a | |||
| 9b64fdfa52 | |||
| d8f335eb4e | |||
| d1b7a9eb76 | |||
| f25feaa55a | |||
| 16639e2384 | |||
| 20ef495571 | |||
| 285a20f070 | |||
| baee5dba83 | |||
| 7d9c879a4e | |||
| 953e5e773c | |||
| 8a4bc1d1ab | |||
| c57c849073 | |||
| 6cc123f272 | |||
| 5168b23609 | |||
| c5299dd655 | |||
| 4bedd8c04b | |||
| 295b71c819 | |||
| 6629c8047f | |||
| bfa615a7f4 | |||
| 288d629f99 | |||
| 15fdbc7043 | |||
| f2f2348b54 | |||
| 9ba152b3c3 | |||
| 21a528d6d1 | |||
| 62ca3888d3 | |||
| 3ec56a925c | |||
| 95c08818cb | |||
| 42355bd1ef | |||
| fe2ce75cec | |||
| 98cac8a0a5 | |||
| 9ce46a0c7d | |||
| 266a43c09d | |||
| 8434301d1f | |||
| adfe3bf34e | |||
| 6a3c6db7a8 | |||
| 4ace3c9f27 | |||
| b52659df6c | |||
| 20877a3eb1 | |||
| 69875f27ad | |||
| 829f5e454e | |||
| 1c916a7fad | |||
| f638704fba | |||
| 4c63d5ebf3 | |||
| a3fb0d8018 | |||
| 88b16ca69e | |||
| ba3467810c | |||
| 0bfedd54cb | |||
| f25d7e4567 | |||
| 4cdedff654 | |||
| 4f99ab4164 | |||
| cdc5af7f45 | |||
| 20e5e58ded |
8
ln_jq_app/.claude/settings.local.json
Normal 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)"
|
||||
]
|
||||
}
|
||||
}
|
||||
7
ln_jq_app/android/.claude/settings.local.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(./gradlew assembleDebug --stacktrace)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
88
ln_jq_app/android/app/proguard-rules.pro
vendored
Normal 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.**{*;}
|
||||
@@ -1,11 +1,14 @@
|
||||
<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" />
|
||||
@@ -14,20 +17,54 @@
|
||||
<!--定位权限-->
|
||||
<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"/>
|
||||
<!--用于申请调用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
|
||||
@@ -35,8 +72,7 @@
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
android:resource="@style/NormalTheme" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -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安全,建议设置不可导出,如需对其他应用开放可通过android:permission进行限制 -->
|
||||
<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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
BIN
ln_jq_app/android/app/src/main/res/drawable/back.png
Normal file
|
After Width: | Height: | Size: 705 B |
@@ -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>
|
||||
BIN
ln_jq_app/android/app/src/main/res/drawable/car.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
ln_jq_app/android/app/src/main/res/drawable/ic_close.png
Normal file
|
After Width: | Height: | Size: 880 B |
40
ln_jq_app/android/app/src/main/res/drawable/ic_fuel.xml
Normal 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>
|
||||
BIN
ln_jq_app/android/app/src/main/res/drawable/ic_location.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
ln_jq_app/android/app/src/main/res/drawable/ic_marker.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
41
ln_jq_app/android/app/src/main/res/drawable/ic_mileage.xml
Normal 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>
|
||||
13
ln_jq_app/android/app/src/main/res/drawable/ic_path.xml
Normal 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>
|
||||
20
ln_jq_app/android/app/src/main/res/drawable/ic_person.xml
Normal 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>
|
||||
12
ln_jq_app/android/app/src/main/res/drawable/ic_phone.xml
Normal 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>
|
||||
40
ln_jq_app/android/app/src/main/res/drawable/ic_price.xml
Normal 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>
|
||||
26
ln_jq_app/android/app/src/main/res/drawable/ic_search.xml
Normal 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>
|
||||
19
ln_jq_app/android/app/src/main/res/drawable/ic_time.xml
Normal 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>
|
||||
37
ln_jq_app/android/app/src/main/res/drawable/ic_toll.xml
Normal 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>
|
||||
BIN
ln_jq_app/android/app/src/main/res/drawable/ic_un_marker.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
@@ -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>
|
||||
@@ -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>
|
||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -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()
|
||||
}
|
||||
|
||||
BIN
ln_jq_app/assets/html/car.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
ln_jq_app/assets/html/ic_tag.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
@@ -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. 处理终点逻辑 (通常是关键词)
|
||||
// 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("路径规划未成功,请尝试微调起终点");
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BIN
ln_jq_app/assets/images/android_apk_img.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
ln_jq_app/assets/images/bg_login.png
Normal file
|
After Width: | Height: | Size: 501 KiB |
BIN
ln_jq_app/assets/images/bg_map@2x.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
ln_jq_app/assets/images/history_bg.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
ln_jq_app/assets/images/ic_attention@2x.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
ln_jq_app/assets/images/ic_car@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ln_jq_app/assets/images/ic_car_bg@2x.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
ln_jq_app/assets/images/ic_car_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ln_jq_app/assets/images/ic_close@2x.png
Normal file
|
After Width: | Height: | Size: 892 B |
BIN
ln_jq_app/assets/images/ic_ex_menu@2x.png
Normal file
|
After Width: | Height: | Size: 394 B |
BIN
ln_jq_app/assets/images/ic_h2@2x.png
Normal file
|
After Width: | Height: | Size: 914 B |
BIN
ln_jq_app/assets/images/ic_h2_my@2x.png
Normal file
|
After Width: | Height: | Size: 947 B |
BIN
ln_jq_app/assets/images/ic_h2_my_select@2x.png
Normal file
|
After Width: | Height: | Size: 594 B |
BIN
ln_jq_app/assets/images/ic_h2_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
ln_jq_app/assets/images/ic_jqz@2x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
ln_jq_app/assets/images/ic_label@2x.png
Normal file
|
After Width: | Height: | Size: 638 B |
BIN
ln_jq_app/assets/images/ic_login_bg@2x.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
ln_jq_app/assets/images/ic_logo@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ln_jq_app/assets/images/ic_logo_unbg@2x.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
ln_jq_app/assets/images/ic_mall@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ln_jq_app/assets/images/ic_mall_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ln_jq_app/assets/images/ic_map@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ln_jq_app/assets/images/ic_map_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ln_jq_app/assets/images/ic_no_data@2x.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
ln_jq_app/assets/images/ic_pj@2x.png
Normal file
|
After Width: | Height: | Size: 779 B |
BIN
ln_jq_app/assets/images/ic_px@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ln_jq_app/assets/images/ic_serch@2x.png
Normal file
|
After Width: | Height: | Size: 636 B |
BIN
ln_jq_app/assets/images/ic_upload@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
ln_jq_app/assets/images/ic_user@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ln_jq_app/assets/images/ic_user_logo@2x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
ln_jq_app/assets/images/ic_user_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ln_jq_app/assets/images/ic_wz@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ln_jq_app/assets/images/mall_bar@2x.png
Normal file
|
After Width: | Height: | Size: 896 B |
BIN
ln_jq_app/assets/images/mall_pay_success@2x.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
ln_jq_app/assets/images/rule_bg@2x.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
ln_jq_app/assets/images/rule_bg_1@2x.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
ln_jq_app/assets/images/tips_1@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ln_jq_app/assets/images/tips_2@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ln_jq_app/assets/images/tips_3@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ln_jq_app/assets/images/tips_4@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ln_jq_app/assets/images/tips_5@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ln_jq_app/assets/images/welcome.png
Normal file
|
After Width: | Height: | Size: 545 KiB |
51
ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK.podspec
Normal 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
|
||||
|
After Width: | Height: | Size: 966 B |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 844 B |
|
After Width: | Height: | Size: 792 B |
|
After Width: | Height: | Size: 909 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 864 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 840 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 829 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -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>
|
||||