diff --git a/positions/build.gradle b/positions/build.gradle
index b8401af2..b7aaa28b 100644
--- a/positions/build.gradle
+++ b/positions/build.gradle
@@ -45,6 +45,9 @@ android {
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
+
+ // 谷歌定位服务核心依赖(FusedLocationProviderClient所在库)
+ api 'com.google.android.gms:play-services-location:21.0.1'
// SSH
api 'com.jcraft:jsch:0.1.55'
diff --git a/positions/build.properties b/positions/build.properties
index 4968ed8f..f8c4e4d0 100644
--- a/positions/build.properties
+++ b/positions/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Mon Sep 29 18:02:11 HKT 2025
+#Mon Sep 29 10:40:51 GMT 2025
stageCount=2
libraryProject=
baseVersion=15.0
publishVersion=15.0.1
-buildCount=0
+buildCount=2
baseBetaVersion=15.0.2
diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml
index 277d9bb8..65f5e10f 100644
--- a/positions/src/main/AndroidManifest.xml
+++ b/positions/src/main/AndroidManifest.xml
@@ -2,7 +2,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
index f824af53..635b8353 100644
--- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
+++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
@@ -5,6 +5,9 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogView;
import com.hjq.toast.ToastUtils;
+import android.view.View;
+import cc.winboll.studio.positions.activities.LocationActivity;
+import android.content.Intent;
public class MainActivity extends AppCompatActivity {
@@ -28,4 +31,8 @@ public class MainActivity extends AppCompatActivity {
super.onResume();
mLogView.start();
}
+
+ public void onPositions(View view) {
+ startActivity(new Intent(this, LocationActivity.class));
+ }
}
diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java
new file mode 100644
index 00000000..ba8830c7
--- /dev/null
+++ b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java
@@ -0,0 +1,219 @@
+package cc.winboll.studio.positions.activities;
+
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/09/29 18:22
+ * @Describe 当前位置实时显示
+ */
+
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationCallback;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationResult;
+import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.tasks.OnSuccessListener;
+import cc.winboll.studio.positions.R;
+
+
+/**
+ * 实时定位活动窗口:
+ * 1. 申请定位必需权限(精确定位+粗略定位)
+ * 2. 初始化FusedLocationProviderClient(谷歌官方定位服务,兼容所有安卓版本)
+ * 3. 实时监听位置变化,更新显示经度、纬度
+ */
+public class LocationActivity extends AppCompatActivity {
+
+ public static final String TAG = "LocationActivity";
+
+ // 1. 核心组件与常量定义
+ private static final int REQUEST_LOCATION_PERMISSIONS = 1004; // 定位权限请求码
+ private FusedLocationProviderClient fusedLocationClient; // 定位核心客户端
+ private LocationCallback locationCallback; // 位置变化监听器
+ private LocationRequest locationRequest; // 定位请求配置(频率、精度等)
+
+ // UI控件:用于显示经纬度(需在布局中定义对应ID)
+ private TextView tvLongitude; // 经度显示
+ private TextView tvLatitude; // 纬度显示
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // 2. 加载布局(需手动创建对应布局文件,见下方说明)
+ setContentView(R.layout.activity_location);
+
+ // 3. 绑定UI控件(与布局文件中的TextView ID对应)
+ tvLongitude = findViewById(R.id.tv_longitude);
+ tvLatitude = findViewById(R.id.tv_latitude);
+
+ // 4. 初始化定位相关组件
+ initLocationConfig();
+
+ // 5. 检查并申请定位权限(无权限则申请,有权限则直接启动定位)
+ if (checkLocationPermissions()) {
+ startRealTimeLocation(); // 权限已授予 → 启动实时定位
+ } else {
+ requestLocationPermissions(); // 权限未授予 → 申请权限
+ }
+ }
+
+
+ /**
+ * 初始化定位配置:设置定位精度、更新频率等
+ */
+ private void initLocationConfig() {
+ // 初始化定位客户端(谷歌官方推荐,替代旧的LocationManager)
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
+
+ // 配置定位请求:实时更新(1秒请求一次,最小间隔500毫秒,最高精度)
+ locationRequest = new LocationRequest.Builder(1000) // 定位更新间隔(毫秒)
+ .setMinUpdateIntervalMillis(500) // 最小更新间隔(避免频繁更新耗电)
+ .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) // 高精度定位(优先GPS)
+ .build();
+
+ // 初始化位置变化监听器:位置更新时触发(实时更新UI)
+ locationCallback = new LocationCallback() {
+ @Override
+ public void onLocationResult(@NonNull LocationResult locationResult) {
+ super.onLocationResult(locationResult);
+ // 获取最新位置信息(locationResult包含最近一次或多次位置)
+ Location latestLocation = locationResult.getLastLocation();
+ if (latestLocation != null) {
+ // 6. 提取经纬度并更新UI(实时显示)
+ double longitude = latestLocation.getLongitude(); // 经度(东经为正,西经为负)
+ double latitude = latestLocation.getLatitude(); // 纬度(北纬为正,南纬为负)
+
+ // 更新TextView显示(保留6位小数,精度足够日常使用)
+ tvLongitude.setText(String.format("当前经度:%.6f", longitude));
+ tvLatitude.setText(String.format("当前纬度:%.6f", latitude));
+ }
+ }
+ };
+ }
+
+
+ /**
+ * 检查定位必需权限是否已授予(精确定位+粗略定位,覆盖所有安卓版本)
+ */
+ private boolean checkLocationPermissions() {
+ // 安卓12+(API31+)新增精确定位权限,需同时检查2个权限;低版本只需检查1个
+ /*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
+ && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
+ } else {*/
+ return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
+ //}
+ }
+
+
+ /**
+ * 申请定位必需权限(弹系统授权弹窗)
+ */
+ private void requestLocationPermissions() {
+ /*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ // 安卓12+:同时申请精确定位+粗略定位
+ ActivityCompat.requestPermissions(
+ this,
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
+ REQUEST_LOCATION_PERMISSIONS
+ );
+ } else {*/
+ // 安卓12以下:仅申请精确定位(包含粗略定位能力)
+ ActivityCompat.requestPermissions(
+ this,
+ new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
+ REQUEST_LOCATION_PERMISSIONS
+ );
+ //}
+ }
+
+
+ /**
+ * 启动实时定位:注册位置监听器,开始接收位置更新
+ */
+ private void startRealTimeLocation() {
+ // 权限兜底检查(避免异常)
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "定位权限未授予,无法启动定位", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // 1. 先获取一次当前位置(快速显示初始经纬度)
+ fusedLocationClient.getLastLocation()
+ .addOnSuccessListener(this, new OnSuccessListener() {
+ @Override
+ public void onSuccess(Location location) {
+ if (location != null) {
+ // 显示初始经纬度
+ tvLongitude.setText(String.format("当前经度:%.6f", location.getLongitude()));
+ tvLatitude.setText(String.format("当前纬度:%.6f", location.getLatitude()));
+ } else {
+ // 无历史位置(如首次启动),提示“等待定位更新”
+ tvLongitude.setText("当前经度:等待更新...");
+ tvLatitude.setText("当前纬度:等待更新...");
+ }
+ }
+ });
+
+ // 2. 注册监听器,接收实时位置更新(持续监听)
+ fusedLocationClient.requestLocationUpdates(
+ locationRequest,
+ locationCallback,
+ getMainLooper() // 在主线程更新UI(避免线程异常)
+ );
+ }
+
+
+ /**
+ * 处理权限申请结果(用户同意/拒绝后触发)
+ */
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (requestCode == REQUEST_LOCATION_PERMISSIONS) {
+ // 检查是否所有必需权限都已授予
+ boolean allGranted = true;
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ allGranted = false;
+ break;
+ }
+ }
+
+ if (allGranted) {
+ // 权限同意 → 启动实时定位
+ startRealTimeLocation();
+ } else {
+ // 权限拒绝 → 提示用户(无法定位)
+ Toast.makeText(this, "定位权限被拒绝,无法显示位置信息", Toast.LENGTH_SHORT).show();
+ tvLongitude.setText("当前经度:无权限");
+ tvLatitude.setText("当前纬度:无权限");
+ }
+ }
+ }
+
+
+ /**
+ * 活动销毁时:停止定位监听(避免内存泄漏、减少耗电)
+ */
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ // 移除定位监听器(核心:防止Activity销毁后仍在监听,导致内存泄漏)
+ if (fusedLocationClient != null && locationCallback != null) {
+ fusedLocationClient.removeLocationUpdates(locationCallback);
+ }
+ }
+}
+
diff --git a/positions/src/main/res/layout/activity_location.xml b/positions/src/main/res/layout/activity_location.xml
new file mode 100644
index 00000000..2d9895d4
--- /dev/null
+++ b/positions/src/main/res/layout/activity_location.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/positions/src/main/res/layout/activity_main.xml b/positions/src/main/res/layout/activity_main.xml
index 8000fb42..97e0df26 100644
--- a/positions/src/main/res/layout/activity_main.xml
+++ b/positions/src/main/res/layout/activity_main.xml
@@ -26,11 +26,11 @@
android:layout_weight="1.0"
android:gravity="center_vertical|center_horizontal">
-
+ android:onClick="onPositions"/>