Files
WinBoLL/libappbase/src/main/java/cc/winboll/studio/libappbase/GlobalApplication.java

225 lines
8.8 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cc.winboll.studio.libappbase;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/11 19:56
* @Describe 全局 Application 类,用于初始化应用核心组件、管理全局状态(如调试模式)
* 需在 AndroidManifest.xml 中配置 android:name=".GlobalApplication" 使其生效
*/
public class GlobalApplication extends Application {
/** 日志标签 */
public static final String TAG = "GlobalApplication";
/** 全局 Application 单例实例volatile 保证多线程可见性,避免指令重排) */
private static volatile GlobalApplication sInstance;
/**
* 应用调试模式标记volatile 保证多线程可见性)
* true调试模式开启日志、调试功能false正式模式关闭调试相关功能
*/
private static volatile boolean isDebugging = false;
// 新增WinBoLL 服务器主机地址volatile 保证多线程可见性)
private static volatile String winbollHost = null;
// 新增SP 存储相关常量(私有存储,仅当前应用可访问)
private static final String SP_NAME = "WinBoLL_SP_CONFIG";
private static final String SP_KEY_WINBOLL_HOST = "winboll_host";
/**
* 获取全局 Application 单例实例(外部可通过此方法获取上下文)
* @return GlobalApplication 单例(未初始化时返回 null需确保配置 AndroidManifest
*/
public static GlobalApplication getInstance() {
return sInstance;
}
/**
* 设置应用调试模式
* @param debugging 调试模式状态true/false
*/
public static void setIsDebugging(boolean debugging) {
isDebugging = debugging;
}
/**
* 保存调试模式状态到本地文件(持久化存储,重启应用后生效)
* @param application 全局 Application 实例(通过 getInstance() 获取更规范)
*/
public static void saveDebugStatus(GlobalApplication application) {
if (application == null) {
LogUtils.e(TAG, "saveDebugStatus: Application 实例为空,保存失败");
return;
}
// 将调试状态封装为 APPModel 并保存到文件
APPModel.saveBeanToFile(
getAppModelFilePath(application),
new APPModel(isDebugging)
);
}
/**
* 获取 APPModel 配置文件的存储路径
* 路径:应用私有数据目录 / APPModel.json仅当前应用可访问安全
* @param application 全局 Application 实例
* @return 配置文件绝对路径
*/
private static String getAppModelFilePath(GlobalApplication application) {
return application.getDataDir().getPath() + "/APPModel.json";
}
/**
* 获取当前应用调试模式状态
* @return true调试模式false正式模式
*/
public static boolean isDebugging() {
return isDebugging;
}
// 新增:设置 WinBoLL 服务器主机地址(同时保存到 SP 持久化)
public static void setWinbollHost(String host) {
if (sInstance == null) {
LogUtils.e(TAG, "setWinbollHost: 应用未初始化,设置失败");
return;
}
// 检查并补全末尾 / 核心改动
if (host != null && !host.isEmpty() && !host.endsWith("/")) {
host += "/";
}
// 更新内存中的字段
winbollHost = host;
// 保存到 SP 持久化(私有模式,安全)
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().putString(SP_KEY_WINBOLL_HOST, host).apply();
LogUtils.d(TAG, "setWinbollHost: 服务器地址已设置并持久化host=" + host);
}
// 新增:获取 WinBoLL 服务器主机地址(优先内存,内存为空则从 SP 读取)
public static String getWinbollHost() {
if (winbollHost != null) {
// 内存中存在,直接返回(提高效率)
return winbollHost;
}
if (sInstance == null) {
LogUtils.e(TAG, "getWinbollHost: 应用未初始化,获取失败");
return null;
}
// 内存中不存在,从 SP 读取并更新到内存
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
winbollHost = sp.getString(SP_KEY_WINBOLL_HOST, "https://console.winboll.cc/");
LogUtils.d(TAG, "getWinbollHost: 从 SP 读取服务器地址host=" + winbollHost);
return winbollHost;
}
/**
* 应用启动时初始化(仅执行一次)
* 初始化核心框架、恢复调试状态、配置全局异常处理等
*/
@Override
public void onCreate() {
super.onCreate();
// 初始化单例实例(确保在所有初始化操作前完成)
sInstance = this;
// 初始化基础组件日志、崩溃处理、Toast
initCoreComponents();
// 恢复/初始化调试模式状态(从本地文件读取,无文件则默认关闭调试)
restoreDebugStatus();
// 新增:初始化服务器地址(从 SP 读取到内存,提高后续访问效率)
initWinbollHost();
LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建");
}
/**
* 初始化应用核心组件日志、崩溃处理、Toast 框架)
*/
private void initCoreComponents() {
// 初始化日志工具(传入 Application 上下文)
LogUtils.init(this);
// 初始化全局异常处理器(捕获应用崩溃信息,用于调试或上报)
CrashHandler.init(this);
// 初始化 Toast 工具(统一 Toast 样式、避免内存泄漏等)
ToastUtils.init(this);
}
/**
* 恢复调试模式状态(从本地配置文件读取)
* 1. 读取本地 APPModel.json 文件
* 2. 读取成功:使用保存的调试状态;读取失败(文件不存在):默认关闭调试并创建配置文件
*/
private void restoreDebugStatus() {
// 从文件加载 APPModel 实例(存储调试状态的模型类)
APPModel appModel = APPModel.loadBeanFromFile(
getAppModelFilePath(this),
APPModel.class
);
if (appModel == null) {
// 配置文件不存在,默认关闭调试模式并创建文件
setIsDebugging(false);
saveDebugStatus(this);
LogUtils.d(TAG, "调试配置文件不存在,默认关闭调试模式并创建配置文件");
} else {
// 配置文件存在,使用保存的调试状态
setIsDebugging(appModel.isDebugging());
LogUtils.d(TAG, "从配置文件恢复调试模式:" + isDebugging);
}
}
// 新增:初始化服务器地址(应用启动时从 SP 读取到内存)
private void initWinbollHost() {
getWinbollHost(); // 触发从 SP 读取并更新内存
}
/**
* 获取应用名称(从 AndroidManifest.xml 的 android:label 读取)
* @param context 上下文(建议传入 Application 上下文,避免内存泄漏)
* @return 应用名称(读取失败返回 null
*/
public static String getAppName(Context context) {
if (context == null) {
LogUtils.w(TAG, "getAppName: 上下文为空,返回 null");
return null;
}
PackageManager packageManager = context.getPackageManager();
try {
// 获取应用信息(包含应用名称、图标等)
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(
context.getPackageName(), // 当前应用包名
0 // 额外标志0 表示默认获取基本信息)
);
// 从应用信息中获取应用名称(支持多语言)
String appName = (String) packageManager.getApplicationLabel(applicationInfo);
LogUtils.d(TAG, "获取应用名称成功:" + appName);
return appName;
} catch (NameNotFoundException e) {
// 包名不存在(理论上不会发生,捕获异常避免崩溃)
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//LogUtils.e(TAG, "获取应用名称失败:包名不存在", e);
e.printStackTrace();
}
return null;
}
/**
* 应用终止时调用(仅用于释放全局资源)
*/
@Override
public void onTerminate() {
super.onTerminate();
// 释放单例引用(可选,避免内存泄漏风险)
sInstance = null;
LogUtils.d(TAG, "GlobalApplication 终止,单例实例已释放");
}
}