Compare commits

..

11 Commits

Author SHA1 Message Date
ZhanGSKen
435f7ced79 Merge remote-tracking branch 'origin/positions' into appbase 2025-10-02 10:45:47 +08:00
ZhanGSKen
bd3270f8dd 20251002_104016_614 2025-10-02 10:40:25 +08:00
ZhanGSKen
5489977a1a 更新主窗口UI提示文字 2025-10-02 10:14:14 +08:00
0bb909427c <positions>APK 15.0.7 release Publish. 2025-10-02 02:27:55 +08:00
ZhanGSKen
d4f054a86b 更新应用中文名为寻龙记 2025-10-02 02:25:35 +08:00
caef679d9a <positions>APK 15.0.6 release Publish. 2025-10-01 21:30:08 +08:00
ZhanGSKen
5194d7a188 修复应用初始设置问题,添加应用权限申请。 2025-10-01 21:28:52 +08:00
ZhanGSKen
0ede961391 Merge remote-tracking branch 'origin/positions' into appbase 2025-09-29 17:12:45 +08:00
e9bb789daa <libappbase>Library Release 15.10.9 2025-09-27 21:03:24 +08:00
dbff19e7f4 <appbase>APK 15.10.9 release Publish. 2025-09-27 21:03:08 +08:00
ZhanGSKen
44679d0c8a GlobalApplication函数参数类型调整 2025-09-27 21:02:02 +08:00
11 changed files with 109 additions and 83 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Fri Sep 26 05:36:14 HKT 2025 #Sat Sep 27 21:03:20 HKT 2025
stageCount=9 stageCount=10
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.10 baseVersion=15.10
publishVersion=15.10.8 publishVersion=15.10.9
buildCount=0 buildCount=0
baseBetaVersion=15.10.9 baseBetaVersion=15.10.10

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Fri Sep 26 05:36:14 HKT 2025 #Sat Sep 27 21:03:08 HKT 2025
stageCount=9 stageCount=10
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.10 baseVersion=15.10
publishVersion=15.10.8 publishVersion=15.10.9
buildCount=0 buildCount=0
baseBetaVersion=15.10.9 baseBetaVersion=15.10.10

View File

