fix: allowUniversalAccessFromFileURLs(CORS审查)
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,user-scalable=no">
|
||||
<title>Yuzu GCA</title>
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
body{font-family:system-ui;background:#0f172a;color:#e2e8f0;padding:16px}
|
||||
h1{font-size:20px;color:#38bdf8;margin-bottom:4px}
|
||||
.info{color:#94a3b8;font-size:12px;margin-bottom:16px}
|
||||
.card{background:#1e293b;border-radius:8px;padding:16px;margin:12px 0}
|
||||
.card-title{font-size:13px;color:#94a3b8;margin-bottom:8px}
|
||||
.btn{display:block;width:100%;padding:14px;margin:8px 0;border:none;border-radius:8px;font-size:15px;cursor:pointer;color:#fff}
|
||||
.btn-blue{background:#1e40af}
|
||||
.btn-green{background:#15803d}
|
||||
.btn-red{background:#991b1b}
|
||||
.input{display:block;width:100%;padding:12px;margin:8px 0;border:none;border-radius:8px;font-size:14px;background:#0f172a;color:#e2e8f0}
|
||||
.log{background:#0a0f1a;padding:12px;border-radius:8px;margin-top:8px;max-height:200px;overflow-y:auto;font-size:11px;white-space:pre-wrap;color:#22c55e;font-family:monospace}
|
||||
.tab{display:inline-block;padding:8px 16px;margin-right:4px;border-radius:6px 6px 0 0;background:#1e293b;color:#64748b;font-size:13px;cursor:pointer}
|
||||
.tab-on{background:#1e40af;color:#fff}
|
||||
</style></head><body>
|
||||
<h1>Yuzu GCA</h1>
|
||||
<div class="info">Self-contained MCP Client</div>
|
||||
|
||||
<div>
|
||||
<span class="tab tab-on" onclick="switchTab('exec')">Exec</span>
|
||||
<span class="tab" onclick="switchTab('files')">Files</span>
|
||||
<span class="tab" onclick="switchTab('sysinfo')">SysInfo</span>
|
||||
</div>
|
||||
|
||||
<div class="card" id="tab-exec">
|
||||
<div class="card-title">Execute Command (Gateway)</div>
|
||||
<input class="input" id="gwUrl" placeholder="Gateway URL (http://x.x.x.x:3000)" value="http://10.1.0.17:3000">
|
||||
<input class="input" id="cmd" placeholder="Command (e.g. ls, whoami, dir)">
|
||||
<button class="btn btn-blue" onclick="execCmd()">Execute</button>
|
||||
<div class="log" id="log-exec"></div>
|
||||
</div>
|
||||
|
||||
<div class="card" id="tab-files" style="display:none">
|
||||
<div class="card-title">List Files (Gateway)</div>
|
||||
<input class="input" id="path" placeholder="Path (e.g. /sdcard, .)" value=".">
|
||||
<button class="btn btn-blue" onclick="listFiles()">List</button>
|
||||
<div class="log" id="log-files"></div>
|
||||
</div>
|
||||
|
||||
<div class="card" id="tab-sysinfo" style="display:none">
|
||||
<div class="card-title">System Info (Local)</div>
|
||||
<button class="btn btn-blue" onclick="showSysInfo()">Refresh</button>
|
||||
<div class="log" id="log-sysinfo"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchTab(t){
|
||||
document.querySelectorAll('.tab').forEach(e=>e.classList.toggle('tab-on',false));
|
||||
document.querySelectorAll('.card').forEach(e=>e.style.display='none');
|
||||
document.getElementById('tab-'+t).style.display='block';
|
||||
event.target.classList.toggle('tab-on',true);
|
||||
}
|
||||
|
||||
function log(id,msg){
|
||||
var l=document.getElementById(id);
|
||||
l.innerText+=msg+'\n';l.scrollTop=l.scrollHeight;
|
||||
}
|
||||
|
||||
function execCmd(){
|
||||
var gw=document.getElementById('gwUrl').value,c=document.getElementById('cmd').value;
|
||||
var id='log-exec';document.getElementById(id).innerText='';
|
||||
log(id,'$ '+c);
|
||||
fetch(gw+'/tools/exec',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({command:c})})
|
||||
.then(r=>r.json()).then(d=>log(id,d.stdout||d.stderr||JSON.stringify(d)))
|
||||
.catch(e=>log(id,'ERR: '+e.message));
|
||||
}
|
||||
|
||||
function listFiles(){
|
||||
var gw=document.getElementById('gwUrl').value,p=document.getElementById('path').value;
|
||||
var id='log-files';document.getElementById(id).innerText='';
|
||||
log(id,'ls '+p);
|
||||
fetch(gw+'/tools/file_list',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p})})
|
||||
.then(r=>r.json()).then(d=>{
|
||||
if(d.entries){d.entries.forEach(e=>log(id,(e.type==='dir'?'[DIR]':'')+' '+e.name+(e.size?' ('+e.size+'B)':'')))}
|
||||
else log(id,JSON.stringify(d));
|
||||
}).catch(e=>log(id,'ERR: '+e.message));
|
||||
}
|
||||
|
||||
function showSysInfo(){
|
||||
var id='log-sysinfo';document.getElementById(id).innerText='';
|
||||
log(id,'Platform: '+navigator.platform);
|
||||
log(id,'UserAgent: '+navigator.userAgent);
|
||||
log(id,'Online: '+navigator.onLine);
|
||||
if(typeof Android!=='undefined'){log(id,'Bridge: YES');log(id,'Files: '+Android.fetchText('version.txt'))}
|
||||
else log(id,'Bridge: NO');
|
||||
}
|
||||
</script></body></html>
|
||||
@@ -1,12 +1,17 @@
|
||||
package dev.yuzu.gca
|
||||
|
||||
import com.facebook.react.ReactActivity
|
||||
import com.facebook.react.ReactActivityDelegate
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
||||
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
||||
import android.os.Bundle
|
||||
import android.webkit.WebView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class MainActivity : ReactActivity() {
|
||||
override fun getMainComponentName(): String = "main"
|
||||
override fun createReactActivityDelegate(): ReactActivityDelegate =
|
||||
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
|
||||
class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
WebView(this).apply {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.domStorageEnabled = true
|
||||
settings.allowUniversalAccessFromFileURLs = true
|
||||
loadUrl("file:///android_asset/index.html")
|
||||
}.also { setContentView(it) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user