Browse Source

高德定位

master
zhaodengke 1 day ago
parent
commit
25ca6eb217
4 changed files with 484 additions and 1 deletions
  1. +11
    -1
      app/build.gradle
  2. BIN
      app/libs/AMap_Location_V6.4.9_20241226.jar
  3. +22
    -0
      app/src/main/AndroidManifest.xml
  4. +451
    -0
      app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java

+ 11
- 1
app/build.gradle View File

@@ -22,6 +22,9 @@ android {
// App启动页厂商名称
buildConfigField "String", "APP_VENDOR", "\"${project.properties.appVendor}\""

// App图标
buildConfigField "String", "APP_ICON", "\"${project.properties.appIconKey}\""

// AndroidManifest.xml占位符
manifestPlaceholders = [
// App名称
@@ -52,12 +55,14 @@ android {
resValue("string", "app_home_url", "\"${project.properties.appHomeUrl}\"")
resValue("string", "app_copyright", "\"${project.properties.appCopyright}\"")
resValue("string", "app_vendor", "\"${project.properties.appVendor}\"")
resValue("string", "app_name2", "\"${project.properties.appName}\"")
}
debug {
signingConfig signingConfigs.release
resValue("string", "app_home_url", "\"${project.properties.appHomeUrl}\"")
resValue("string", "app_copyright", "\"${project.properties.appCopyright}\"")
resValue("string", "app_vendor", "\"${project.properties.appVendor}\"")
resValue("string", "app_name2", "\"${project.properties.appName}\"")
}
}
compileOptions {
@@ -78,4 +83,9 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.github.Justson.AgentWeb:agentweb-core:v4.1.9-androidx' // (必选)
implementation 'com.github.Justson.AgentWeb:agentweb-filechooser:v4.1.9-androidx'
}
implementation 'androidx.preference:preference:1.1.1'
implementation 'cn.hutool:hutool-all:5.5.4'

compile fileTree(include: ['*.jar'], dir: 'libs')
//compile 'com.amap.api:location:latest.integration'
}

BIN
app/libs/AMap_Location_V6.4.9_20241226.jar View File


+ 22
- 0
app/src/main/AndroidManifest.xml View File

@@ -15,6 +15,16 @@
<!--AgentWeb 是默认允许定位的 ,如果你需要该功能 , 请在你的 AndroidManifest 文件里面加入如下权限 。-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


<!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!--用于申请调用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"/>

<!-- android:icon 、 android:roundIcon 是APP显示图标-->
<!--
APP_NAME占位符:
@@ -36,6 +46,10 @@
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.Nsgk_rural_web">
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="7e6911ad842a6a6f492d27efdbd42f30"/>

<activity
android:name=".WelcomeActivity"
android:configChanges="orientation|keyboardHidden|screenSize|layoutDirection|uiMode"
@@ -46,9 +60,16 @@

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name=".FullscreenActivity"
android:label="${APP_NAME}"
android:configChanges="orientation|keyboardHidden|screenSize|layoutDirection|uiMode" />
<activity
android:name=".SettingsActivity"
android:label="设置"
android:configChanges="orientation|keyboardHidden|screenSize|layoutDirection|uiMode" />

<!--开机广播接受者
@@ -58,6 +79,7 @@
</intent-filter>
</receiver>
-->
<service android:name="com.amap.api.location.APSService"></service>
</application>

</manifest>

+ 451
- 0
app/src/main/java/com/nsgk/ruralWeb/location/NSAMapLocation.java View File

@@ -0,0 +1,451 @@
package com.nsgk.ruralWeb.location;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.CoordinateConverter;
import com.amap.api.location.DPoint;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

