v2.2.5: Shebang patching + proot from nativeLib + Termux RUN_COMMAND + F-Droid fallback

This commit is contained in:
admin
2026-05-19 21:14:26 +04:00
Unverified
parent ce0cf20eaf
commit 71a26e259d
6 changed files with 230 additions and 107 deletions

View File

@@ -327,13 +327,24 @@
</div>
<div class="settings-section">
<h3>About</h3>
<p class="about-text">Z.AI Chat v2.2.4</p>
<p class="about-text">Z.AI Chat v2.2.5</p>
<p class="about-text">Built with Z.AI SDK &amp; GLM-5.1</p>
<p class="about-text">Compatible with Android 15/16</p>
</div>
<div class="settings-section">
<h3>Changelog</h3>
<ul class="changelog-list">
<li>
<span class="changelog-version">v2.2.5</span>
<span class="changelog-date">2026-05-19</span>
<ul>
<li><strong>Shebang Patching</strong> — all bin/ scripts patched to use #!/system/bin/sh (bypasses interpreter SELinux)</li>
<li><strong>Proot from APK nativeLib</strong> — uses proot directly from APK (apk_data_file SELinux label, always executable)</li>
<li><strong>Termux Integration</strong> — detects installed Termux, sends RUN_COMMAND to install tools</li>
<li><strong>F-Droid Fallback</strong> — opens Termux F-Droid page if not installed</li>
<li><strong>3-Strategy Install</strong> — direct → proot → Termux RUN_COMMAND → manual instructions</li>
</ul>
</li>
<li>
<span class="changelog-version">v2.2.4</span>
<span class="changelog-date">2026-05-19</span>

View File

