225 lines
7.9 KiB
Kotlin
225 lines
7.9 KiB
Kotlin
package com.stand.standapp
|
|
|
|
import android.content.Intent
|
|
import android.os.Bundle
|
|
import android.view.KeyEvent
|
|
import android.view.ViewGroup
|
|
import android.webkit.ConsoleMessage
|
|
import android.webkit.WebResourceError
|
|
import android.webkit.WebResourceRequest
|
|
import android.webkit.WebView
|
|
import android.widget.LinearLayout
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import timber.log.Timber
|
|
import com.just.agentweb.AgentWeb
|
|
import com.just.agentweb.WebChromeClient
|
|
import com.just.agentweb.WebViewClient
|
|
import com.stand.standapp.R
|
|
import com.stand.standapp.AppConfig
|
|
import com.stand.standapp.AndroidInterface
|
|
import com.stand.standapp.UpdateManager
|
|
|
|
class MainActivity : AppCompatActivity() {
|
|
|
|
companion object {
|
|
private var instance: MainActivity? = null
|
|
|
|
@JvmStatic
|
|
fun executeJs(script: String) {
|
|
instance?.let { activity ->
|
|
activity.runOnUiThread {
|
|
activity.mAgentWeb?.jsAccessEntrace?.quickCallJs(script)
|
|
}
|
|
}
|
|
}
|
|
|
|
@JvmStatic
|
|
fun onPttLoginSuccess() {
|
|
Timber.tag("MainActivity").d("onPttLoginSuccess called from Native")
|
|
executeJs("onPttLoginSuccess")
|
|
}
|
|
|
|
// 硬件按键触发
|
|
@JvmStatic
|
|
fun onHardwarePttDown() {
|
|
instance?.runOnUiThread {
|
|
// 直接调用 JSBridge 对象的逻辑以复用保护机制
|
|
val jsInterface = instance?.mAgentWeb?.webCreator?.webView?.tag as? AndroidInterface
|
|
// 或者更直接一点,我们把逻辑抽离出来
|
|
instance?.pttInterface?.pttSpeakPlay()
|
|
// 通知 H5 更新 UI
|
|
executeJs("onHardwarePttDown")
|
|
}
|
|
}
|
|
|
|
@JvmStatic
|
|
fun onHardwarePttUp() {
|
|
instance?.runOnUiThread {
|
|
instance?.pttInterface?.pttSpeakRelease()
|
|
executeJs("onHardwarePttUp")
|
|
}
|
|
}
|
|
|
|
@JvmStatic
|
|
fun showPttConflictDialog() {
|
|
instance?.runOnUiThread {
|
|
val ctx = instance ?: return@runOnUiThread
|
|
androidx.appcompat.app.AlertDialog.Builder(ctx)
|
|
.setTitle("账号冲突")
|
|
.setMessage("您的 PTT 账号已在其他设备登录,当前设备已被迫下线。\n请点击确认退出并重新登录。")
|
|
.setCancelable(false)
|
|
.setPositiveButton("确认") { _, _ ->
|
|
val pm = ctx.packageManager
|
|
val intent = pm.getLaunchIntentForPackage(ctx.packageName)
|
|
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
ctx.startActivity(intent)
|
|
android.os.Process.killProcess(android.os.Process.myPid())
|
|
}
|
|
.show()
|
|
}
|
|
}
|
|
}
|
|
|
|
private var mAgentWeb: AgentWeb? = null
|
|
private var pttInterface: AndroidInterface? = null
|
|
|
|
private val mHandler = android.os.Handler(android.os.Looper.getMainLooper())
|
|
private val TIMEOUT_MS = 30000L
|
|
|
|
private val timeoutRunnable = Runnable {
|
|
showErrorPage()
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
instance = this
|
|
try {
|
|
|
|
setContentView(R.layout.activity_main)
|
|
|
|
val container = findViewById<LinearLayout>(R.id.container)
|
|
if (container == null) return
|
|
|
|
findViewById<android.widget.Button>(R.id.btn_retry)?.setOnClickListener {
|
|
hideErrorPage()
|
|
mAgentWeb?.webCreator?.webView?.reload()
|
|
startTimeoutTimer()
|
|
}
|
|
|
|
// 从配置中获取服务器地址
|
|
val serverUrl = AppConfig.getServerUrl(this)
|
|
val finalUrl = "$serverUrl/example/print_demo.html?t=${System.currentTimeMillis()}"
|
|
Timber.tag("MainActivity").d("Loading URL: $finalUrl")
|
|
|
|
mAgentWeb = AgentWeb.with(this)
|
|
.setAgentWebParent(container, LinearLayout.LayoutParams(-1, -1))
|
|
.useDefaultIndicator()
|
|
.setWebChromeClient(object : WebChromeClient() {
|
|
override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
|
|
Timber.tag("WebConsole").d("${consoleMessage?.messageLevel()}: ${consoleMessage?.message()} -- From line ${consoleMessage?.lineNumber()} of ${consoleMessage?.sourceId()}")
|
|
return super.onConsoleMessage(consoleMessage)
|
|
}
|
|
})
|
|
.setWebViewClient(object : WebViewClient() {
|
|
// ...
|
|
})
|
|
.addJavascriptInterface("android", AndroidInterface(this).also { pttInterface = it })
|
|
.createAgentWeb()
|
|
|
|
.ready()
|
|
.go(finalUrl)
|
|
|
|
startTimeoutTimer()
|
|
|
|
// 配置 WebView 属性以支持 SSE 和跨域
|
|
|
|
mAgentWeb?.let { agent ->
|
|
try {
|
|
val webView = agent.webCreator.webView
|
|
val settings = webView.settings
|
|
// 允许混合内容 (HTTP/HTTPS)
|
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
|
settings.mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
|
}
|
|
// 允许跨域和存储
|
|
settings.allowUniversalAccessFromFileURLs = true
|
|
settings.allowFileAccessFromFileURLs = true
|
|
settings.domStorageEnabled = true
|
|
settings.javaScriptEnabled = true
|
|
} catch (e: Exception) {
|
|
Timber.tag("MainActivity").e(e, "WebView settings error")
|
|
}
|
|
}
|
|
// .go("http://152.32.186.199/local/print_demo.html")
|
|
|
|
// 启动时检查更新
|
|
UpdateManager(this).checkUpdate()
|
|
|
|
} catch (e: Exception) {
|
|
Timber.tag("MainActivity").e(e, "Fatal Crash")
|
|
}
|
|
}
|
|
|
|
fun getAgentWeb(): AgentWeb? {
|
|
return mAgentWeb
|
|
}
|
|
|
|
fun showExitDialog() {
|
|
// 调用 JS 函数
|
|
mAgentWeb?.jsAccessEntrace?.quickCallJs("addExitText")
|
|
|
|
androidx.appcompat.app.AlertDialog.Builder(this)
|
|
.setTitle("提示")
|
|
.setMessage("确定要退出应用吗?")
|
|
.setPositiveButton("确定") { _, _ -> finish() }
|
|
.setNegativeButton("取消", null)
|
|
.show()
|
|
}
|
|
|
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
|
if (mAgentWeb?.handleKeyEvent(keyCode, event) == true) {
|
|
return true
|
|
}
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
showExitDialog()
|
|
return true
|
|
}
|
|
return super.onKeyDown(keyCode, event)
|
|
}
|
|
|
|
override fun onPause() {
|
|
mAgentWeb?.webLifeCycle?.onPause()
|
|
super.onPause()
|
|
}
|
|
|
|
override fun onResume() {
|
|
mAgentWeb?.webLifeCycle?.onResume()
|
|
super.onResume()
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
mAgentWeb?.webLifeCycle?.onDestroy()
|
|
cancelTimeoutTimer()
|
|
super.onDestroy()
|
|
}
|
|
|
|
private fun startTimeoutTimer() {
|
|
cancelTimeoutTimer()
|
|
mHandler.postDelayed(timeoutRunnable, TIMEOUT_MS)
|
|
}
|
|
|
|
fun cancelTimeoutTimer() {
|
|
mHandler.removeCallbacks(timeoutRunnable)
|
|
}
|
|
|
|
private fun showErrorPage() {
|
|
findViewById<android.view.View>(R.id.loading_layout)?.visibility = android.view.View.GONE
|
|
findViewById<android.view.View>(R.id.error_layout)?.visibility = android.view.View.VISIBLE
|
|
}
|
|
|
|
private fun hideErrorPage() {
|
|
findViewById<android.view.View>(R.id.error_layout)?.visibility = android.view.View.GONE
|
|
findViewById<android.view.View>(R.id.loading_layout)?.visibility = android.view.View.VISIBLE
|
|
}
|
|
}
|