// 主线程调用, 无线程安全
public class NSAMapLocation implements AMapLocationListener
{
// 定位场景: 默认无场景
public static final int FLAG_PURPOSE_SIGNIN = 1; // 签到
public static final int FLAG_PURPOSE_TRANSPORT = 1 << 1; // 出行
public static final int FLAG_PURPOSE_SPORT = 1 << 2; // 运动

// 定位模式
public static final int FLAG_MODE_HIGH = 1 << 3; // 高精度模式
public static final int FLAG_MODE_SAVING = 1 << 4; // 低功耗模式
public static final int FLAG_MODE_SENSORS = 1 << 5; // 仅设备模式

// 获取一次定位结果: 默认为false
public static final int FLAG_ONCE = 1 << 6; // true

// 获取最近3s内精度最高的一次定位结果: 默认为false
public static final int FLAG_ONCE_LATEST = 1 << 7; // true

// 设置是否返回地址信息: 默认返回地址信息
public static final int FLAG_NO_NEED_ADDRESS = 1 << 8; // false

// 设置是否允许模拟位置: 默认为true
public static final int FLAG_MOCK_DISABLE = 1 << 9; // false

// 关闭缓存机制: 默认缓存
public static final int FLAG_CACHE_DISABLE = 1 << 10; // false

// 线程
public static final int FLAG_BUILTIN_THREAD = 1 << 11; // 使用内建线程
public static final int FLAG_CUSTOM_THREAD = 1 << 12; // 使用外部线程
public static final int FLAG_MAIN_THREAD = 1 << 13; // 使用主线程

public static final int DEFAULT_FLAG = FLAG_MODE_HIGH | FLAG_NO_NEED_ADDRESS;


public static final int OPTION_INTERVAL = 1; // 定位间隔(毫秒) 默认1000
public static final int OPTION_HTTP_TIMEOUT = 2; // 定位间隔(毫秒) 默认20000

private static final int DEFAULT_INTERVAL = 1000;
private static final int DEFAULT_HTTP_TIMEOUT = 20000;

private static final String ID_TAG = NSSystemLocation.class.getName();

private final Object m_lock = new Object();

//声明AMapLocationClient类对象
public AMapLocationClient mLocationClient = null;
//声明定位回调监听器
public AMapLocationListener mLocationListener = this;
//声明AMapLocationClientOption对象
public AMapLocationClientOption mLocationOption = null;
private final Context m_context;
private int m_flag = DEFAULT_FLAG;
private boolean m_isPreInit = false;
private NSLocationInfo m_lastLocation = null;
private HandlerThread m_thread = null;
private Looper m_customLooper = null;
private AtomicInteger m_readOnce = new AtomicInteger(-1);
private Map<Integer, Object> m_options = new HashMap<>();

public NSAMapLocation(Context context)
{
m_context = context;
}

public boolean Init(int flag)
{
if(IsInitialized())
{
Log.e(ID_TAG, "定位已初始化");
return true;
}

try
{
m_readOnce.set(-1);
m_flag = flag < 0 ? DEFAULT_FLAG : flag;

// 在构造AMapLocationClient 之前必须进行合规检查,设置接口之前保证隐私政策合规
PreInit();

Context applicationContext = m_context.getApplicationContext();
//初始化定位
if(HasFlag(FLAG_BUILTIN_THREAD))
{
m_thread = new HandlerThread("AMap内建定位");
m_thread.start();
mLocationClient = new AMapLocationClient(m_thread.getLooper(), applicationContext);
Log.d(ID_TAG, "定位使用内建线程: " + m_thread.getId());
}
else if(HasFlag(FLAG_CUSTOM_THREAD))
{
if(null == m_customLooper)
{
throw new RuntimeException("请先传入线程Looper");
}
mLocationClient = new AMapLocationClient(m_customLooper, applicationContext);
Log.d(ID_TAG, "定位使用用户指定线程: " + m_customLooper.getThread().getId());
}
else if(HasFlag(FLAG_MAIN_THREAD))
{
Looper mainLooper = Looper.getMainLooper();
mLocationClient = new AMapLocationClient(mainLooper, applicationContext);
Log.d(ID_TAG, "定位使用主线程: " + mainLooper.getThread().getId());
}
else
{
mLocationClient = new AMapLocationClient(applicationContext);
Log.d(ID_TAG, "定位使用当前线程: " + Thread.currentThread().getId());
}

//设置定位回调监听
mLocationClient.setLocationListener(mLocationListener);

InitOptions();

mLocationClient.setLocationOption(mLocationOption);

//V6.4.9版本起 client设置逆地理回调
/* mLocationClient.setReGeoLocationCallback(new IReGeoLocationCallback()
{
@Override
public void onReGeoLocation(AMapLocation reGeoLocation)
{
Log.i(ID_TAG, reGeoLocation.toStr());
}
});*/

Log.i(ID_TAG, "定位初始化完成");
return true;
}
catch(Exception e)
{
e.printStackTrace();
mLocationClient = null;
return false;
}
}

public void SetThread(Looper looper)
{
CheckInitialization(false);
m_customLooper = looper;
}

public void SetThread(HandlerThread thread)
{
CheckInitialization(false);
m_customLooper = thread.getLooper();
}

public boolean IsRunning()
{
return IsInitialized() && mLocationClient.isStarted();
}

public void Start()
{
Run(-1);
}

public void Stop()
{
CheckInitialization(true);

//设置场景模式后最好调用一次stop,再调用start以保证场景模式生效
mLocationClient.stopLocation();

Log.i(ID_TAG, "定位停止");
}

public void Shutdown()
{
if(!IsInitialized())
{
Log.e(ID_TAG, "请先初始化");
return;
}

Stop();

mLocationClient.onDestroy();
mLocationClient = null;
if(null != m_thread)
{
m_thread.quit();
m_thread = null;
Log.d(ID_TAG, "内建线程结束");
}

Log.i(ID_TAG, "定位销毁");
}

public void PreInit()
{
if(m_isPreInit)
return;
Context applicationContext = m_context.getApplicationContext();
/** 设置包含隐私政策,并展示用户授权弹窗 <b>必须在AmapLocationClient实例化之前调用</b>
*
* @param context
* @param isContains: 是隐私权政策是否包含高德开平隐私权政策 true是包含
* @param isShow: 隐私权政策是否弹窗展示告知用户 true是展示
* @since 5.6.0
*/
AMapLocationClient.updatePrivacyShow(applicationContext, true, true);
/**
* 设置是否同意用户授权政策 <b>必须在AmapLocationClient实例化之前调用</b>
* @param context
* @param isAgree:隐私权政策是否取得用户同意 true是用户同意
*
* @since 5.6.0
*/
AMapLocationClient.updatePrivacyAgree(applicationContext, true);
Log.i(ID_TAG, "定位预初始化");
m_isPreInit = true;
}

public boolean IsInitialized()
{
return null != mLocationClient;
}

private void CheckInitialization(boolean inited)
{
if(IsInitialized() != inited)
{
String msg = inited ? "定位未初始化" : "定位已初始化";
Log.e(ID_TAG, msg);
throw new RuntimeException(msg);
}
}

private boolean HasFlag(int f)
{
return (m_flag & f) != 0;
}

public void SetOption(int type, Object value)
{
CheckInitialization(false);
m_options.put(type, value);
}

@SuppressLint("unchecked")
private <T> T GetOption(int type, T def)
{
Object o = m_options.get(type);
if(null == o)
return def;
return (T) o;
}

private void InitOptions()
{
//初始化AMapLocationClientOption对象
mLocationOption = new AMapLocationClientOption();

/**
* 设置定位场景,目前支持三种场景(签到、出行、运动,默认无场景)
*/
if(HasFlag(FLAG_PURPOSE_SIGNIN))
mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn);
else if(HasFlag(FLAG_PURPOSE_TRANSPORT))
mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Transport);
else if(HasFlag(FLAG_PURPOSE_SPORT))
mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport);