@@ -22,12 +22,12 @@ public class GlobalApplication extends Application {
GlobalApplication.isDebuging = isDebuging; GlobalApplication.isDebuging = isDebuging;
} }
public static void saveDebugStatus(GlobalApplication application) { public static void saveDebugStatus(Context context) {
APPModel.saveBeanToFile(application.getAPPModelFilePath(application), new APPModel(GlobalApplication.isDebuging)); APPModel.saveBeanToFile(getAPPModelFilePath(context), new APPModel(GlobalApplication.isDebuging));
} }
static String getAPPModelFilePath(GlobalApplication application) { static String getAPPModelFilePath(Context context) {
return application.getDataDir().getPath() + "/APPModel.json"; return context.getDataDir().getPath() + "/APPModel.json";
} }
public static boolean isDebuging() { public static boolean isDebuging() {

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Oct 01 21:03:35 HKT 2025 #Thu Oct 02 02:36:00 GMT 2025
stageCount=6 stageCount=8
libraryProject= libraryProject=
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.5 publishVersion=15.0.7
buildCount=0 buildCount=9
baseBetaVersion=15.0.6 baseBetaVersion=15.0.8

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">@笨笨龙@</string> <string name="app_name">寻龙记#</string>
</resources> </resources>

View File

@@ -1,5 +1,6 @@
package cc.winboll.studio.positions; package cc.winboll.studio.positions;
import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -9,7 +10,10 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.Switch; import android.widget.Switch;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
@@ -17,7 +21,6 @@ import cc.winboll.studio.positions.activities.LocationActivity;
import cc.winboll.studio.positions.activities.WinBoLLActivity; import cc.winboll.studio.positions.activities.WinBoLLActivity;
import cc.winboll.studio.positions.services.MainService; import cc.winboll.studio.positions.services.MainService;
import cc.winboll.studio.positions.utils.AppConfigsUtil; import cc.winboll.studio.positions.utils.AppConfigsUtil;
import com.hjq.toast.ToastUtils;
/** /**
* 主页面:仅负责 * 主页面:仅负责
@@ -27,9 +30,10 @@ import com.hjq.toast.ToastUtils;
*/ */
public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "MainActivity"; public static final String TAG = "MainActivity";
// 位置权限请求码(自定义唯一标识 // 权限请求码(建议定义为类常量,避免魔法值
private static final int REQUEST_LOCATION_PERMISSIONS = 1001; private static final int REQUEST_LOCATION_PERMISSIONS = 1001;
private static final int REQUEST_BACKGROUND_LOCATION_PERMISSION = 1002;
// UI 控件:服务控制开关、顶部工具栏 // UI 控件:服务控制开关、顶部工具栏
private Switch mServiceSwitch; private Switch mServiceSwitch;
private Button mManagePositionsButton; private Button mManagePositionsButton;
@@ -37,7 +41,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
// 服务相关:服务实例、绑定状态标记 // 服务相关:服务实例、绑定状态标记
//private DistanceRefreshService mDistanceService; //private DistanceRefreshService mDistanceService;
private boolean isServiceBound = false; private boolean isServiceBound = false;
@Override @Override
public Activity getActivity() { public Activity getActivity() {
@@ -110,7 +114,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
// 给ActionBar设置标题先判断非空避免空指针异常 // 给ActionBar设置标题先判断非空避免空指针异常
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setTitle("位置管理"); getSupportActionBar().setTitle(getString(R.string.app_name));
} }
} }
@@ -120,7 +124,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
private void initViews() { private void initViews() {
mServiceSwitch = (Switch) findViewById(R.id.switch_service_control); // 显式强转 mServiceSwitch = (Switch) findViewById(R.id.switch_service_control); // 显式强转
mServiceSwitch.setChecked(AppConfigsUtil.getInstance(this).isEnableMainService(true)); mServiceSwitch.setChecked(AppConfigsUtil.getInstance(this).isEnableMainService(true));
mManagePositionsButton = (Button) findViewById(R.id.btn_manage_positions); mManagePositionsButton = (Button) findViewById(R.id.btn_manage_positions);
mManagePositionsButton.setEnabled(mServiceSwitch.isChecked()); mManagePositionsButton.setEnabled(mServiceSwitch.isChecked());
@@ -206,49 +210,57 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
return hasForegroundPerm && hasBackgroundPerm; return hasForegroundPerm && hasBackgroundPerm;
} }
/** private void requestLocationPermissions() {
* 申请「前台+后台」位置权限(弹出系统权限弹窗,适配版本差异) // 1. 先判断前台定位权限ACCESS_FINE_LOCATION是否已授予
*/ if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
private void requestLocationPermissions() { != PackageManager.PERMISSION_GRANTED) {
String[] permissions; // 1.1 未授予前台权限先申请前台权限API 30+ 后台权限依赖前台权限)
// Java7 显式版本判断Android 10+ 需同时申请前台+后台权限 String[] foregroundPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // 对API 23+Android 6.0)动态申请,低版本会直接授予(清单已声明前提下)
permissions = new String[]{ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
android.Manifest.permission.ACCESS_FINE_LOCATION, requestPermissions(foregroundPermissions, REQUEST_LOCATION_PERMISSIONS);
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION }
}; } else {
} else { // 2. 已授予前台权限判断是否需要申请后台权限仅API 29+需要)
// 低版本仅需申请前台权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
permissions = new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}; // 2.1 检查后台权限是否未授予
} if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
// 触发系统权限申请Java7 显式调用requestPermissions无方法引用 != PackageManager.PERMISSION_GRANTED) {
requestPermissions(permissions, REQUEST_LOCATION_PERMISSIONS); // 2.2 API 30+ 必须单独申请后台权限(不能和前台权限一起弹框)
} requestPermissions(
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
REQUEST_BACKGROUND_LOCATION_PERMISSION
);
}
}
// 3. 前台权限已授予(+ 后台权限按需授予):此处可执行定位相关逻辑
// doLocationRelatedLogic();
}
}
/** // 【必须补充】权限申请结果回调(处理用户同意/拒绝逻辑)
* 处理权限申请结果系统弹窗用户选择后回调Java7 显式重写方法) @Override
*/ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@Override super.onRequestPermissionsResult(requestCode, permissions, grantResults);
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { // 处理前台权限申请结果
super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSIONS) {
// 仅处理位置权限的申请结果 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_LOCATION_PERMISSIONS) { // 前台权限同意自动尝试申请后台权限如果是API 29+
boolean allGranted = true; requestLocationPermissions();
// Java7 显式for循环遍历结果无增强for简化写法 } else {
for (int i = 0; i < grantResults.length; i++) { // 前台权限拒绝:提示用户(可选:引导跳转到应用设置页)
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "需要前台定位权限才能使用该功能", Toast.LENGTH_SHORT).show();
allGranted = false; }
break; // 有一个权限未通过,直接终止判断 } else if (requestCode == REQUEST_BACKGROUND_LOCATION_PERMISSION) {
} if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} // 后台权限同意:可执行后台定位逻辑
Toast.makeText(this, "已获得后台定位权限", Toast.LENGTH_SHORT).show();
} else {
// 后台权限拒绝:提示用户(可选:说明后台定位的用途,引导手动开启)
Toast.makeText(this, "拒绝后台权限将无法在后台持续定位", Toast.LENGTH_SHORT).show();
}
}
}
// 提示用户权限结果,并处理开关状态
if (allGranted) {
ToastUtils.show("已获取位置权限(含后台),可正常使用定位功能");
} else {
ToastUtils.show("位置权限未完全授予无法后台获取GPS数据请在设置中开启");
}
}
}
} }