@@ -1949,87 +1949,101 @@
termPrint('[*] This may take a few minutes...', 'info');
showStatusToast('Installing build tools...', 'info');
var methods = [];
var installCmd = 'export PREFIX="' + prefixUsr + '" LD_LIBRARY_PATH="' + prefixUsr + '/lib" && export PATH="' + prefixUsr + '/bin:/system/bin:$PATH" && ';
if (pkgTest.exitCode === 0) {
methods.push({cmd: 'export PREFIX="' + prefixUsr + '" PATH="' + prefixUsr + '/bin:$PATH" LD_LIBRARY_PATH="' + prefixUsr + '/lib" && sh "' + pkgBin + '" update -y 2>&1 && sh "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1', label: 'pkg'});
}
if (aptTest.exitCode === 0) {
methods.push({cmd: 'export PREFIX="' + prefixUsr + '" PATH="' + prefixUsr + '/bin:$PATH" LD_LIBRARY_PATH="' + prefixUsr + '/lib" && sh "' + aptBin + '" update -y 2>&1 && sh "' + aptBin + '" install -y aapt2 ecj dx apksigner 2>&1', label: 'apt'});
installCmd += 'sh "' + pkgBin + '" update -y 2>&1 && sh "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1';
} else {
installCmd += 'sh "' + aptBin + '" update -y 2>&1 && sh "' + aptBin + '" install -y aapt2 ecj dx apksigner 2>&1';
}
for (var m = 0; m < methods.length; m++) {
termPrint('[*] Attempt ' + (m + 1) + ' (' + methods[m].label + ')...', 'info');
var installResult = await shellExec(methods[m].cmd, termState.homeDir, false);
if (installResult.output) {
var out = installResult.output;
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
termPrint(out.replace(/\n$/, ''), '');
}
termPrint('[*] Strategy 1: Direct execution (patched shebangs)...', 'info');
var result = await shellExec(installCmd, termState.homeDir, false);
if (result.output) {
var out = result.output;
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
termPrint(out.replace(/\n$/, ''), '');
}
if (await toolsReady()) { termPrint('[OK] Build tools installed!', 'success'); return true; }
var recheck = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
if (recheck.exitCode === 0) {
termPrint('[OK] Build tools installed successfully!', 'success');
showStatusToast('Build tools installed!', 'success');
termState.devToolsInstalled = true;
return true;
}
termPrint('[*] Strategy 2: Bundled PRoot...', 'info');
if (termState.prootPath) {
termPrint('[OK] PRoot from APK: ' + termState.prootPath, 'success');
var prootOk = await tryProotExec(termState.prootPath, prefixUsr, pkgBin, aptBin);
if (prootOk) return true;
} else {
termPrint('[!] No bundled PRoot found', 'warning');
}
termPrint('[*] Direct execution failed. Trying PRoot workaround...', 'info');
var prootOk = await tryProotInstall(prefixUsr, pkgBin, aptBin);
if (prootOk) return true;
termPrint('[*] Strategy 3: Termux RUN_COMMAND...', 'info');
var termuxOk = await tryTermuxInstall();
if (termuxOk) return true;
termPrint('', '');
termPrint('[!] Auto-install failed. Android SELinux may be blocking binary execution.', 'err');
termPrint('[*] Fallback options:', 'warning');
termPrint(' 1. Install Termux from F-Droid, then run:', 'warning');
termPrint(' pkg install aapt2 ecj dx apksigner', 'warning');
termPrint(' 2. Z.AI Chat will auto-detect Termux tools.', 'warning');
termPrint('[!] All auto-install strategies failed.', 'err');
termPrint('[*] Manual fix: Install Termux from F-Droid:', 'warning');
termPrint(' 1. Open: https://f-droid.org/en/packages/com.termux/', 'warning');
termPrint(' 2. Install Termux, open it, run:', 'warning');
termPrint(' pkg update && pkg install aapt2 ecj dx apksigner', 'warning');
termPrint(' 3. Restart Z.AI Chat — tools will be detected.', 'warning');
termState.devToolsInstalled = false;
return false;
}
async function tryProotInstall(prefixUsr, pkgBin, aptBin) {
var prootCmd = termState.prootPath;
if (!prootCmd) {
try {
var prootResult = await Bootstrap.installProot();
if (prootResult && prootResult.path) {
prootCmd = prootResult.path;
termState.prootPath = prootCmd;
termState.hasProot = true;
}
} catch(e) {
termPrint('[!] PRoot download failed: ' + e.message, 'err');
}
async function toolsReady() {
var recheck = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
if (recheck.exitCode === 0) {
showStatusToast('Build tools installed!', 'success');
termState.devToolsInstalled = true;
return true;
}
return false;
}
if (!prootCmd) {
termPrint('[!] No PRoot available', 'err');
return false;
}
termPrint('[OK] PRoot available: ' + prootCmd, 'success');
var pkgCmd = 'sh "' + pkgBin + '" update -y 2>&1 && sh "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1';
async function tryProotExec(prootCmd, prefixUsr, pkgBin, aptBin) {
var pkgCmd = 'sh /usr/bin/pkg update -y 2>&1 && sh /usr/bin/pkg install -y aapt2 ecj dx apksigner 2>&1';
if (!new File(pkgBin).exists) pkgCmd = 'sh /usr/bin/apt update -y 2>&1 && sh /usr/bin/apt install -y aapt2 ecj dx apksigner 2>&1';
var wrappedCmd = prootCmd + ' -0 -b /dev -b /proc -b /sys -r ' + prefixUsr + ' /bin/sh -c \'' + pkgCmd.replace(/'/g, "'\\''") + '\'';
termPrint('[*] Installing via PRoot...', 'info');
termPrint('[*] Running pkg via PRoot...', 'info');
var result = await shellExec(wrappedCmd, termState.homeDir, false);
if (result.output) {
var out = result.output;
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
termPrint(out.replace(/\n$/, ''), '');
}
if (result.exitCode === 0 || result.output.indexOf('Setting up') !== -1) {
if (await toolsReady()) return true;
}
termPrint('[!] PRoot strategy failed (exit ' + result.exitCode + ')', 'err');
return false;
}
var recheck = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
if (recheck.exitCode === 0) {
termPrint('[OK] Build tools installed via PRoot!', 'success');
showStatusToast('Build tools installed!', 'success');
termState.devToolsInstalled = true;
return true;
async function tryTermuxInstall() {
if (!Bootstrap) return false;
var termuxInfo;
try { termuxInfo = await Bootstrap.isTermuxInstalled(); } catch(e) { return false; }
if (!termuxInfo.installed) {
termPrint('[!] Termux not installed. Opening F-Droid...', 'warning');
try { await Bootstrap.openTermuxPage(); } catch(e) {}
termPrint('[*] After installing Termux:', 'info');
termPrint(' 1. Open Termux app', 'info');
termPrint(' 2. Run: pkg update && pkg install aapt2 ecj dx apksigner', 'info');
termPrint(' 3. Come back to Z.AI Chat', 'info');
return false;
}
termPrint('[!] PRoot execution result: exit code ' + result.exitCode, 'err');
termPrint('[OK] Termux detected! Sending install command...', 'success');
try {
var runResult = await Bootstrap.runInTermux({command: 'pkg update -y && pkg install -y aapt2 ecj dx apksigner'});
termPrint('[*] Command sent to Termux. Waiting...', 'info');
await new Promise(function(r) { setTimeout(r, 15000); });
if (await toolsReady()) return true;
await new Promise(function(r) { setTimeout(r, 30000); });
if (await toolsReady()) return true;
} catch(e) {
termPrint('[!] Termux RUN_COMMAND failed: ' + e.message, 'err');
}
return false;
}