//设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。
if(HasFlag(FLAG_MODE_HIGH))
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//设置定位模式为AMapLocationMode.Battery_Saving,低功耗模式。
else if(HasFlag(FLAG_MODE_SAVING))
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
//设置定位模式为AMapLocationMode.Device_Sensors,仅设备模式。
else if(HasFlag(FLAG_MODE_SENSORS))
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);

//获取一次定位结果:
//该方法默认为false。
if(HasFlag(FLAG_ONCE))
mLocationOption.setOnceLocation(true);

//获取最近3s内精度最高的一次定位结果:
//设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。
if(HasFlag(FLAG_ONCE_LATEST))
mLocationOption.setOnceLocationLatest(true);

//设置定位间隔,单位毫秒,默认为2000ms,最低1000ms。
int interval = GetOption(OPTION_INTERVAL, DEFAULT_INTERVAL);
mLocationOption.setInterval(interval);

//设置是否返回地址信息(默认返回地址信息)
if(HasFlag(FLAG_NO_NEED_ADDRESS))
mLocationOption.setNeedAddress(false);

//设置是否允许模拟位置,默认为true,允许模拟位置
if(HasFlag(FLAG_MOCK_DISABLE))
mLocationOption.setMockEnable(false);

//单位是毫秒,默认30000毫秒,建议超时时间不要低于8000毫秒。
int timeout = GetOption(OPTION_HTTP_TIMEOUT, DEFAULT_HTTP_TIMEOUT);
mLocationOption.setHttpTimeOut(timeout);