View File

@@ -22,6 +22,8 @@ import cc.winboll.studio.positions.models.PositionModel;
import cc.winboll.studio.positions.models.PositionTaskModel; import cc.winboll.studio.positions.models.PositionTaskModel;
import cc.winboll.studio.positions.services.MainService; import cc.winboll.studio.positions.services.MainService;
import java.util.ArrayList; import java.util.ArrayList;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.positions.utils.AppConfigsUtil;
/** /**
* 核心调整说明: * 核心调整说明:
@@ -61,11 +63,13 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location); setContentView(R.layout.activity_location);
LogUtils.d(TAG, "onCreate");
// 1. 初始化服务实例(通过单例/全局方式避免直接new导致数据重置 // 1. 初始化服务实例(通过单例/全局方式避免直接new导致数据重置
initServiceInstance(); initServiceInstance();
// 2. 检查服务状态(未运行/未初始化则提示关闭) // 2. 检查服务状态(未运行/未初始化则提示关闭)
//checkServiceStatus(); checkServiceStatus();
// 3. 初始化RecyclerView布局+性能优化) // 3. 初始化RecyclerView布局+性能优化)
initRecyclerViewConfig(); initRecyclerViewConfig();
// 4. 缓存服务数据从服务PUBLIC方法获取不访问私有字段 // 4. 缓存服务数据从服务PUBLIC方法获取不访问私有字段
@@ -112,27 +116,27 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
finish(); finish();
} }
} }
/** /**
* 检查服务状态替代原绑定检查通过服务PUBLIC方法判断 * 检查服务状态替代原绑定检查通过服务PUBLIC方法判断
*/ */
private void checkServiceStatus() { private void checkServiceStatus() {
LogUtils.d(TAG, "checkServiceStatus");
// 1. 服务实例未初始化 // 1. 服务实例未初始化
if (mMainService == null) { if (mMainService == null) {
return; // 已在initServiceInstance中处理此处避免重复finish return; // 已在initServiceInstance中处理此处避免重复finish
} }
// 2. 检查服务运行状态通过服务PUBLIC方法isServiceRunning()获取,不访问私有字段) // 2. 检查服务运行状态通过服务PUBLIC方法isServiceRunning()获取,不访问私有字段)
// if (!mMainService.isServiceRunning()) { if (!mMainService.isServiceRunning()) {
// // 服务未运行手动触发启动调用服务PUBLIC方法run() // 服务未运行手动触发启动调用服务PUBLIC方法run()
// mMainService.run(); mMainService.run();
// LogUtils.d(TAG, "服务未运行已通过PUBLIC方法触发启动"); LogUtils.d(TAG, "服务未运行已通过PUBLIC方法触发启动");
// } }
// 3. 检查SP中服务配置双重校验确保一致性 // 3. 检查SP中服务配置双重校验确保一致性
SharedPreferences sp = getSharedPreferences(SP_SERVICE_CONFIG, Context.MODE_PRIVATE); if (!AppConfigsUtil.getInstance(LocationActivity.this).isEnableMainService(true)) {
boolean isServiceConfigRunning = sp.getBoolean(KEY_SERVICE_RUNNING, false);
if (!isServiceConfigRunning) {
Toast.makeText(this, "位置服务配置未启用,数据可能无法更新", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "位置服务配置未启用,数据可能无法更新", Toast.LENGTH_SHORT).show();
} }
} }
@@ -142,6 +146,7 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
*/ */
private void cacheServiceData() { private void cacheServiceData() {
if (mMainService == null) { if (mMainService == null) {
ToastUtils.show("缓存数据失败:服务实例为空");
LogUtils.e(TAG, "缓存数据失败:服务实例为空"); LogUtils.e(TAG, "缓存数据失败:服务实例为空");
mCachedPositionList = new ArrayList<PositionModel>(); mCachedPositionList = new ArrayList<PositionModel>();
mCachedTaskList = new ArrayList<PositionTaskModel>(); mCachedTaskList = new ArrayList<PositionTaskModel>();
@@ -156,6 +161,7 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>(); if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>();
if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>(); if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>();
ToastUtils.show("缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size());
LogUtils.d(TAG, "缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size()); LogUtils.d(TAG, "缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size());
} }
@@ -175,6 +181,7 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
* 初始化Adapter通过缓存数据初始化数据更新时同步调用服务方法 * 初始化Adapter通过缓存数据初始化数据更新时同步调用服务方法
*/ */
private void initAdapter() { private void initAdapter() {
LogUtils.d(TAG, "initAdapter");
if (mCachedPositionList == null || mCachedTaskList == null) { if (mCachedPositionList == null || mCachedTaskList == null) {
LogUtils.e(TAG, "初始化Adapter失败缓存数据为空"); LogUtils.e(TAG, "初始化Adapter失败缓存数据为空");
return; return;

View File

@@ -107,7 +107,7 @@ public class MainService extends Service {
} }
private void run() { public void run() {
if (mAppConfigsUtil.isEnableMainService(true)) { if (mAppConfigsUtil.isEnableMainService(true)) {
if (_mIsServiceRunning == false) { if (_mIsServiceRunning == false) {
// 设置运行状态 // 设置运行状态
@@ -135,6 +135,10 @@ public class MainService extends Service {
} }
} }
} }
public boolean isServiceRunning() {
return _mIsServiceRunning;
}
public interface SMSListener { public interface SMSListener {
void speakMessage(); void speakMessage();

View File

@@ -53,11 +53,14 @@ public class AppConfigsUtil {
if (isReloadConfigs) { if (isReloadConfigs) {
loadConfigs(); loadConfigs();
} }
return mAppConfigsModel.isEnableMainService(); return (mAppConfigsModel == null) ?false: mAppConfigsModel.isEnableMainService();
} }
public void setIsEnableMainService(boolean isEnableMainService) { public void setIsEnableMainService(boolean isEnableMainService) {
if(mAppConfigsModel == null) {
mAppConfigsModel = new AppConfigsModel();
}
mAppConfigsModel.setIsEnableMainService(isEnableMainService); mAppConfigsModel.setIsEnableMainService(isEnableMainService);
saveConfigs(); saveConfigs();
} }

View File

@@ -16,7 +16,7 @@
<Switch <Switch
android:id="@+id/switch_service_control" android:id="@+id/switch_service_control"
android:layout_margin="16dp" android:layout_margin="16dp"
android:text="主要服务开关" android:text="GPS服务开关"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
@@ -25,7 +25,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp" android:layout_margin="16dp"
android:onClick="onPositions" android:onClick="onPositions"
android:text="进入位置管理" android:text="位置与任务管理"
android:id="@+id/btn_manage_positions"/> android:id="@+id/btn_manage_positions"/>
<Button <Button
@@ -33,7 +33,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp" android:layout_margin="16dp"
android:onClick="onLog" android:onClick="onLog"
android:text="查看操作日志"/> android:text="查看应用日志"/>
</LinearLayout> </LinearLayout>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">~笨笨龙~</string> <string name="app_name">寻龙记</string>
</resources> </resources>