Commit d873167a authored by p x's avatar p x
Browse files

增加点串判断用例

parent 3c1fafd6
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-06-11T06:55:43.863682Z"> <DropdownSelection timestamp="2026-01-16T06:30:04.853123900Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=1198d45e9f92b317" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=e21e375a" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>
......
...@@ -38,6 +38,18 @@ android { ...@@ -38,6 +38,18 @@ android {
buildFeatures { buildFeatures {
dataBinding = true dataBinding = true
} }
applicationVariants.all {
outputs.all {
if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
val config = project.android.defaultConfig
val versionName = config.versionName
// val formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd_HHmm")
// val createTime = LocalDateTime.now().format(formatter)
// outputFileName = "Greey_${buildType.name}_${versionName}.apk"
outputFileName = "avp_greey.apk"
}
}
}
} }
dependencies { dependencies {
......
...@@ -18,4 +18,25 @@ ...@@ -18,4 +18,25 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
\ No newline at end of file
#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.loc.**{*;}
-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.**{*;}
\ No newline at end of file
...@@ -2,12 +2,34 @@ ...@@ -2,12 +2,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!--允许获取精确位置,精准定位必选-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--允许获取粗略位置,粗略定位必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--后台获取位置信息,若需后台定位则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许写设备缓存,用于问题排查-->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_OWNER_DATA" />
<uses-permission <uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" /> tools:ignore="ScopedStorage" />
...@@ -23,7 +45,17 @@ ...@@ -23,7 +45,17 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.GeelyHMIWeb" android:theme="@style/Theme.GeelyHMIWeb"
android:requestLegacyExternalStorage="true"
tools:targetApi="31"> tools:targetApi="31">
<!-- b29a0ea92384d99bf2dcc9a9dbdbeb78-->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="b29a0ea92384d99bf2dcc9a9dbdbeb78" />
<service android:name="com.amap.api.location.APSService" />
<activity <activity
android:name=".ui.BootActivity" android:name=".ui.BootActivity"
android:exported="true"> android:exported="true">
...@@ -42,8 +74,7 @@ ...@@ -42,8 +74,7 @@
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation" android:configChanges="orientation"
android:exported="true" android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask">
>
</activity> </activity>
......
...@@ -4,31 +4,36 @@ import android.webkit.JavascriptInterface ...@@ -4,31 +4,36 @@ import android.webkit.JavascriptInterface
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.sd.geelyhmiweb.dsbridge.CompletionHandler import com.sd.geelyhmiweb.dsbridge.CompletionHandler
import com.sd.geelyhmiweb.utils.LocationUtils import com.sd.geelyhmiweb.utils.LocationUtils
import com.sd.geelyhmiweb.viewmodels.AMapLoc
import com.sd.geelyhmiweb.viewmodels.MainVM import com.sd.geelyhmiweb.viewmodels.MainVM
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
class JsApi { class JsApi {
var mainVM: MainVM? = null var mainVM: MainVM? = null
var aMapLoc: AMapLoc? = null
//定位字符串
var locStr = MutableLiveData("")
//JS点击开始定位
var jsStartLoc = MutableSharedFlow<String>()
/***开始定位 js 调用 Android 获取位置**/
@JavascriptInterface @JavascriptInterface
fun synLoc(arg: Any, handler: CompletionHandler<String>) { fun synLoc(arg: Any, handler: CompletionHandler<String>) {
LocationUtils.getInstan().onJsLoc = object : LocationUtils.OnJsLoc { // println("--------开始定位 js 调用 Android 获取位置")
override fun onJsLoc(str: String) { // LocationUtils.getInstan().getLocation()
// handler.complete(str); CoroutineScope(Dispatchers.Main).launch {
// Log.d("------------js 调用 Android 获取异步位置=", str); jsStartLoc.emit("1")
locStr.postValue(str)
}
} }
LocationUtils.getInstan().getLocation()
} }
@JavascriptInterface @JavascriptInterface
fun stopLoc(arg: Any?) { fun stopLoc(arg: Any?) {
LocationUtils.getInstan().stopLoc() // LocationUtils.getInstan().stopLoc()
} }
@JavascriptInterface @JavascriptInterface
......
...@@ -3,6 +3,7 @@ package com.sd.geelyhmiweb ...@@ -3,6 +3,7 @@ package com.sd.geelyhmiweb
import android.net.http.SslError import android.net.http.SslError
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.KeyEvent
import android.webkit.ConsoleMessage import android.webkit.ConsoleMessage
import android.webkit.SslErrorHandler import android.webkit.SslErrorHandler
import android.webkit.WebChromeClient import android.webkit.WebChromeClient
...@@ -12,23 +13,38 @@ import android.webkit.WebSettings ...@@ -12,23 +13,38 @@ import android.webkit.WebSettings
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.webkit.WebResourceErrorCompat import androidx.webkit.WebResourceErrorCompat
import androidx.webkit.WebViewAssetLoader import androidx.webkit.WebViewAssetLoader
import androidx.webkit.WebViewClientCompat import androidx.webkit.WebViewClientCompat
import com.sd.geelyhmiweb.databinding.ActivityMainBinding import com.sd.geelyhmiweb.databinding.ActivityMainBinding
import com.sd.geelyhmiweb.dsbridge.OnReturnValue import com.sd.geelyhmiweb.dsbridge.OnReturnValue
import com.sd.geelyhmiweb.utils.LocationUtils
import com.sd.geelyhmiweb.utils.MyContants import com.sd.geelyhmiweb.utils.MyContants
import com.sd.geelyhmiweb.viewmodels.AMapLoc
import com.sd.geelyhmiweb.viewmodels.MainVM import com.sd.geelyhmiweb.viewmodels.MainVM
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
override fun onStart() {
super.onStart()
// aMapLoc.startLocation()
}
override fun onStop() {
super.onStop()
//停止定位
aMapLoc.stopLocation()
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
LocationUtils.getInstan().stopLoc() aMapLoc.destroyLocation()
binding.dwebview.destroy() binding.dwebview.destroy()
} }
...@@ -40,15 +56,18 @@ class MainActivity : AppCompatActivity() { ...@@ -40,15 +56,18 @@ class MainActivity : AppCompatActivity() {
private val jsApi = JsApi() private val jsApi = JsApi()
// private val myLocVM: MyLocVM by viewModels()
private val aMapLoc: AMapLoc by viewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
LocationUtils.setLocManager(this) aMapLoc.initLocation()
aMapLoc.startLocation()
// LocationUtils.getInstan().getLocation()
jsApi.mainVM = mainVM jsApi.mainVM = mainVM
jsApi.aMapLoc = aMapLoc
initWeb() initWeb()
initLis() initLis()
} }
...@@ -94,6 +113,7 @@ class MainActivity : AppCompatActivity() { ...@@ -94,6 +113,7 @@ class MainActivity : AppCompatActivity() {
var url = if (MyContants.LOAD_WEB_FILE == 1) { var url = if (MyContants.LOAD_WEB_FILE == 1) {
"file:///android_asset/dist/index.html" "file:///android_asset/dist/index.html"
// "http://192.168.60.155:5100/#/login"
} else { } else {
websiteUrl websiteUrl
} }
...@@ -110,11 +130,11 @@ class MainActivity : AppCompatActivity() { ...@@ -110,11 +130,11 @@ class MainActivity : AppCompatActivity() {
// headers.put("sec-ch-ua-platform", "") // headers.put("sec-ch-ua-platform", "")
// headers.put("","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0") // headers.put("","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0")
// 优先拦截虚拟域名请求 // 优先拦截虚拟域名请求
if (MyContants.LOAD_WEB_FILE==1){ if (MyContants.LOAD_WEB_FILE == 1) {
return super.shouldInterceptRequest(view, request) return super.shouldInterceptRequest(view, request)
}else if (MyContants.LOAD_WEB_FILE==2){ } else if (MyContants.LOAD_WEB_FILE == 2) {
return assetLoader.shouldInterceptRequest(request.url) return assetLoader.shouldInterceptRequest(request.url)
}else{ } else {
return assetLoader.shouldInterceptRequest(request.url) return assetLoader.shouldInterceptRequest(request.url)
} }
} }
...@@ -143,36 +163,60 @@ class MainActivity : AppCompatActivity() { ...@@ -143,36 +163,60 @@ class MainActivity : AppCompatActivity() {
// super.onReceivedSslError(view, handler, error) // super.onReceivedSslError(view, handler, error)
handler?.cancel() handler?.cancel()
} }
} }
binding.dwebview.webChromeClient = object : WebChromeClient() { binding.dwebview.webChromeClient = object : WebChromeClient() {
override fun onConsoleMessage(message: ConsoleMessage?): Boolean { override fun onConsoleMessage(message: ConsoleMessage?): Boolean {
Log.d( /* Log.d(
"---onConsoleMessage ", "---onConsoleMessage ",
"${message?.message()} -- From line " + "${message?.lineNumber()} of ${message?.sourceId()}" "${message?.message()} -- From line " + "${message?.lineNumber()} of ${message?.sourceId()}"
) )*/
return true return true
} }
} }
} }
private fun initLis() { private fun initLis() {
jsApi.locStr.observe(this) { lifecycleScope.launch {
// handler.complete(str); repeatOnLifecycle(Lifecycle.State.STARTED) {
// Log.d("------------上报异步位置", it) jsApi.jsStartLoc.collect {
println("--------开始定位 js 调用 Android 获取位置")
aMapLoc.startLocation()
}
}
}
aMapLoc.myLocValue.observe(this) { myLoc ->
var locStr =
"${myLoc.lng} ${myLoc.lat} ${myLoc.bearing} ${myLoc.altitude}"
println("------传给前端的: ${locStr}")
binding.dwebview.callHandler( binding.dwebview.callHandler(
"retLoc", arrayOf<String>(it), "retLoc", arrayOf<String>(locStr),
OnReturnValue<String> { retValue -> OnReturnValue<String> { retValue ->
/* Log.d( Log.d(
"---jsbridge", "---jsbridge",
"call succeed,return value is $retValue" "call succeed,return value is $retValue"
)*/ )
}) })
} }
} }
/* override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK) || event.getKeyCode() == KeyEvent.KEYCODE_HOME) {
val webView = binding.dwebview
// 优先让WebView返回
if (webView.canGoBack()) {
webView.goBack()
return true
} else {
return super.dispatchKeyEvent(event)
}
} else {
return super.dispatchKeyEvent(event)
}
}*/
} }
\ No newline at end of file
package com.sd.geelyhmiweb.bean
class MyLoc {
var lat = 0.0
var lng = 0.0
var speed = 0.0f
//角度
var bearing = 0.0f
//高度
var altitude = 0.0
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import android.content.Intent ...@@ -5,6 +5,7 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.amap.api.location.AMapLocationClient
import com.permissionx.guolindev.PermissionX import com.permissionx.guolindev.PermissionX
import com.sd.geelyhmiweb.MainActivity import com.sd.geelyhmiweb.MainActivity
import com.sd.geelyhmiweb.databinding.ActivityBootBinding import com.sd.geelyhmiweb.databinding.ActivityBootBinding
...@@ -21,6 +22,8 @@ class BootActivity : AppCompatActivity() { ...@@ -21,6 +22,8 @@ class BootActivity : AppCompatActivity() {
binding = ActivityBootBinding.inflate(layoutInflater) binding = ActivityBootBinding.inflate(layoutInflater)
// enableEdgeToEdge() // enableEdgeToEdge()
setContentView(binding.root) setContentView(binding.root)
AMapLocationClient.updatePrivacyShow(this, true, true)
AMapLocationClient.updatePrivacyAgree(this, true)
requestPers() requestPers()
} }
...@@ -35,7 +38,9 @@ class BootActivity : AppCompatActivity() { ...@@ -35,7 +38,9 @@ class BootActivity : AppCompatActivity() {
private fun requestPers() { private fun requestPers() {
val pers = mutableListOf( val pers = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE
) )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
pers.add(Manifest.permission.READ_EXTERNAL_STORAGE) pers.add(Manifest.permission.READ_EXTERNAL_STORAGE)
...@@ -70,4 +75,10 @@ class BootActivity : AppCompatActivity() { ...@@ -70,4 +75,10 @@ class BootActivity : AppCompatActivity() {
} }
} }
\ No newline at end of file
/*
*MD5: 85:D7:46:90:81:07:55:A5:5E:6B:0C:0D:82:E8:F7:69
SHA1: 4F:71:B6:3B:0B:E6:37:33:9E:55:BF:EA:EA:62:70:8B:CD:77:6F:B2
*
*/
package com.sd.geelyhmiweb.utils;
/**
* 提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
*
* @author Daniel
* @since 2016/7/27 0027
*/
public class CoordinateTransformUtils {
private static final double x_PI = 3.14159265358979324 * 3000.0 / 180.0;
private static final double PI = 3.1415926535897932384626;
private static final double a = 6378245.0;
private static final double ee = 0.00669342162296594323;
/**
* 百度坐标(BD09)转 GCJ02
*
* @param lng 百度经度
* @param lat 百度纬度
* @return GCJ02 坐标:[经度,纬度]
*/
public static double[] transformBD09ToGCJ02(double lng, double lat) {
double x = lng - 0.0065;
double y = lat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
double gcj_lng = z * Math.cos(theta);
double gcj_lat = z * Math.sin(theta);
return new double[]{gcj_lng, gcj_lat};
}
/**
* GCJ02 转百度坐标
*
* @param lng GCJ02 经度
* @param lat GCJ02 纬度
* @return 百度坐标:[经度,纬度]
*/
public static double[] transformGCJ02ToBD09(double lng, double lat) {
double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
double bd_lng = z * Math.cos(theta) + 0.0065;
double bd_lat = z * Math.sin(theta) + 0.006;
return new double[]{bd_lng, bd_lat};
}
/**
* GCJ02 转 WGS84
*
* @param lng 经度
* @param lat 纬度
* @return WGS84坐标:[经度,纬度]
*/
public static double[] transformGCJ02ToWGS84(double lng, double lat) {
if (outOfChina(lng, lat)) {
return new double[]{lng, lat};
} else {
double dLat = transformLat(lng - 105.0, lat - 35.0);
double dLng = transformLng(lng - 105.0, lat - 35.0);
double radLat = lat / 180.0 * PI;
double magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = lat + dLat;
double mgLng = lng + dLng;
return new double[]{lng * 2 - mgLng, lat * 2 - mgLat};
}
}
/**
* WGS84 坐标 转 GCJ02
*
* @param lng 经度
* @param lat 纬度
* @return GCJ02 坐标:[经度,纬度]
*/
public static double[] transformWGS84ToGCJ02(double lng, double lat) {
if (outOfChina(lng, lat)) {
return new double[]{lng, lat};
} else {
double dLat = transformLat(lng - 105.0, lat - 35.0);
double dLng = transformLng(lng - 105.0, lat - 35.0);
double redLat = lat / 180.0 * PI;
double magic = Math.sin(redLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(redLat) * PI);
double mgLat = lat + dLat;
double mgLng = lng + dLng;
return new double[]{mgLng, mgLat};
}
}
/**
* 百度坐标BD09 转 WGS84
*
* @param lng 经度
* @param lat 纬度
* @return WGS84 坐标:[经度,纬度]
*/
public static double[] transformBD09ToWGS84(double lng, double lat) {
double[] lngLat = transformBD09ToGCJ02(lng, lat);
return transformGCJ02ToWGS84(lngLat[0], lngLat[1]);
}
/**
* WGS84 转 百度坐标BD09
*
* @param lng 经度
* @param lat 纬度
* @return BD09 坐标:[经度,纬度]
*/
public static double[] transformWGS84ToBD09(double lng, double lat) {
double[] lngLat = transformWGS84ToGCJ02(lng, lat);
return transformGCJ02ToBD09(lngLat[0], lngLat[1]);
}
private static double transformLat(double lng, double lat) {
double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
;
private static double transformLng(double lng, double lat) {
double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
;
/**
* 判断坐标是否不在国内
*
* @param lng 经度
* @param lat 纬度
* @return 坐标是否在国内
*/
public static boolean outOfChina(double lng, double lat) {
return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271);
}
public static void main(String[] args) {
/* //工具转换结果116.4732071375548,39.9932029943646
//高德转换结果116.473207,39.993202
double[] re = transformWGS84ToGCJ02(116.46706996, 39.99188446);
//hutool工具偏差较大
CoordinateUtil.Coordinate p=CoordinateUtil.wgs84ToGcj02(116.46706996, 39.99188446);
System.out.println(p.getLng() + "," + p.getLat());
//工具转换结果116.47325695920523,39.99316293714061
//高德转换结果116.473256,39.993164
//re= transformBD09ToGCJ02(116.4798674287,39.9989020876);
//工具转换结果116.33993249456921,39.997903976430734
//百度转换结果116.33993794568,39.9979082195
//re= transformWGS84ToBD09(116.32715863448607,39.990912172420714);
System.out.println(re[0] + "," + re[1]);
double[] p1 = transformGCJ02ToWGS84(116.368904, 39.923423);
double[] p2 = transformGCJ02ToWGS84(116.387271, 39.922501);
System.out.println(DistanceUtil.getDistance1(116.368904, 39.923423, 116.387271, 39.922501));
System.out.println(DistanceUtil.getDistance1(p1[0], p1[1], p2[0], p2[1]));
p1 = transformWGS84ToBD09(p1[0], p1[1]);
System.out.println(p1[0] + "," + p1[1]);
p2 = transformWGS84ToBD09(p2[0], p2[1]);
System.out.println(p2[0] + "," + p2[1]);
List<Double[]> points =new ArrayList<>();
points.add(new Double[]{p1[0], p1[1]});
points.add(new Double[]{p2[0], p2[1]});
LineString line = JtsUtils.createLineStringWithPoints(points);
Double len = JtsUtils.getMeterLength(line);
System.out.println(len);
p1 = transformBD09ToWGS84(116.347227, 39.894908);
p2 = transformBD09ToWGS84(116.447549, 39.898229);
System.out.println(DistanceUtil.getDistance(p1[0], p1[1], p2[0], p2[1]));*/
}
}
package com.sd.geelyhmiweb.utils;
/**
* 星际旅行概论(坐标系偏移工具类)
* 支持GC02、BD09和WGS84坐标系之间互相转化
* @author marquis
*
*/
public class CrsShiftUtils {
/**
* π
*/
private final static double PI = 3.1415926535897931;
/**
* 长半轴
*/
private final static double aa = 6378245.0;
/**
* 偏心率平方
*/
private final static double ee = 0.00669342162296594323;
private final static double ee1 = 0.0066934216229659433;
/**
* 默认偏移中心点坐标
*/
private final static double centerLng = 105.0;
private final static double centerLat = 35.0;
private final static double centerLng1 = 100.0;
private final static double centerLat1 = 30.0;
/**
* 偏移/反偏移方向
* @author marquis
*
*/
public enum Method {
WGS84_2_GCJ02,
GCJ02_2_WGS84,
WGS84_2_BD09,
BD09_2_WGS84,
GCJ02_2_BD09,
BD09_2_GCJ02
}
/**
* 禁止实例化
*/
private CrsShiftUtils() {
}
/**
* 二维点数据的坐标系转换
* @param lng
* @param lat
* @param method
* @return
*/
public static double[] convert(double lng, double lat, Method method) {
double ret[];
switch (method) {
case WGS84_2_GCJ02:
ret = shift2Mars(lng, lat, Math.PI, aa, ee, lng, lat);
ret[0] = lng + ret[0];
ret[1] = lat + ret[1];
return ret;
case GCJ02_2_WGS84:
ret = shift2Mars(lng, lat, Math.PI, aa, ee, centerLng, centerLat);
ret[0] = lng - ret[0];
ret[1] = lat - ret[1];
return ret;
case WGS84_2_BD09:
ret = shift2Mars(lng, lat, Math.PI, aa, ee, centerLng, centerLat);
ret[0] = lng + ret[0];
ret[1] = lat + ret[1];
return mars2Saturn(ret[0], ret[1], Math.PI);
case BD09_2_WGS84:
ret = saturn2Mars(lng, lat, Math.PI);
ret = shift2Mars(ret[0], ret[1], Math.PI, aa, ee, centerLng, centerLat);
ret[0] = lng - ret[0];
ret[1] = lat - ret[1];
return ret;
case GCJ02_2_BD09:
return mars2Saturn(lng, lat, Math.PI);
case BD09_2_GCJ02:
return saturn2Mars(lng, lat, Math.PI);
default:
ret = new double[2];
ret[0] = lng;
ret[1] = lat;
return ret;
}
}
/**
* 计算火星坐标系的偏移量,正向偏移时坐标加偏移量,反向偏移时减偏移量
* @param lng
* @param lat
* @param pi
* @param a
* @param e
* @param cLng
* @param cLat
* @return
*/
private static double[] shift2Mars(double lng, double lat, double pi, double a, double e, double cLng, double cLat) {
if (outOfChina(lng, lat)) {
double[] ret = new double[2];
ret[0] = lng;
ret[1] = lat;
return ret;
}
double dlat = transformlat(lng - cLng, lat - cLat, pi);
double dlng = transformlng(lng - cLng, lat - cLat, pi);
double radlat = lat / 180.0 * pi;
double magic = Math.sin(radlat);
magic = 1 - e * magic * magic;
double sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
return new double[]{dlng, dlat};
}
/**
* 计算火星坐标系到土星坐标系
* @param lng
* @param lat
* @param pi
* @param a
* @param e
* @param cLng
* @param cLat
* @return
*/
private static double[] mars2Saturn(double lng, double lat, double pi) {
if (outOfChina(lng, lat)) {
double[] ret = new double[2];
ret[0] = lng;
ret[1] = lat;
return ret;
}
double magic = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * pi);
double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * pi);
double bdLng = magic * Math.cos(theta) + 0.0065;
double bdLat = magic * Math.sin(theta) + 0.006;
return new double[] { bdLng, bdLat };
}
/**
* 计算土星坐标系到火星坐标系
* @param lng
* @param lat
* @param pi
* @param a
* @param e
* @param cLng
* @param cLat
* @return
*/
private static double[] saturn2Mars(double lng, double lat, double pi) {
if (outOfChina(lng, lat)) {
return new double[] { lng, lat };
}
double bdLng = lng - 0.0065, bdLat = lat - 0.006;
double magic = Math.sqrt(bdLng * bdLng + bdLat * bdLat) - 0.00002 * Math.sin(bdLat * pi);
double theta = Math.atan2(bdLat, bdLng) - 0.000003 * Math.cos(bdLng * pi);
double gcjLng = magic * Math.cos(theta);
double gcjLat = magic * Math.sin(theta);
return new double[] { gcjLng, gcjLat };
}
/**
* 转换经度
* @param lng
* @param lat
* @param pi
* @return
*/
private static double transformlng(double lng, double lat, double pi) {
double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * pi) + 40.0 * Math.sin(lng / 3.0 * pi)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * pi) + 300.0 * Math.sin(lng / 30.0 * pi)) * 2.0 / 3.0;
return ret;
}
/**
* 转换维度
* @param lng
* @param lat
* @param pi
* @return
*/
private static double transformlat(double lng, double lat, double pi) {
double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat
+ 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * pi) + 40.0 * Math.sin(lat / 3.0 * pi)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * pi) + 320 * Math.sin(lat * pi / 30.0)) * 2.0 / 3.0;
return ret;
}
/**
* 简单粗暴的判断是否在国内,不在国内不做偏移
* @param lng
* @param lat
* @return
*/
private static boolean outOfChina(double lng, double lat) {
//return false;
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
}
}
package com.sd.geelyhmiweb.viewmodels
import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode
import com.amap.api.location.AMapLocationClientOption.AMapLocationProtocol
import com.amap.api.location.AMapLocationListener
import com.amap.api.location.AMapLocationQualityReport
import com.amap.api.location.CoordinateConverter
import com.amap.api.location.DPoint
import com.sd.geelyhmiweb.bean.MyLoc
import com.sd.geelyhmiweb.utils.CrsShiftUtils
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
@HiltViewModel
class AMapLoc @Inject constructor(@ApplicationContext var context: Context) : ViewModel() {
val TAG = AMapLoc::class.java::getSimpleName.toString()
private var locationClient: AMapLocationClient? = null
private var locationOption: AMapLocationClientOption? = null
private var myLoc = MyLoc()
var myLocValue = MutableLiveData<MyLoc>()
/**
* 初始化定位
*
* @since 2.8.0
* @author hongming.wang
*/
fun initLocation() {
//初始化client
try {
locationClient = AMapLocationClient(context)
locationOption = getDefaultOption()
//设置定位参数
locationClient?.setLocationOption(locationOption)
// 设置定位监听
locationClient?.setLocationListener(locationListener)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 默认的定位参数
* @since 2.8.0
* @author hongming.wang
*/
private fun getDefaultOption(): AMapLocationClientOption {
val mOption = AMapLocationClientOption()
mOption.setLocationMode(AMapLocationMode.Hight_Accuracy) //可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
mOption.setGpsFirst(true) //可选,设置是否gps优先,只在高精度模式下有效。默认关闭
mOption.setHttpTimeOut(30000) //可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.setInterval(2000) //可选,设置定位间隔。默认为2秒 最快1秒,低于1秒还是1秒
mOption.setNeedAddress(false) //可选,设置是否返回逆地理地址信息。默认是true
mOption.setOnceLocation(false) //可选,设置是否单次定位。默认是false
mOption.setOnceLocationLatest(false) //可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.HTTP) //可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
mOption.setSensorEnable(true) //可选,设置是否使用传感器。默认是false
mOption.setWifiScan(true) //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
mOption.setLocationCacheEnable(true) //可选,设置是否使用缓存定位,默认为true
mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT) //可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
return mOption
}
private fun getTrancesportOption(): AMapLocationClientOption {
val mOption = AMapLocationClientOption()
/**
* 设置签到场景,相当于设置为:
* option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
* option.setOnceLocation(false);
* option.setOnceLocationLatest(false);
* option.setMockEnable(false);
* option.setWifiScan(true);
*
* 其他属性均为模式属性。
* 如果要改变其中的属性,请在在设置定位场景之后进行
*/
mOption.setHttpTimeOut(1000) //可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.setInterval(2000) //可选,设置定位间隔。默认为2秒
mOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Transport)
return mOption
}
/**
* 定位监听
*/
private var locationListener: AMapLocationListener = AMapLocationListener { location ->
if (null != location) {
/*val sb = StringBuffer()
//errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
if (location.errorCode == 0) {
sb.append("定位成功" + "\n")
sb.append("定位类型: " + location.locationType + "\n")
sb.append("经 度 : " + location.longitude + "\n")
sb.append("纬 度 : " + location.latitude + "\n")
sb.append("精 度 : " + location.accuracy + "米" + "\n")
sb.append("提供者 : " + location.provider + "\n")
sb.append("速 度 : " + location.speed + "米/秒" + "\n")
sb.append("角 度 : " + location.bearing + "\n")
// 获取当前提供定位服务的卫星个数
sb.append("星 数 : " + location.satellites + "\n")
sb.append("国 家 : " + location.country + "\n")
sb.append("省 : " + location.province + "\n")
sb.append("市 : " + location.city + "\n")
sb.append("城市编码 : " + location.cityCode + "\n")
sb.append("区 : " + location.district + "\n")
sb.append("区域 码 : " + location.adCode + "\n")
sb.append("地 址 : " + location.address + "\n")
sb.append("兴趣点 : " + location.poiName + "\n")
//定位完成的时间
*//* sb.append(
"定位时间: " + AmapUtils.formatUTC(
location.time,
"yyyy-MM-dd HH:mm:ss"
) + "\n"
)*//*
} else {
//定位失败
sb.append("定位失败" + "\n")
sb.append("错误码:" + location.errorCode + "\n")
sb.append("错误信息:" + location.errorInfo + "\n")
sb.append("错误描述:" + location.locationDetail + "\n")
}
sb.append("***定位质量报告***").append("\n")
sb.append("* WIFI开关:")
.append(if (location.locationQualityReport.isWifiAble) "开启" else "关闭")
.append("\n")
sb.append("* GPS状态:")
.append(getGPSStatusString(location.locationQualityReport.gpsStatus)).append("\n")
sb.append("* GPS星数:").append(location.locationQualityReport.gpsSatellites)
.append("\n")
sb.append("* 网络类型:" + location.locationQualityReport.networkType).append("\n")
sb.append("* 网络耗时:" + location.locationQualityReport.netUseTime).append("\n")
sb.append("****************").append("\n")*/
//定位之后的回调时间
/* sb.append(
"回调时间: " + AmapUtils.formatUTC(
System.currentTimeMillis(),
"yyyy-MM-dd HH:mm:ss"
) + "\n"
)*/
//解析定位结果,
// val result = sb.toString()
// println("result = ${result}")
// CustomLog.d(TAG, result)
setMyLocation(location, "result")
} else {
// CustomLog.d(TAG, "定位失败,loc is null")
}
}
private fun setMyLocation(location: AMapLocation, debugString: String = "") {
var dst= CrsShiftUtils.convert(location.longitude,location.latitude,CrsShiftUtils.Method.GCJ02_2_WGS84)
// var decimalFormat = DecimalFormat("#.00000000")
// var strLat = decimalFormat.format(dst[1])
// var strLng = decimalFormat.format(dst[0])
myLoc.lat = dst[1]
myLoc.lng = dst[0]
myLoc.bearing = location.bearing
myLoc.altitude = location.altitude
myLoc.speed = location.speed
// myLoc.com_time = location.time
// myLoc.debugStr = debugString
// println("--------lat = ${myLoc.lat} lng = ${myLoc.lng} bearing=${myLoc.bearing}")
myLocValue.postValue(myLoc)
// val loc = location.latitude.toString() + " " + location.longitude.toString()
}
/**
* 获取GPS状态的字符串
* @param statusCode GPS状态码
* @return
*/
private fun getGPSStatusString(statusCode: Int): String {
var str = ""
when (statusCode) {
AMapLocationQualityReport.GPS_STATUS_OK -> str = "GPS状态正常"
AMapLocationQualityReport.GPS_STATUS_NOGPSPROVIDER -> str =
"手机中没有GPS Provider,无法进行GPS定位"
AMapLocationQualityReport.GPS_STATUS_OFF -> str = "GPS关闭,建议开启GPS,提高定位质量"
AMapLocationQualityReport.GPS_STATUS_MODE_SAVING -> str =
"选择的定位模式中不包含GPS定位,建议选择包含GPS定位的模式,提高定位质量"
AMapLocationQualityReport.GPS_STATUS_NOGPSPERMISSION -> str =
"没有GPS定位权限,建议开启gps定位权限"
}
return str
}
/**
* 开始定位
*
* @since 2.8.0
* @author hongming.wang
*/
fun startLocation() {
try {
//根据控件的选择,重新设置定位参数
// resetOption()
// 设置定位参数
locationClient?.setLocationOption(locationOption)
// 启动定位
locationClient?.startLocation()
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 停止定位
*
* @since 2.8.0
* @author hongming.wang
*/
fun stopLocation() {
try {
// 停止定位
locationClient?.stopLocation()
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
/**
* 销毁定位
*
* @since 2.8.0
* @author hongming.wang
*/
fun destroyLocation() {
if (null != locationClient) {
/**
* 如果AMapLocationClient是在当前Activity实例化的,
* 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
*/
locationClient?.onDestroy()
locationClient = null
locationOption = null
}
}
/**
* WGS-84转高德坐标(GCJ-02)
*/
fun convertWGS84ToGCJ02(longitude: Double, latitude: Double): DPoint {
val converter = CoordinateConverter(context)
// 设置源坐标为GPS坐标(WGS-84)
converter.from(CoordinateConverter.CoordType.GPS)
converter.coord(DPoint(latitude, longitude))
val destLatLng = converter.convert()
return destLatLng
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment