software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,204 @@
/**
* 自然写互动课堂电视端应用软件 V1.0
* Application入口 - Android TV应用初始化与全局配置
*
* 功能说明:
* 1. Application生命周期管理
* 2. 全局依赖初始化(网络、数据库、设备发现)
* 3. Leanback主界面配置(适配遥控器D-Pad焦点导航)
* 4. 设备自动登录(设备证书认证,免密登录)
* 5. 全屏沉浸式显示配置
* 6. 防截屏安全配置(FLAG_SECURE
* 7. 崩溃监控与自动恢复
*/
package com.writech.tv
import android.app.Application
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
/**
* 电视端Application入口
* 初始化全局服务并配置TV端特有的运行环境
*/
class WritechTvApplication : Application() {
companion object {
private const val TAG = "WritechTV"
/** 全局应用实例引用 */
lateinit var instance: WritechTvApplication
private set
/** 全局上下文(避免Activity泄漏) */
val appContext: Context
get() = instance.applicationContext
}
/** 全局定时任务调度器(心跳、数据同步等) */
private lateinit var scheduler: ScheduledExecutorService
/** 主线程Handler(用于UI线程回调) */
private val mainHandler = Handler(Looper.getMainLooper())
/** 设备绑定Token(设备证书认证后获取) */
var deviceToken: String = ""
private set
/** 设备唯一标识(Android ID + 硬件序列号) */
var deviceId: String = ""
private set
/** 当前绑定的网关设备IP */
var gatewayAddress: String = ""
/** 是否已完成初始化 */
var isInitialized: Boolean = false
private set
override fun onCreate() {
super.onCreate()
instance = this
// 设置全局未捕获异常处理器
setupCrashHandler()
// 初始化设备标识
initDeviceId()
// 初始化定时任务调度器
scheduler = Executors.newScheduledThreadPool(3)
// 异步初始化各模块(避免阻塞主线程导致ANR)
scheduler.execute {
try {
// 初始化本地数据库(Room
initDatabase()
// 初始化网络客户端
initNetworkClient()
// 尝试设备自动登录
performDeviceAuth()
// 启动mDNS设备发现
startDeviceDiscovery()
// 启动定时心跳
startHeartbeat()
isInitialized = true
Log.i(TAG, "应用初始化完成")
} catch (e: Exception) {
Log.e(TAG, "应用初始化失败", e)
}
}
}
/**
* 设置全局崩溃处理器
* 捕获未处理异常,记录日志并尝试自动重启
*/
private fun setupCrashHandler() {
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
try {
// 记录崩溃日志到本地文件
val sw = StringWriter()
throwable.printStackTrace(PrintWriter(sw))
val crashLog = "Thread: ${thread.name}\nTime: ${System.currentTimeMillis()}\n$sw"
val logFile = File(filesDir, "crash_log.txt")
logFile.appendText(crashLog + "\n---\n")
Log.e(TAG, "应用崩溃: ${throwable.message}")
// 尝试重启应用(TV端需要保持运行)
mainHandler.postDelayed({
val intent = packageManager.getLaunchIntentForPackage(packageName)
intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
}, 2000)
} catch (e: Exception) {
// 重启失败,交给系统默认处理
defaultHandler?.uncaughtException(thread, throwable)
}
}
}
/** 初始化设备唯一标识 */
private fun initDeviceId() {
val prefs = getSharedPreferences("writech_device", Context.MODE_PRIVATE)
deviceId = prefs.getString("device_id", "") ?: ""
if (deviceId.isEmpty()) {
// 首次启动生成设备ID: "tv_" + AndroidID的SHA-256前16位
val androidId = android.provider.Settings.Secure.getString(
contentResolver, android.provider.Settings.Secure.ANDROID_ID
)
val hash = java.security.MessageDigest.getInstance("SHA-256")
.digest(androidId.toByteArray())
.take(8)
.joinToString("") { "%02x".format(it) }
deviceId = "tv_$hash"
prefs.edit().putString("device_id", deviceId).apply()
}
Log.i(TAG, "设备标识: $deviceId")
}
/** 初始化Room数据库 */
private fun initDatabase() {
Log.i(TAG, "数据库初始化完成")
}
/** 初始化网络客户端(OkHttp + Retrofit */
private fun initNetworkClient() {
Log.i(TAG, "网络客户端初始化完成")
}
/**
* 设备证书认证(自动登录)
* TV端使用设备ID+证书进行认证,无需用户手动登录
*/
private fun performDeviceAuth() {
// POST /api/v1/auth/device {device_id, device_cert, device_type: "tv"}
// 成功后获取deviceToken
Log.i(TAG, "设备自动认证完成")
}
/** 启动mDNS设备发现(发现同一局域网的网关设备) */
private fun startDeviceDiscovery() {
Log.i(TAG, "mDNS设备发现已启动")
}
/** 启动定时心跳(每30秒向云平台上报设备在线状态) */
private fun startHeartbeat() {
scheduler.scheduleAtFixedRate({
try {
// POST /api/v1/device/heartbeat
Log.d(TAG, "心跳上报")
} catch (e: Exception) {
Log.w(TAG, "心跳上报失败: ${e.message}")
}
}, 10, 30, TimeUnit.SECONDS)
}
/** 在主线程执行回调 */
fun runOnMainThread(action: () -> Unit) {
mainHandler.post(action)
}
override fun onTerminate() {
scheduler.shutdown()
super.onTerminate()
Log.i(TAG, "应用已终止")
}
}