Update code to v1.0.12+2

wakelock, modified proot with binfmt-like feature, more wine scripts
This commit is contained in:
Caten
2023-12-11 15:07:07 +08:00
parent b3428555c6
commit 938745036d
14 changed files with 388 additions and 98 deletions

View File

@@ -31,6 +31,7 @@ import 'package:permission_handler/permission_handler.dart';
//import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:xterm/xterm.dart';
//import 'package:xterm/flutter.dart';
import 'package:tiny_computer/workflow.dart';
@@ -239,8 +240,9 @@ class _SettingPageState extends State<SettingPage> {
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("开启时启动图形界面"), value: Util.getGlobal("autoLaunchVnc") as bool, onChanged:(value) {
G.prefs.setBool("autoLaunchVnc", value);
SwitchListTile(title: const Text("屏幕常亮"), value: Util.getGlobal("wakelock") as bool, onChanged:(value) {
G.prefs.setBool("wakelock", value);
WakelockPlus.toggle(enable: value);
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
@@ -248,6 +250,11 @@ class _SettingPageState extends State<SettingPage> {
SizedBox.fromSize(size: const Size.square(16)),
const Text("以下选项修改后将在下次启动软件时生效。"),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("开启时启动图形界面"), value: Util.getGlobal("autoLaunchVnc") as bool, onChanged:(value) {
G.prefs.setBool("autoLaunchVnc", value);
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("重新安装引导包"), value: Util.getGlobal("reinstallBootstrap") as bool, onChanged:(value) {
G.prefs.setBool("reinstallBootstrap", value);
setState(() {});
@@ -329,7 +336,7 @@ class _SettingPageState extends State<SettingPage> {
}
break;
case false: {
G.streamServerPty.write(const Utf8Encoder().convert("${String.fromCharCode(3)}exit\n"));
G.streamServerPty.write(const Utf8Encoder().convert("\x03exit\n"));
}
break;
}
@@ -398,7 +405,7 @@ class _SettingPageState extends State<SettingPage> {
switch (value) {
case true: {
G.virglServerPty = Pty.start("/system/bin/sh");
G.virglServerPty.write(const Utf8Encoder().convert("export CONTAINER_DIR=${G.dataPath}/containers/0\n${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}\nexit\n"));
G.virglServerPty.write(const Utf8Encoder().convert("export CONTAINER_DIR=${G.dataPath}/containers/${G.currentContainer}\n${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}\nexit\n"));
G.virglServerPty.exitCode.then((value) {
G.isVirglServerStarted = false;
setState(() {});
@@ -406,7 +413,7 @@ class _SettingPageState extends State<SettingPage> {
}
break;
case false: {
G.virglServerPty.write(const Utf8Encoder().convert("${String.fromCharCode(3)}exit\n"));
G.virglServerPty.write(const Utf8Encoder().convert("\x03exit\n"));
}
break;
}
@@ -438,29 +445,27 @@ class _SettingPageState extends State<SettingPage> {
headerBuilder: ((context, isExpanded) {
return const ListTile(title: Text("跨架构/跨系统支持"), subtitle: Text("实验性功能"),);
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [
const Text("""你的梦想是在你的小小电脑上,运行着那些你熟悉的x86/x64或windows的程序。你不惧怕任何困难你勇敢地使用box86/box64或wine让你的梦想成为现实。但是你也要知道这是一条漫长而艰辛的道路你需要付出很多的代价。你的程序要经过两层的模拟就像穿越两个世界它们的速度会变得缓慢而沉重。你需要有足够的耐心即使你的眼前一片空白你的终端还在默默地工作。你要时刻关注它的输出看看它是否还在前进还是遇到了难以逾越的障碍。或者你也可以选择另一条路去寻找那些为linux arm64而生的程序它们或许能让你的梦想更加顺畅
你的选择就在下面,你只需勾选你想要的选项,然后重新启动你的小小电脑,你的梦想就会有所不同。
......人话:
使用box86/box64运行x86/x64架构的程序或使用wine运行windows程序。
const Text("""使用box86/box64运行x86/x64架构的程序或使用wine运行windows程序
运行windows程序需要经过架构和系统两层模拟不要对运行速度抱有期待。程序崩溃也是常有的。
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
如果不耐烦可以去看个广告消磨时间bushi
或者寻找该windows软件官方是否提供linux arm64版本。
以下选项启用后下次启动时生效。
"""),
SizedBox.fromSize(size: const Size.square(16)),
给高级用户的注意事项:
跨架构/跨系统提供类似binfmt_misc的支持。
你可以直接执行x86或x64的elf系统会自动调用box86/box64也可以直接执行exe文件系统会自动调用wine64
前提是这些文件拥有可执行权限。"""),
SizedBox.fromSize(size: const Size.square(8)),
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: [
OutlinedButton(style: D.commandButtonStyle, child: const Text("安装box86和box64"), onPressed: () {
Util.termWrite("bash ~/.local/share/tiny/extra/install-box");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("安装wine与winetricks"), onPressed: () async {
OutlinedButton(style: D.commandButtonStyle, child: const Text("安装wine"), onPressed: () async {
if (!await File("${G.dataPath}/tiny/cross/box64").exists()) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
@@ -472,6 +477,18 @@ class _SettingPageState extends State<SettingPage> {
Util.termWrite("bash ~/.local/share/tiny/extra/install-wine");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("安装dxvk"), onPressed: () async {
if (!G.wasWineEnabled) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请启用wine后重试"))
);
return;
}
Util.termWrite("bash ~/.local/share/tiny/extra/install-dxvk");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("移除所有安装"), onPressed: () async {
if (G.wasBoxEnabled) {
if (!context.mounted) return;
@@ -488,17 +505,33 @@ class _SettingPageState extends State<SettingPage> {
Util.termWrite("rm -rf ~/.wine");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("配置wine"), onPressed: () async {
Util.termWrite("wine64 winecfg");
G.pageIndex.value = 0;
Workflow.launchBrowser();
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("启动winetricks"), onPressed: () async {
Util.termWrite("winetricks64");
G.pageIndex.value = 0;
Workflow.launchBrowser();
}),
]),
SizedBox.fromSize(size: const Size.square(16)),
const Divider(height: 2, indent: 8, endIndent: 8),
SizedBox.fromSize(size: const Size.square(16)),
const Text("""开启wine后的常用指令点击后前往图形界面耐心等待。
任意程序启动参考时间:
虎贲T7510 6GB 超过一分钟
骁龙870 12GB 约10秒
骁龙8gen3 不支持32位 可能不可用
初始化时间:
可能比本软件初始化还长
"""),
SizedBox.fromSize(size: const Size.square(8)),
Wrap(alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, children: D.wineCommands.asMap().entries.map<Widget>(
(e) {
return OutlinedButton(style: D.commandButtonStyle, child: Text(e.value["name"]!), onPressed: () {
Util.termWrite("${e.value["command"]!} &");
G.pageIndex.value = 0;
});
}
).toList()),
SizedBox.fromSize(size: const Size.square(16)),
const Divider(height: 2, indent: 8, endIndent: 8),
SizedBox.fromSize(size: const Size.square(16)),
const Text("以下选项修改后将在下次启动软件时生效。"),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("启用box86/box64"), subtitle: const Text("运行跨架构软件"), value: Util.getGlobal("isBoxEnabled") as bool, onChanged:(value) async {
//检测box64是否存在存在才开启
@@ -518,7 +551,7 @@ class _SettingPageState extends State<SettingPage> {
},),
SwitchListTile(title: const Text("启用wine"), subtitle: const Text("运行windows exe软件"), value: Util.getGlobal("isWineEnabled") as bool, onChanged:(value) async {
//检测wine是否存在且box64是否开启
if (value && !(Util.getGlobal("isBoxEnabled") && await File("${G.dataPath}/tiny/cross/wine64-executable").exists())) {
if (value && !(Util.getGlobal("isBoxEnabled") && await File("${G.dataPath}/tiny/cross/wine/bin/wine").exists())) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
@@ -526,6 +559,16 @@ class _SettingPageState extends State<SettingPage> {
);
return;
}
Util.execute(value ? """filename="${G.dataPath}/containers/${G.currentContainer}/home/tiny/.bashrc"
command="export PATH=\\\$HOME/.local/share/tiny/cross/wine/bin:\\\$PATH # Auto-generated, do NOT edit"
if ! ${G.dataPath}/busybox grep -qF "\$command" "\$filename"; then
echo "\$command" >> "\$filename"
fi""" : """filename="${G.dataPath}/containers/${G.currentContainer}/home/tiny/.bashrc"
command="export PATH=\\\$HOME/.local/share/tiny/cross/wine/bin:\\\$PATH # Auto-generated, do NOT edit"
if ${G.dataPath}/busybox grep -qF "\$command" "\$filename"; then
command="export PATH=\\\$HOME/.local/share/tiny/cross/wine/bin:\\\$PATH \\\\# Auto-generated, do NOT edit"
${G.dataPath}/busybox sed -i "\\\\#\$command#d" "\$filename"
fi""");
G.prefs.setBool("isWineEnabled", value);
setState(() {});
},),
@@ -1120,7 +1163,7 @@ SOFTWARE.
}), body: const Padding(padding: EdgeInsets.all(8), child: Text("""
除由Unity提供的广告功能外, 本软件不会收集你的隐私信息。
当然,你在容器系统内部安装或使用的软件行为就不受我控制了,所以我不对其负责。
当然,你在容器系统内部安装或使用的软件行为(包括通过快捷指令)就不受我控制了,我不对其负责。
本软件申请的权限用于以下目的:
文件相关权限:用于系统访问手机目录;
@@ -1223,7 +1266,7 @@ class LoadingPage extends StatelessWidget {
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 8),
child: ValueListenableBuilder(valueListenable: G.updateText, builder:(context, value, child) {
return Text(value, textScaleFactor: 2);
return Text(value, textScaler: const TextScaler.linear(2));
}),
),
const FakeLoadingStatus(),

View File

@@ -43,6 +43,8 @@ import 'package:unity_ads_plugin/unity_ads_plugin.dart';
import 'package:clipboard/clipboard.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
class Util {
static Future<void> copyAsset(String src, String dst) async {
@@ -60,7 +62,7 @@ class Util {
Pty pty = Pty.start(
"/system/bin/sh"
);
pty.write(const Utf8Encoder().convert("$str\nexit \$!\n"));
pty.write(const Utf8Encoder().convert("$str\nexit \$?\n"));
return await pty.exitCode;
}
@@ -93,6 +95,7 @@ class Util {
//bool isBoxEnabled = false 下次启动是否开启box86/box64
//bool isWineEnabled = false 下次启动是否开启wine
//bool virgl = false 下次启动是否启用virgl
//bool wakelock = false 屏幕常亮
//? int bootstrapVersion: 启动包版本
//String[] containersInfo: 所有容器信息(json)
//{name, boot:"\$DATA_DIR/bin/proot ...", vnc:"startnovnc", vncUrl:"...", commands:[{name:"更新和升级", command:"apt update -y && apt upgrade -y"},
@@ -122,6 +125,7 @@ class Util {
case "isBoxEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "isWineEnabled" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "virgl" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "wakelock" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "defaultFFmpegCommand" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("-hide_banner -an -max_delay 1000000 -r 30 -f android_camera -camera_index 0 -i 0:0 -vf scale=iw/2:-1 -rtsp_transport udp -f rtsp rtsp://127.0.0.1:8554/stream");
case "defaultVirglCommand" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("--socket-path=\$CONTAINER_DIR/tmp/.virgl_test");
case "defaultVirglOpt" : return b ? G.prefs.getString(key)! : (value){G.prefs.setString(key, value); return value;}("GALLIUM_DRIVER=virpipe MESA_GL_VERSION_OVERRIDE=4.0");
@@ -197,6 +201,7 @@ class Util {
opr();
return null;
}
}
//来自xterms关于操作ctrl, shift, alt键的示例
@@ -289,7 +294,7 @@ class TermPty {
child: Scrollbar(child:
SingleChildScrollView(
child: Column(children: [
const Text(":(\n发生了什么?", textScaleFactor: 2, style: ts, textAlign: TextAlign.center,),
const Text(":(\n发生了什么?", textScaler: TextScaler.linear(2), style: ts, textAlign: TextAlign.center,),
const Text("终端异常退出, 返回错误码9\n此错误通常是高版本安卓系统(12+)限制进程造成的, \n可以使用以下工具修复:", style: ts, textAlign: TextAlign.center),
const SelectableText(helperLink, style: ts, textAlign: TextAlign.center),
const Text("(复制链接到浏览器查看)", style: ts, textAlign: TextAlign.center),
@@ -349,6 +354,7 @@ class D {
{"name":"查看系统信息", "command":"neofetch -L && neofetch --off"},
{"name":"清屏", "command":"clear"},
{"name":"查看IP", "command":"hostname -I | awk '{print \$NF}' # 如果显示无权限(Permission denied)请在全局设置里开启getifaddrs桥接"},
{"name":"中断任务", "command":"\x03"},
{"name":"安装图形处理软件Krita", "command":"sudo apt update && sudo apt install -y krita krita-l10n"},
{"name":"卸载Krita", "command":"sudo apt autoremove --purge -y krita krita-l10n"},
{"name":"安装视频剪辑软件Kdenlive", "command":"sudo apt update && sudo apt install -y kdenlive"},
@@ -373,6 +379,19 @@ class D {
{"name":"拉流测试", "command":"ffplay rtsp://127.0.0.1:8554/stream &"},
{"name":"关机", "command":"stopvnc\nexit\nexit"},
{"name":"???", "command":"timeout 8 cmatrix"}];
//默认wine快捷指令
static const wineCommands = [{"name":"wine配置", "command":"wine64 winecfg"},
{"name":"我的电脑", "command":"wine64 explorer"},
{"name":"记事本", "command":"wine64 notepad"},
{"name":"扫雷", "command":"wine64 winemine"},
{"name":"注册表", "command":"wine64 regedit"},
{"name":"控制面板", "command":"wine64 control"},
{"name":"文件管理器", "command":"wine64 winefile"},
{"name":"任务管理器", "command":"wine64 taskmgr"},
{"name":"ie浏览器", "command":"wine64 iexplore"},
{"name":"强制关闭wine", "command":"wineserver -k"}];
//默认小键盘
static const termCommands = [
{"name": "Esc", "key": TerminalKey.escape},
@@ -475,6 +494,7 @@ class G {
static ValueNotifier<String> updateText = ValueNotifier("小小电脑"); //加载界面的说明文字
static bool wasBoxEnabled = false; //本次启动时是否启用了box86/64
static bool wasWineEnabled = false; //本次启动时是否启用了wine
static late SharedPreferences prefs;
@@ -714,6 +734,8 @@ done
await G.prefs.setBool("virgl", false);
}
//设置屏幕常亮
WakelockPlus.toggle(enable: Util.getGlobal("wakelock"));
}
static Future<void> initTerminalForCurrent() async {
@@ -750,7 +772,11 @@ exit
}
static Future<void> launchCurrentContainer() async {
String extraMount = "";
String box86BinPath = "";
String box64BinPath = "";
String box86LibraryPath = "";
String box64LibraryPath = "";
String extraMount = ""; //mount options and other proot options
String extraOpt = "";
if (Util.getGlobal("getifaddrsBridge")) {
Util.execute("${G.dataPath}/bin/getifaddrs_bridge_server ${G.dataPath}/containers/${G.currentContainer}/tmp/.getifaddrs-bridge");
@@ -769,13 +795,25 @@ ${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}""")
}
if (Util.getGlobal("isBoxEnabled")) {
G.wasBoxEnabled = true;
extraMount += "--x86=/home/tiny/.local/bin/box86 --x64=/home/tiny/.local/bin/box64 ";
extraMount += "--mount=\$DATA_DIR/tiny/cross/box86:/home/tiny/.local/bin/box86 --mount=\$DATA_DIR/tiny/cross/box64:/home/tiny/.local/bin/box64 ";
extraOpt += "BOX86_NOBANNER=1 BOX64_NOBANNER=1 ";
}
if (Util.getGlobal("isWineEnabled")) {
extraOpt += "BOX86_PATH=/home/tiny/.local/share/tiny/cross/wine/bin/ BOX86_LD_LIBRARY_PATH=/home/tiny/.local/share/tiny/cross/wine/lib/wine/i386-unix/:/lib/i386-linux-gnu/:/lib/aarch64-linux-gnu/:/lib/arm-linux-gnueabihf/:/usr/lib/aarch64-linux-gnu/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/i386-linux-gnu/:/home/tiny/.local/share/tiny/cross/x86lib/ ";
extraOpt += "BOX64_PATH=/home/tiny/.local/share/tiny/cross/wine/bin/ BOX64_LD_LIBRARY_PATH=/home/tiny/.local/share/tiny/cross/wine/lib/wine/i386-unix/:/home/tiny/.local/share/tiny/cross/wine/lib/wine/x86_64-unix/:/lib/i386-linux-gnu/:/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu/:/lib/arm-linux-gnueabihf/:/usr/lib/aarch64-linux-gnu/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/i386-linux-gnu/:/usr/lib/x86_64-linux-gnu/:/home/tiny/.local/share/tiny/cross/x64lib/ ";
extraMount += "--mount=\$DATA_DIR/tiny/cross/wine-executable:/home/tiny/.local/bin/wine --mount=\$DATA_DIR/tiny/cross/wine64-executable:/home/tiny/.local/bin/wine64 --mount=\$DATA_DIR/tiny/cross/wine64.desktop:/usr/share/applications/wine64.desktop ";
extraMount += "--mount=\$DATA_DIR/tiny/cross/winetricks64-executable:/home/tiny/.local/bin/winetricks64 --mount=\$DATA_DIR/tiny/cross/winetricks64.desktop:/usr/share/applications/winetricks64.desktop ";
G.wasWineEnabled = true;
box86BinPath += "/home/tiny/.local/share/tiny/cross/wine/bin:";
box64BinPath += "/home/tiny/.local/share/tiny/cross/wine/bin:";
box86LibraryPath += "/home/tiny/.local/share/tiny/cross/wine/lib/wine/i386-unix:";
box64LibraryPath += "/home/tiny/.local/share/tiny/cross/wine/lib/wine/x86_64-unix:";
extraMount += "--wine=/home/tiny/.local/bin/wine64 ";
extraMount += "--mount=\$DATA_DIR/tiny/cross/wine.desktop:/usr/share/applications/wine.desktop ";
//extraMount += "--mount=\$DATA_DIR/tiny/cross/winetricks:/home/tiny/.local/bin/winetricks --mount=\$DATA_DIR/tiny/cross/winetricks.desktop:/usr/share/applications/winetricks.desktop ";
}
if (G.wasBoxEnabled) {
extraOpt += "BOX86_PATH=$box86BinPath/home/tiny/.local/share/tiny/cross/bin ";
extraOpt += "BOX64_PATH=$box64BinPath/home/tiny/.local/share/tiny/cross/bin ";
extraOpt += "BOX86_LD_LIBRARY_PATH=$box86LibraryPath/home/tiny/.local/share/tiny/cross/x86lib ";
extraOpt += "BOX64_LD_LIBRARY_PATH=$box64LibraryPath/home/tiny/.local/share/tiny/cross/x64lib ";
}
Util.termWrite(
"""