//关闭缓存机制
if(HasFlag(FLAG_CACHE_DISABLE))
mLocationOption.setLocationCacheEnable(false);
}

private void Run(int num)
{
CheckInitialization(true);

m_readOnce.set(num);

//设置场景模式后最好调用一次stop,再调用start以保证场景模式生效
mLocationClient.stopLocation();
mLocationClient.startLocation();

Log.i(ID_TAG, "定位开始");
}

/*
在调用线程中执行
*/
@Override
public void onLocationChanged(AMapLocation amapLocation)
{
Log.d(ID_TAG, "onLocationChanged线程: " + Thread.currentThread().getId());
System.err.println(amapLocation);
SetLastLocation(amapLocation);
if(null != amapLocation)
{
if(m_readOnce.get() > 0)
{
m_readOnce.decrementAndGet();
if(m_readOnce.get() == 0)
{
synchronized(m_lock)
{
m_lock.notifyAll();
}
}
}
}
}

private double[] Convert(double longitude, double latitude)
{
try
{
//初始化坐标转换类
CoordinateConverter converter = new CoordinateConverter(m_context.getApplicationContext());
converter.from(CoordinateConverter.CoordType.GPS);
//设置需要转换的坐标
converter.coord(new DPoint(latitude, longitude));
//转换成高德坐标
DPoint destPoint = converter.convert();
double dx = destPoint.getLongitude() - longitude;
double dy = destPoint.getLatitude() - latitude;
longitude = longitude - dx;
latitude = latitude - dy;
return new double[]{
longitude, latitude
};
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}

private void SetLastLocation(AMapLocation amapLocation)
{
if(null != amapLocation)
{
double longitude = amapLocation.getLongitude();
double latitude = amapLocation.getLatitude();
double[] coord = Convert(longitude, latitude);
longitude = coord[0];
latitude = coord[1];
m_lastLocation = new NSLocationInfo(amapLocation.getProvider(), longitude, latitude);
}
else
{
m_lastLocation = null;
}
}

/**
* 同步调用, 会锁住线程
*/
public NSLocationInfo Read(int count)
{
CheckInitialization(true);
/* if(IsRunning())
{
throw new RuntimeException("请先停止定位");
}*/

Log.d(ID_TAG, "定位线程: " + Thread.currentThread().getId());
synchronized(m_lock)
{
try
{
CleanLastLocation();
Run(count);
m_lock.wait();
}
catch(Exception e)
{
throw new RuntimeException(e);
}
finally
{
Stop();
}
}
return m_lastLocation;
}

public NSLocationInfo GetLastLocation()
{
return m_lastLocation;
}

public void CleanLastLocation()
{
m_lastLocation = null;
}
}

Loading…
Cancel
Save