build: v6 — WebView热更新修复 + fetch跨域设置

- versionCode 5→6
- WebView allowFileAccessFromFileURLs + mixedContent
- index.html 版本号v6
- index.html fetch检查更新+下载热更新完整链路
This commit is contained in:
LukeMackin
2026-07-21 14:55:57 +08:00
parent cd1f19815d
commit 0727aa33f1
3 changed files with 64 additions and 101 deletions

View File

@@ -9,7 +9,7 @@ android {
applicationId "dev.yuzu.gca"
minSdk 24
targetSdk 35
versionCode 5
versionCode 6
versionName "0.1.0"
}

View File

@@ -3,45 +3,49 @@
<style>
body{font-family:monospace;background:#0f172a;color:#e2e8f0;padding:16px;margin:0}
h1{font-size:18px;color:#38bdf8}
.btn{display:block;width:100%;padding:14px;margin:8px 0;border:none;border-radius:8px;
font-size:16px;cursor:pointer}
.btn{display:block;width:100%;padding:14px;margin:8px 0;border:none;border-radius:8px;font-size:16px;cursor:pointer}
.btn-check{background:#1e40af;color:#fff}
.btn-download{background:#15803d;color:#fff}
.log{background:#1e293b;padding:12px;border-radius:8px;margin-top:12px;
max-height:300px;overflow-y:auto;font-size:12px;white-space:pre-wrap}
.log{background:#1e293b;padding:12px;border-radius:8px;margin-top:12px;max-height:300px;overflow-y:auto;font-size:12px;white-space:pre-wrap}
.info{color:#94a3b8;font-size:12px;margin:4px 0}
.badge{display:inline-block;background:#f59e0b;color:#000;padding:2px 8px;border-radius:4px;font-size:11px;margin-left:8px}
</style></head><body>
<h1>Yuzu GCA</h1>
<div class="info">version <span id="ver">v0.1.0-dav-android-5</span></div>
<div class="info">version <span id="ver">v0.1.0-dav-android-6</span></div>
<button class="btn btn-check" onclick="checkUpdate()">检查更新</button>
<button class="btn btn-download" onclick="applyUpdate()" id="btnApply" disabled>下载更新</button>
<div class="log" id="log"></div>
<script>
var dlUrl='',dlVer='';
var BASE='https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota';
function log(m){document.getElementById('log').innerText+=m+'\n'}
function checkUpdate(){
log('正在检查...');
fetch('https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota/version.txt')
.then(r=>{if(!r.ok)throw Error('网络错误');return r.text()})
.then(t=>{t=t.trim();log('远程: '+t);
log('checking '+BASE+'/version.txt ...');
fetch(BASE+'/version.txt',{cache:'no-store'})
.then(r=>{if(!r.ok)throw Error('HTTP '+r.status);return r.text()})
.then(t=>{t=t.trim();log('remote: '+t);
var local=document.getElementById('ver').innerText;
if(t!==local){dlVer=t;dlUrl='https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/'+t+'/index.android.bundle';
log('有新版本!');document.getElementById('btnApply').disabled=false}
else log('已是最新')})
.catch(e=>log('失败: '+e.message))
if(t!==local){dlVer=t;dlUrl=BASE+'/h5/index-v6.html';
log('*** NEW VERSION: '+dlVer+' ***');document.getElementById('btnApply').disabled=false}
else log('up to date')})
.catch(e=>log('ERR: '+e.message))
}
function applyUpdate(){
log('下载中...');
fetch(dlUrl).then(r=>{if(!r.ok)throw Error('下载失败');return r.text()})
.then(t=>{localStorage.setItem('bundle',t);localStorage.setItem('ver',dlVer);
log('下载完成,重启生效');location.reload()})
.catch(e=>log('失败: '+e.message))
}
window.onload=function(){
var b=localStorage.getItem('bundle'),v=localStorage.getItem('ver');
if(b&&v){
document.getElementById('ver').innerText=v;
document.write(b);document.close()
log('downloading '+dlUrl+' ...');
fetch(dlUrl,{cache:'no-store'})
.then(r=>{if(!r.ok)throw Error('HTTP '+r.status);return r.text()})
.then(t=>{localStorage.setItem('gca_html',t);localStorage.setItem('gca_ver',dlVer);
log('OK reloading...');setTimeout(function(){location.reload()},400)})
.catch(e=>log('ERR: '+e.message))
}
(function(){
var b=localStorage.getItem('gca_html'),v=localStorage.getItem('gca_ver');
if(b&&v&&v!==document.getElementById('ver').innerText){
document.open();document.write(b);document.close()
}
})();
</script></body></html>

View File

@@ -7,6 +7,8 @@ import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
import android.widget.LinearLayout
import android.widget.ScrollView
@@ -29,93 +31,41 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val scroll = ScrollView(this)
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(24, 24, 24, 24)
val wv = WebView(this).apply {
WebView.setWebContentsDebuggingEnabled(true)
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = true
settings.allowFileAccessFromFileURLs = true
settings.allowUniversalAccessFromFileURLs = true
settings.mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if (url.startsWith("http")) { view.loadUrl(url); return true }
return false
}
}
addJavascriptInterface(AndroidBridge(this@MainActivity), "Android")
loadUrl("file:///android_asset/index.html")
}
setContentView(wv)
}
val title = TextView(this).apply {
text = "Yuzu GCA"
textSize = 20f
setPadding(0, 0, 0, 4)
}
layout.addView(title)
val versionInfo = TextView(this).apply {
text = "v0.1.0-dav-android-5-debug"
textSize = 12f
setTextColor(Color.GRAY)
setPadding(0, 0, 0, 12)
}
layout.addView(versionInfo)
val channelLabel = TextView(this).apply {
text = "选择更新渠道:"
textSize = 13f
setPadding(0, 8, 0, 4)
}
layout.addView(channelLabel)
// 渠道按钮行
val channelRow = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
setPadding(0, 0, 0, 12)
}
fun makeChannelBtn(label: String, channel: String): Button {
return Button(this).apply {
text = label
textSize = 12f
setOnClickListener {
selectedChannel = channel
highlightChannel(channelRow, this)
}
}
}
val btnStable = makeChannelBtn("Stable", "stable")
val btnBeta = makeChannelBtn("Beta", "beta")
val btnNightly = makeChannelBtn("Nightly", "nightly")
channelRow.addView(btnStable)
channelRow.addView(btnBeta)
channelRow.addView(btnNightly)
layout.addView(channelRow)
highlightChannel(channelRow, btnStable)
logView = TextView(this).apply {
textSize = 12f
setTextColor(Color.LTGRAY)
}
layout.addView(logView)
val btn = Button(this).apply {
text = "检查更新"
setOnClickListener {
val ch = selectedChannel
CoroutineScope(Dispatchers.IO).launch { doOtaTest(ch) }
}
}
layout.addView(btn)
scroll.addView(layout)
setContentView(scroll)
appendLog("渠道: stable | 点击[检查更新]开始")
}
private fun highlightChannel(row: LinearLayout, active: Button) {
for (i in 0 until row.childCount) {
val b = row.getChildAt(i) as Button
b.isSelected = (b == active)
inner class AndroidBridge(private val ctx: MainActivity) {
@android.webkit.JavascriptInterface
fun checkUpdate(channel: String) {
CoroutineScope(Dispatchers.IO).launch { doOtaTest(channel) }
}
@android.webkit.JavascriptInterface
fun log(msg: String) { appendLog(msg) }
}
private fun appendLog(msg: String) {
Log.i(TAG, msg)
if (::logView.isInitialized) {
runOnUiThread { logView.append("$msg\n") }
}
}
companion object { private const val TAG = "GCA-OTA" }
@@ -163,6 +113,15 @@ class MainActivity : AppCompatActivity() {
manifestTag = android.getString("tag")
appendLog(" 渠道: $channel 版本: $manifestTag")
appendLog(" SHA256: ${manifestSha256.take(16)}...")
// 版本比较:一致则跳过
val localTag = "v0.1.0-dav-android-${packageManager.getPackageInfo(packageName, 0).versionCode}"
if (manifestTag == localTag) {
appendLog(" ✅ 已是最新版本,无需更新")
appendLog("=== $channel 渠道测试完成 ===")
return@withContext
}
appendLog(" 发现新版本,开始更新...")
} catch (e: Exception) {
appendLog(" ❌ 解析失败: ${e.message}")
return@withContext