Compare commits

...

3 Commits

Author SHA1 Message Date
Caten
b3428555c6 box and wine initial support 2023-11-30 15:57:56 +08:00
Caten
2a19c5eb78 Audio fix, more install scripts 2023-11-25 08:20:12 +08:00
Caten
54a941da63 update readme 2023-11-11 21:28:48 +08:00
15 changed files with 397 additions and 107 deletions

View File

@@ -2,45 +2,42 @@
<img decoding="async" src="readme/cover0.png" width="50%">
即开即用的类PC环境内置火狐浏览器和fcitx输入法等常用软件
给所有安卓arm64设备的“PC应用引擎”平替
Click-to-run debian bookworm xfce on android for Chinese users, with fcitx pinyin input method preinstalled. No termux required.
## 特点
- 一键安装,即开即用
- 来自kali-undercover的win10主题(仅xfce版本),友好的界面
<img decoding="async" src="readme/img1.png" width="50%">
- 提供常用软件的一键安装指令
<img decoding="async" src="readme/img2.png" width="50%">
- 可方便地改变屏幕缩放,不用担心屏幕过大或过小
<img decoding="async" src="readme/img3.gif" width="50%">
- 便捷访问设备文件或通过设备SAF访问软件文件
<img decoding="async" src="readme/img4.png" width="50%">
- 提供终端和众多可调节参数供高级用户使用
<img decoding="async" src="readme/img5.png" width="50%">
## 原理
使用proot运行debian环境
内置[noVNC](https://github.com/novnc/noVNC)显示图形界面
初次启动由于解压的缘故要点时间
以后点开就能用
只支持arm64安卓
## 项目结构
assets的文件来源如下:
- [proot](https://github.com/Cateners/proot), 使用[build-proot-android](https://github.com/green-green-avk/build-proot-android)脚本编译
- [busybox](https://github.com/meefik/busybox)
- [mediamtx相关](https://github.com/bluenviron/mediamtx)
- [tar](https://github.com/Rprop/tar-android-static)
- [Xserver XSDL, pulseaudio相关文件](https://github.com/pelya/commandergenius/tree/sdl_android/project/jni/application/xserver)
- [Tmoe Linux, debian包来源](https://github.com/2moe/tmoe)
其中tar、busybox和pulseaudio相关文件都是直接用了二进制文件。
更多信息可以在[这里](extra/readme)找到。
对debian容器进行了如下修改
- 使用tmoe安装了xfce环境和全套VNC
- 使用kali-undercover提供的Win10主题美化xfce
- (使用tmoe)安装了fcitx输入法和云拼音组件。按<Ctrl+空格>切换输入法。
- 强烈建议**不要**使用安卓中文输入法直接输入中文,而是使用英文键盘通过容器的输入法输入中文,避免丢字错字。
- 对noVNC进行[修改](https://github.com/Cateners/noVNC)添加了scale factor滑块控制缩放(scale_factor分支)添加了上下左右shift等按键(arrow_key分支),添加了强制显示原系统光标的功能(force_cursor分支),添加了中文翻译(translation_zh_cn分支)
- 在主目录下可以方便地访问手机存储(如果提供了存储权限的话)
- 启动时会尝试挂载手机的一些字体目录(AppFiles/Fonts、Fonts和/system/fonts), 如果这些目录下有字体文件的话会一并加载到系统中,无需额外安装;
- 最后采用tar.xz压缩用split命令分成了xa*等多个文件(低内存设备一次性拷贝大文件会导致软件闪退)。
assets的文件来源信息可以在[这里](extra/readme.md)找到。
完整的容器制作过程可以在[这里](extra/build-tiny-rootfs.md)看到。
@@ -48,7 +45,7 @@ assets的文件来源如下:
lib目录
- main.dart文件页面布局老实说已经有点乱
- main.dart文件页面布局有点乱
- workflow.dart文件逻辑部分目前也还可以理解
- Util 工具类
- TermPty 一个终端

Binary file not shown.

56
extra/cross/install-box Normal file
View File

@@ -0,0 +1,56 @@
#!/bin/bash
sudo dpkg --add-architecture armhf
sudo apt update
sudo apt upgrade -y
sudo apt install -y cmake gcc-arm-linux-gnueabihf libc6:armhf
sudo apt reinstall -y libc6-dev
mkdir $HOME/.local/share/tiny/cross
rm -rf $HOME/.local/share/tiny/tmp
mkdir $HOME/.local/share/tiny/tmp
cd $HOME/.local/share/tiny/tmp
git clone https://mirror.ghproxy.com/https://github.com/ptitSeb/box86
if [ $? -ne 0 ]; then
git clone https://github.com/ptitSeb/box86
if [ $? -ne 0 ]; then
rm -rf $HOME/.local/share/tiny/tmp
echo '仓库克隆失败...退出安装...'
exit
fi
fi
git clone https://mirror.ghproxy.com/https://github.com/ptitSeb/box64
if [ $? -ne 0 ]; then
git clone https://github.com/ptitSeb/box64
if [ $? -ne 0 ]; then
rm -rf $HOME/.local/share/tiny/tmp
echo '仓库克隆失败...退出安装...'
exit
fi
fi
cd box86
mkdir build
cd build
cmake .. -DARM64=1 -DBAD_SIGNAL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j
cd ../..
mv box86/build/box86 ../cross
mv box86/x86lib ../cross
cd box64
mkdir build
cd build
cmake .. -DARM64=1 -DBAD_SIGNAL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j
cd ../..
mv box64/build/box64 ../cross
mv box64/x64lib ../cross
cd ..
rm -rf tmp
echo '安装完成'

79
extra/cross/install-wine Normal file
View File

@@ -0,0 +1,79 @@
#!/bin/bash
sudo apt update
sudo apt upgrade -y
sudo apt install -y nano cabextract libfreetype6 libfreetype6:armhf libfontconfig libfontconfig:armhf libxext6 libxext6:armhf libxinerama-dev libxinerama-dev:armhf libxxf86vm1 libxxf86vm1:armhf libxrender1 libxrender1:armhf libxcomposite1 libxcomposite1:armhf libxrandr2 libxrandr2:armhf libxi6 libxi6:armhf libxcursor1 libxcursor1:armhf libvulkan-dev libvulkan-dev:armhf zenity
rm -rf $HOME/.local/share/tiny/tmp
mkdir $HOME/.local/share/tiny/tmp
cd $HOME/.local/share/tiny/tmp
MIRROR_SITE=https://mirror.ghproxy.com
LATEST_WINE_NAME=$(curl -L https://github.com/Kron4ek/Wine-Builds/releases | grep "amd64\.tar\.xz" | grep "proton" | head -n 1 | awk '{print $NF}')
LATEST_WINE_TAG=$(echo $LATEST_WINE_NAME | cut -d "-" -f 2)
if [ $LATEST_WINE_TAG == proton ]; then
LATEST_WINE_TAG=proton-$(echo $LATEST_WINE_NAME | cut -d "-" -f 3)-$(echo $LATEST_WINE_NAME | cut -d "-" -f 4)
fi
LATEST_WINE_LINK=https://github.com/Kron4ek/Wine-Builds/releases/download/$LATEST_WINE_TAG/$LATEST_WINE_NAME
wget $MIRROR_SITE/$LATEST_WINE_LINK
if [ $? -ne 0 ]; then
wget $LATEST_WINE_LINK
if [ $? -ne 0 ]; then
rm -rf $HOME/.local/share/tiny/tmp
echo '下载失败...退出安装...'
exit
fi
fi
wget $MIRROR_SITE/https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
if [ $? -ne 0 ]; then
wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
if [ $? -ne 0 ]; then
rm -rf $HOME/.local/share/tiny/tmp
echo '下载失败...退出安装...'
exit
fi
fi
tar xvf $LATEST_WINE_NAME
mv wine-$LATEST_WINE_TAG-amd64 ../cross/wine
mv winetricks ../cross/winetricks-executable
chmod +x $HOME/.local/share/tiny/cross/winetricks-executable
cd ..
rm -rf tmp
echo '#!/bin/bash
export WINEPREFIX=~/.wine
box86 '"$HOME/.local/share/tiny/cross/wine/bin/wine "'"$@"' > $HOME/.local/share/tiny/cross/wine-executable
chmod +x $HOME/.local/share/tiny/cross/wine-executable
echo '#!/bin/bash
export WINEPREFIX=~/.wine
box64 '"$HOME/.local/share/tiny/cross/wine/bin/wine64 "'"$@"' > $HOME/.local/share/tiny/cross/wine64-executable
chmod +x $HOME/.local/share/tiny/cross/wine64-executable
echo '#!/bin/bash
export BOX64_NOBANNER=1 WINE=wine64 WINEPREFIX=~/.wine WINESERVER=~/.local/share/tiny/cross/wine/bin/wineserver
wine64 '"$HOME/.local/share/tiny/cross/winetricks-executable "'"$@"' > $HOME/.local/share/tiny/cross/winetricks64-executable
chmod +x $HOME/.local/share/tiny/cross/winetricks64-executable
echo '[Desktop Entry]
Name=Wine64 启动器
Exec=wine64 start /unix %F
Icon=wine
Type=Application' > $HOME/.local/share/tiny/cross/wine64.desktop
chmod +x $HOME/.local/share/tiny/cross/wine64.desktop
echo '[Desktop Entry]
Name=Wine64 winetricks 实用工具
Exec=winetricks64
Icon=wine
Type=Application' > $HOME/.local/share/tiny/cross/winetricks64.desktop
chmod +x $HOME/.local/share/tiny/cross/winetricks64.desktop
echo '安装完成在启用wine后可以点击exe文件选择用wine启动。'
echo '程序的运行可能依赖一些配置或组件。比如一些使用directx的游戏可能需要安装dxvk。'
echo '如果缺失可以尝试使用winetricks安装。请务必保持耐心。'

View File

@@ -2,7 +2,15 @@
### assets.zip中的文件
#### [容器文件xa*](build-tiny-rootfs.md)
- [proot](https://github.com/Cateners/proot), 使用[build-proot-android](https://github.com/green-green-avk/build-proot-android)脚本编译
- [busybox](https://github.com/meefik/busybox)
- [mediamtx相关](https://github.com/bluenviron/mediamtx)
- [tar](https://github.com/Rprop/tar-android-static)
- [Xserver XSDL, pulseaudio相关文件](https://github.com/pelya/commandergenius/tree/sdl_android/project/jni/application/xserver)
- [Tmoe Linux, debian包来源](https://github.com/2moe/tmoe)
- [容器文件xa*](build-tiny-rootfs.md)
其中tar、busybox和pulseaudio相关文件都是直接用了二进制文件。
### patch.tar.gz中的文件

View File

@@ -18,6 +18,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
//import 'dart:convert';
@@ -103,7 +104,7 @@ class SettingPage extends StatefulWidget {
class _SettingPageState extends State<SettingPage> {
final List<bool> _expandState = [false, false, false, false, false, false];
final List<bool> _expandState = [false, false, false, false, false, false, false];
@override
Widget build(BuildContext context) {
@@ -120,25 +121,6 @@ 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: [
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("name"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "容器名称"), onChanged: (value) async {
await Util.setCurrentProp("name", value);
//setState(() {});
}),
SizedBox.fromSize(size: const Size.square(8)),
ValueListenableBuilder(valueListenable: G.bootTextChange, builder:(context, v, child) {
return TextFormField(maxLines: null, initialValue: Util.getCurrentProp("boot"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "启动命令"), onChanged: (value) async {
await Util.setCurrentProp("boot", value);
});
}),
SizedBox.fromSize(size: const Size.square(8)),
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vnc"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "vnc启动命令"), onChanged: (value) async {
await Util.setCurrentProp("vnc", value);
}),
SizedBox.fromSize(size: const Size.square(8)),
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vncUrl"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "网页跳转地址"), onChanged: (value) async {
await Util.setCurrentProp("vncUrl", value);
}),
SizedBox.fromSize(size: const Size.square(8)),
OutlinedButton(style: D.commandButtonStyle, child: const Text("重置启动命令"), onPressed: () {
showDialog(context: context, builder: (context) {
return AlertDialog(title: const Text("注意"), content: const Text("是否重置启动命令?"), actions: [
@@ -154,6 +136,30 @@ class _SettingPageState extends State<SettingPage> {
]);
});
}),
SizedBox.fromSize(size: const Size.square(8)),
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("name"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "容器名称"), onChanged: (value) async {
await Util.setCurrentProp("name", value);
//setState(() {});
}),
SizedBox.fromSize(size: const Size.square(8)),
ValueListenableBuilder(valueListenable: G.bootTextChange, builder:(context, v, child) {
return TextFormField(maxLines: null, initialValue: Util.getCurrentProp("boot"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "启动命令"), onChanged: (value) async {
await Util.setCurrentProp("boot", value);
});
}),
SizedBox.fromSize(size: const Size.square(8)),
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vnc"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "vnc启动命令"), onChanged: (value) async {
await Util.setCurrentProp("vnc", value);
}),
SizedBox.fromSize(size: const Size.square(8)),
const Divider(height: 2, indent: 8, endIndent: 8),
SizedBox.fromSize(size: const Size.square(16)),
const Text("你可以在当前所有同一网络下的设备(如:连接同一路由器的手机,电脑等)里使用小小电脑。\n\n将下面的链接复制到其他设备在其他设备上把链接localhost字样改为当前设备的IP地址可以通过快捷指令查看然后使用浏览器打开链接即可。"),
SizedBox.fromSize(size: const Size.square(16)),
TextFormField(maxLines: null, initialValue: Util.getCurrentProp("vncUrl"), decoration: const InputDecoration(border: OutlineInputBorder(), labelText: "网页跳转地址"), onChanged: (value) async {
await Util.setCurrentProp("vncUrl", value);
}),
SizedBox.fromSize(size: const Size.square(8)),
],))),
ExpansionPanel(
isExpanded: _expandState[1],
@@ -238,15 +244,24 @@ class _SettingPageState extends State<SettingPage> {
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("重新安装引导包"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("reinstallBootstrap") as bool, onChanged:(value) {
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("重新安装引导包"), value: Util.getGlobal("reinstallBootstrap") as bool, onChanged:(value) {
G.prefs.setBool("reinstallBootstrap", value);
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("getifaddrs桥接"), subtitle: const Text("下次启动时生效"), value: Util.getGlobal("getifaddrsBridge") as bool, onChanged:(value) {
SwitchListTile(title: const Text("getifaddrs桥接"), subtitle: const Text("修复安卓13设备getifaddrs无权限"), value: Util.getGlobal("getifaddrsBridge") as bool, onChanged:(value) {
G.prefs.setBool("getifaddrsBridge", value);
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(8)),
SwitchListTile(title: const Text("伪装系统为UOS"), subtitle: const Text("修复UOS微信无法启动"), value: Util.getGlobal("uos") as bool, onChanged:(value) {
G.prefs.setBool("uos", value);
setState(() {});
},),
],))),
ExpansionPanel(
isExpanded: _expandState[2],
@@ -420,6 +435,104 @@ class _SettingPageState extends State<SettingPage> {
],))),
ExpansionPanel(
isExpanded: _expandState[5],
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程序。
运行windows程序需要经过架构和系统两层模拟不要对运行速度抱有期待。程序崩溃也是常有的。
你需要耐心。即使图形界面什么也没显示。看看终端,还在继续输出吗?还是停止在某个报错?
或者寻找该windows软件官方是否提供linux arm64版本。
以下选项启用后下次启动时生效。
"""),
SizedBox.fromSize(size: const Size.square(16)),
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 {
if (!await File("${G.dataPath}/tiny/cross/box64").exists()) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先安装box86/box64"))
);
return;
}
Util.termWrite("bash ~/.local/share/tiny/extra/install-wine");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("移除所有安装"), onPressed: () async {
if (G.wasBoxEnabled) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请关闭跨架构支持后重试"))
);
return;
}
Util.termWrite("rm -rf ~/.local/share/tiny/cross");
G.pageIndex.value = 0;
}),
OutlinedButton(style: D.commandButtonStyle, child: const Text("清空wine数据"), onPressed: () async {
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(8)),
SwitchListTile(title: const Text("启用box86/box64"), subtitle: const Text("运行跨架构软件"), value: Util.getGlobal("isBoxEnabled") as bool, onChanged:(value) async {
//检测box64是否存在存在才开启
if (value && !await File("${G.dataPath}/tiny/cross/box64").exists()) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先安装box86/box64"))
);
return;
}
G.prefs.setBool("isBoxEnabled", value);
if (!value && Util.getGlobal("isWineEnabled")) {
G.prefs.setBool("isWineEnabled", false);
}
setState(() {});
},),
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 (!context.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先安装wine并启用box86/box64"))
);
return;
}
G.prefs.setBool("isWineEnabled", value);
setState(() {});
},),
SizedBox.fromSize(size: const Size.square(16)),
],))),
ExpansionPanel(
isExpanded: _expandState[6],
headerBuilder: ((context, isExpanded) {
return const ListTile(title: Text("广告记录"), subtitle: Text("在这里看广告"));
}), body: Padding(padding: const EdgeInsets.all(12), child: Column(children: [

View File

@@ -89,6 +89,9 @@ class Util {
//String defaultVirglOpt 默认virgl环境变量
//bool reinstallBootstrap = false 下次启动是否重装引导包
//bool getifaddrsBridge = false 下次启动是否桥接getifaddrsBridge
//bool uos = false 下次启动是否伪装UOS
//bool isBoxEnabled = false 下次启动是否开启box86/box64
//bool isWineEnabled = false 下次启动是否开启wine
//bool virgl = false 下次启动是否启用virgl
//? int bootstrapVersion: 启动包版本
//String[] containersInfo: 所有容器信息(json)
@@ -115,6 +118,9 @@ class Util {
case "isStickyKey" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(true);
case "reinstallBootstrap" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "getifaddrsBridge" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
case "uos" : return b ? G.prefs.getBool(key)! : (value){G.prefs.setBool(key, value); return value;}(false);
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 "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");
@@ -342,20 +348,25 @@ class D {
static const commands = [{"name":"检查更新并升级", "command":"sudo apt update && sudo apt upgrade -y"},
{"name":"查看系统信息", "command":"neofetch -L && neofetch --off"},
{"name":"清屏", "command":"clear"},
{"name":"查看IP", "command":"hostname -I | awk '{print \$NF}' # 如果显示无权限(Permission denied)请在全局设置里开启getifaddrs桥接"},
{"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":"卸载Krita", "command":"sudo apt autoremove --purge -y krita krita-l10n"},
{"name":"安装视频剪辑软件Kdenlive", "command":"sudo apt update && sudo apt install -y kdenlive"},
{"name":"卸载视频剪辑软件Kdenlive", "command":"sudo apt autoremove --purge -y kdenlive"},
{"name":"卸载Kdenlive", "command":"sudo apt autoremove --purge -y kdenlive"},
{"name":"安装科学计算软件Octave", "command":"sudo apt update && sudo apt install -y octave"},
{"name":"卸载科学计算软件Octave", "command":"sudo apt autoremove --purge -y octave"},
{"name":"安装WPS", "command":"wget https://wps-linux-personal.wpscdn.cn/wps/download/ep/Linux2019/11708/wps-office_11.1.0.11708_arm64.deb -O /tmp/wps.deb && sudo apt update && sudo apt install -y /tmp/wps.deb; rm /tmp/wps.deb"},
{"name":"卸载Octave", "command":"sudo apt autoremove --purge -y octave"},
{"name":"安装WPS", "command":"""wget \$(curl -L https://linux.wps.cn/ | grep -oP 'href="\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/wps.deb && sudo apt update && sudo apt install -y /tmp/wps.deb; rm /tmp/wps.deb"""},
{"name":"卸载WPS", "command":"sudo apt autoremove --purge -y wps-office"},
{"name":"安装CAJViewer", "command":"wget https://download.cnki.net/net.cnki.cajviewer_1.3.20-1_arm64.deb -O /tmp/caj.deb && sudo apt update && sudo apt install -y /tmp/caj.deb && bash /home/tiny/.local/share/tiny/caj/postinst; rm /tmp/caj.deb"},
{"name":"卸载CAJViewer", "command":"sudo apt autoremove --purge -y net.cnki.cajviewer && bash /home/tiny/.local/share/tiny/caj/postrm"},
{"name":"安装亿图图示", "command":"wget https://www.edrawsoft.cn/2download/aarch64/edrawmax_11.5.6-3_arm64.deb -O /tmp/edraw.deb && sudo apt update && sudo apt install -y /tmp/edraw.deb && bash /home/tiny/.local/share/tiny/edraw/postinst; rm /tmp/edraw.deb"},
{"name":"卸载亿图图示", "command":"sudo apt autoremove --purge -y edrawmax libldap-2.4-2"},
{"name":"安装QQ", "command":"wget https://dldir1.qq.com/qqfile/qq/QQNT/fd2e886e/linuxqq_3.2.2-18394_arm64.deb -O /tmp/qq.deb && sudo apt update && sudo apt install -y /tmp/qq.deb && sed -i 's#Exec=/opt/QQ/qq %U#Exec=/opt/QQ/qq --no-sandbox %U#g' /usr/share/applications/qq.desktop; rm /tmp/qq.deb"},
{"name":"安装QQ", "command":"""wget \$(curl -L https://cdn-go.cn/qq-web/im.qq.com_new/latest/rainbow/linuxQQDownload.js | grep -oP 'deb":"\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/qq.deb && sudo apt update && sudo apt install -y /tmp/qq.deb && sed -i 's#Exec=/opt/QQ/qq %U#Exec=/opt/QQ/qq --no-sandbox %U#g' /usr/share/applications/qq.desktop; rm /tmp/qq.deb"""},
{"name":"卸载QQ", "command":"sudo apt autoremove --purge -y linuxqq"},
{"name":"安装UOS微信", "command":"wget https://home-store-packages.uniontech.com/appstore/pool/appstore/c/com.tencent.weixin/com.tencent.weixin_2.1.9_arm64.deb -O /tmp/wechat.deb && sudo apt update && sudo apt install -y /tmp/wechat.deb /home/tiny/.local/share/tiny/wechat/deepin-elf-verify_all.deb /home/tiny/.local/share/tiny/wechat/libssl1.1_1.1.1n-0+deb10u6_arm64.deb && sed -i 's#/opt/apps/com.tencent.weixin/files/weixin/weixin#/opt/apps/com.tencent.weixin/files/weixin/weixin --no-sandbox#g' /opt/apps/com.tencent.weixin/files/weixin/weixin.sh && echo '该微信为UOS特供版只有账号实名且在UOS系统上运行时可用。在使用前请前往全局设置开启UOS伪装。\n如果你使用微信只是为了传输文件那么可以考虑使用支持SAF的文件管理器质感文件直接访问小小电脑所有文件。'; rm /tmp/wechat.deb"},
{"name":"卸载UOS微信", "command":"sudo apt autoremove --purge -y com.tencent.weixin libssl1.1 deepin-elf-verify"},
{"name":"安装钉钉", "command":"""wget \$(curl -L https://g.alicdn.com/dingding/h5-home-download/0.2.4/js/index.js | grep -oP 'url:"\\K[^"]*arm64\\.deb' | head -n 1) -O /tmp/dingtalk.deb && sudo apt update && sudo apt install -y /tmp/dingtalk.deb && sed -i 's#\\./com.alibabainc.dingtalk#\\./com.alibabainc.dingtalk --no-sandbox#g' /opt/apps/com.alibabainc.dingtalk/files/Elevator.sh; rm /tmp/dingtalk.deb"""},
{"name":"卸载钉钉", "command":"sudo apt autoremove --purge -y com.alibabainc.dingtalk"},
{"name":"修复无法编译C语言程序", "command":"sudo apt update && sudo apt reinstall -y libc6-dev"},
{"name":"修复系统语言到中文", "command":"sudo localedef -c -i zh_CN -f UTF-8 zh_CN.UTF-8"},
{"name":"启用回收站", "command":"sudo apt update && sudo apt install -y gvfs && echo '安装完成, 重启软件即可使用回收站。'"},
@@ -417,7 +428,7 @@ class D {
};
static const String boot = "\$DATA_DIR/bin/proot -H --change-id=1000:1000 --pwd=/home/tiny --rootfs=\$CONTAINER_DIR --mount=/system --mount=/apex --kill-on-exit --mount=/storage:/storage --sysvipc -L --link2symlink --mount=/proc:/proc --mount=/dev:/dev --mount=\$CONTAINER_DIR/tmp:/dev/shm --mount=/dev/urandom:/dev/random --mount=/proc/self/fd:/dev/fd --mount=/proc/self/fd/0:/dev/stdin --mount=/proc/self/fd/1:/dev/stdout --mount=/proc/self/fd/2:/dev/stderr --mount=/dev/null:/dev/tty0 --mount=/dev/null:/proc/sys/kernel/cap_last_cap --mount=/storage/self/primary:/media/sd --mount=\$DATA_DIR/share:/home/tiny/公共 --mount=\$DATA_DIR/tiny:/home/tiny/.local/share/tiny --mount=/storage/self/primary/Fonts:/usr/share/fonts/wpsm --mount=/storage/self/primary/AppFiles/Fonts:/usr/share/fonts/yozom --mount=/system/fonts:/usr/share/fonts/androidm --mount=/storage/self/primary/Pictures:/home/tiny/图片 --mount=/storage/self/primary/Music:/home/tiny/音乐 --mount=/storage/self/primary/Movies:/home/tiny/视频 --mount=/storage/self/primary/Download:/home/tiny/下载 --mount=/storage/self/primary/DCIM:/home/tiny/照片 --mount=/storage/self/primary/Documents:/home/tiny/文档 --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.stat:/proc/stat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.version:/proc/version --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/bus:/proc/bus --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/buddyinfo:/proc/buddyinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/cgroups:/proc/cgroups --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/consoles:/proc/consoles --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/crypto:/proc/crypto --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/devices:/proc/devices --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/diskstats:/proc/diskstats --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/execdomains:/proc/execdomains --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/fb:/proc/fb --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/filesystems:/proc/filesystems --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/interrupts:/proc/interrupts --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/iomem:/proc/iomem --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/ioports:/proc/ioports --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kallsyms:/proc/kallsyms --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/keys:/proc/keys --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/key-users:/proc/key-users --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kpageflags:/proc/kpageflags --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/loadavg:/proc/loadavg --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/locks:/proc/locks --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/misc:/proc/misc --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/modules:/proc/modules --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/pagetypeinfo:/proc/pagetypeinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/partitions:/proc/partitions --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/sched_debug:/proc/sched_debug --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/softirqs:/proc/softirqs --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/timer_list:/proc/timer_list --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/uptime:/proc/uptime --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmallocinfo:/proc/vmallocinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmstat:/proc/vmstat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/zoneinfo:/proc/zoneinfo /usr/bin/env -i HOSTNAME=TINY HOME=/home/tiny USER=tiny TERM=xterm-256color SDL_IM_MODULE=fcitx XMODIFIERS=@im=fcitx QT_IM_MODULE=fcitx GTK_IM_MODULE=fcitx TMOE_CHROOT=false TMOE_PROOT=true TMPDIR=/tmp MOZ_FAKE_NO_SANDBOX=1 DISPLAY=:4 PULSE_SERVER=tcp:127.0.0.1:4718 LANG=zh_CN.UTF-8 SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games \$EXTRA_OPT /bin/bash -l";
static const String boot = "\$DATA_DIR/bin/proot -H --change-id=1000:1000 --pwd=/home/tiny --rootfs=\$CONTAINER_DIR --mount=/system --mount=/apex --mount=/sys --kill-on-exit --mount=/storage:/storage --sysvipc -L --link2symlink --mount=/proc:/proc --mount=/dev:/dev --mount=\$CONTAINER_DIR/tmp:/dev/shm --mount=/dev/urandom:/dev/random --mount=/proc/self/fd:/dev/fd --mount=/proc/self/fd/0:/dev/stdin --mount=/proc/self/fd/1:/dev/stdout --mount=/proc/self/fd/2:/dev/stderr --mount=/dev/null:/dev/tty0 --mount=/dev/null:/proc/sys/kernel/cap_last_cap --mount=/storage/self/primary:/media/sd --mount=\$DATA_DIR/share:/home/tiny/公共 --mount=\$DATA_DIR/tiny:/home/tiny/.local/share/tiny --mount=/storage/self/primary/Fonts:/usr/share/fonts/wpsm --mount=/storage/self/primary/AppFiles/Fonts:/usr/share/fonts/yozom --mount=/system/fonts:/usr/share/fonts/androidm --mount=/storage/self/primary/Pictures:/home/tiny/图片 --mount=/storage/self/primary/Music:/home/tiny/音乐 --mount=/storage/self/primary/Movies:/home/tiny/视频 --mount=/storage/self/primary/Download:/home/tiny/下载 --mount=/storage/self/primary/DCIM:/home/tiny/照片 --mount=/storage/self/primary/Documents:/home/tiny/文档 --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.stat:/proc/stat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/.tmoe-container.version:/proc/version --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/bus:/proc/bus --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/buddyinfo:/proc/buddyinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/cgroups:/proc/cgroups --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/consoles:/proc/consoles --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/crypto:/proc/crypto --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/devices:/proc/devices --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/diskstats:/proc/diskstats --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/execdomains:/proc/execdomains --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/fb:/proc/fb --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/filesystems:/proc/filesystems --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/interrupts:/proc/interrupts --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/iomem:/proc/iomem --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/ioports:/proc/ioports --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kallsyms:/proc/kallsyms --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/keys:/proc/keys --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/key-users:/proc/key-users --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/kpageflags:/proc/kpageflags --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/loadavg:/proc/loadavg --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/locks:/proc/locks --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/misc:/proc/misc --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/modules:/proc/modules --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/pagetypeinfo:/proc/pagetypeinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/partitions:/proc/partitions --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/sched_debug:/proc/sched_debug --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/softirqs:/proc/softirqs --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/timer_list:/proc/timer_list --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/uptime:/proc/uptime --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmallocinfo:/proc/vmallocinfo --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/vmstat:/proc/vmstat --mount=\$CONTAINER_DIR/usr/local/etc/tmoe-linux/proot_proc/zoneinfo:/proc/zoneinfo \$EXTRA_MOUNT /usr/bin/env -i HOSTNAME=TINY HOME=/home/tiny USER=tiny TERM=xterm-256color SDL_IM_MODULE=fcitx XMODIFIERS=@im=fcitx QT_IM_MODULE=fcitx GTK_IM_MODULE=fcitx TMOE_CHROOT=false TMOE_PROOT=true TMPDIR=/tmp MOZ_FAKE_NO_SANDBOX=1 DISPLAY=:4 PULSE_SERVER=tcp:127.0.0.1:4718 LANG=zh_CN.UTF-8 SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games \$EXTRA_OPT /bin/bash -l";
static final ButtonStyle commandButtonStyle = OutlinedButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
@@ -463,6 +474,8 @@ class G {
static ValueNotifier<bool> bootTextChange = ValueNotifier(true); //更改值,用于刷新启动命令
static ValueNotifier<String> updateText = ValueNotifier("小小电脑"); //加载界面的说明文字
static bool wasBoxEnabled = false; //本次启动时是否启用了box86/64
static late SharedPreferences prefs;
}
@@ -726,11 +739,10 @@ done
G.audioPty = Pty.start(
"/system/bin/sh"
);
//pulseaudio也需要一个tmp文件夹这里选择前面的cache没有什么特别的原因不行再换
//pulseaudio还需要一个文件夹放配置这里用share
G.audioPty!.write(const Utf8Encoder().convert("""
export DATA_DIR=${G.dataPath}
\$DATA_DIR/busybox sed "s/4713/${Util.getGlobal("defaultAudioPort") as int}/g" \$DATA_DIR/bin/pulseaudio.conf > \$DATA_DIR/bin/pulseaudio.conf.tmp
rm -rf \$DATA_DIR/pulseaudio_tmp/*
TMPDIR=\$DATA_DIR/pulseaudio_tmp HOME=\$DATA_DIR/pulseaudio_tmp XDG_CONFIG_HOME=\$DATA_DIR/pulseaudio_tmp LD_LIBRARY_PATH=\$DATA_DIR/bin \$DATA_DIR/bin/pulseaudio -F \$DATA_DIR/bin/pulseaudio.conf.tmp
exit
"""));
@@ -738,11 +750,16 @@ exit
}
static Future<void> launchCurrentContainer() async {
String extraMount = "";
String extraOpt = "";
if (Util.getGlobal("getifaddrsBridge")) {
Util.execute("${G.dataPath}/bin/getifaddrs_bridge_server ${G.dataPath}/containers/${G.currentContainer}/tmp/.getifaddrs-bridge");
extraOpt += "LD_PRELOAD=/home/tiny/.local/share/tiny/extra/getifaddrs_bridge_client_lib.so ";
}
if (Util.getGlobal("uos")) {
extraMount += "--mount=\$DATA_DIR/tiny/wechat/uos-lsb:/etc/lsb-release --mount=\$DATA_DIR/tiny/wechat/uos-release:/usr/lib/os-release ";
extraMount += "--mount=\$DATA_DIR/tiny/wechat/license/var/uos:/var/uos --mount=\$DATA_DIR/tiny/wechat/license/var/lib/uos-license:/var/lib/uos-license ";
}
if (Util.getGlobal("virgl")) {
Util.execute("""
export DATA_DIR=${G.dataPath}
@@ -750,10 +767,21 @@ export CONTAINER_DIR=\$DATA_DIR/containers/${G.currentContainer}
${G.dataPath}/bin/virgl_test_server ${Util.getGlobal("defaultVirglCommand")}""");
extraOpt += "${Util.getGlobal("defaultVirglOpt")} ";
}
if (Util.getGlobal("isBoxEnabled")) {
G.wasBoxEnabled = true;
extraMount += "--mount=\$DATA_DIR/tiny/cross/box86:/home/tiny/.local/bin/box86 --mount=\$DATA_DIR/tiny/cross/box64:/home/tiny/.local/bin/box64 ";
}
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 ";
}
Util.termWrite(
"""
export DATA_DIR=${G.dataPath}
export CONTAINER_DIR=\$DATA_DIR/containers/${G.currentContainer}
export EXTRA_MOUNT="$extraMount"
export EXTRA_OPT="$extraOpt"
#export PROOT_L2S_DIR=\$DATA_DIR/containers/0/.l2s
cd \$DATA_DIR
@@ -801,7 +829,8 @@ clear""");
}
return KeyEventResult.ignored;
},
child: WebViewWidget(controller: G.controller),
child: GestureDetector(onSecondaryTap: () {
}, child: WebViewWidget(controller: G.controller))
);
}));
}

View File

@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.17.2"
version: "1.18.0"
convert:
dependency: transitive
description:
@@ -114,10 +114,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
url: "https://pub.dev"
source: hosted
version: "2.0.3"
version: "3.0.1"
flutter_pty:
dependency: "direct main"
description:
@@ -140,10 +140,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.2"
http_parser:
dependency: transitive
description:
@@ -164,10 +164,10 @@ packages:
dependency: transitive
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "3.0.0"
matcher:
dependency: transitive
description:
@@ -188,10 +188,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
path:
dependency: transitive
description:
@@ -252,42 +252,50 @@ packages:
dependency: "direct main"
description:
name: permission_handler
sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5
sha256: "860c6b871c94c78e202dc69546d4d8fd84bd59faeb36f8fb9888668a53ff4f78"
url: "https://pub.dev"
source: hosted
version: "10.4.5"
version: "11.1.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47"
sha256: "2f1bec180ee2f5665c22faada971a8f024761f632e93ddc23310487df52dcfa6"
url: "https://pub.dev"
source: hosted
version: "10.3.6"
version: "12.0.1"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
sha256: "1a816084338ada8d574b1cb48390e6e8b19305d5120fe3a37c98825bacc78306"
url: "https://pub.dev"
source: hosted
version: "9.1.4"
version: "9.2.0"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: d96ff56a757b7f04fa825c469d296c5aebc55f743e87bd639fef91a466a24da8
url: "https://pub.dev"
source: hosted
version: "0.1.0+1"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4"
sha256: d87349312f7eaf6ce0adaf668daf700ac5b06af84338bd8b8574dfbd93ffe1a1
url: "https://pub.dev"
source: hosted
version: "3.12.0"
version: "4.0.2"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
sha256: "1e8640c1e39121128da6b816d236e714d2cf17fac5a105dd6acdd3403a628004"
url: "https://pub.dev"
source: hosted
version: "0.1.3"
version: "0.2.0"
platform:
dependency: transitive
description:
@@ -308,10 +316,10 @@ packages:
dependency: transitive
description:
name: plugin_platform_interface
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
url: "https://pub.dev"
source: hosted
version: "2.1.6"
version: "2.1.7"
quiver:
dependency: transitive
description:
@@ -372,10 +380,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
@@ -401,18 +409,18 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
string_scanner:
dependency: transitive
description:
@@ -433,10 +441,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
version: "0.6.1"
typed_data:
dependency: transitive
description:
@@ -473,10 +481,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
sha256: "4ac97281cf60e2e8c5cc703b2b28528f9b50c8f7cebc71df6bdf0845f647268a"
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
url: "https://pub.dev"
source: hosted
version: "6.2.0"
version: "6.2.1"
url_launcher_linux:
dependency: transitive
description:
@@ -505,10 +513,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2"
sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.2.1"
url_launcher_windows:
dependency: transitive
description:
@@ -529,10 +537,10 @@ packages:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
version: "0.3.0"
webview_flutter:
dependency: "direct main"
description:
@@ -553,10 +561,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
version: "2.8.0"
webview_flutter_wkwebview:
dependency: transitive
description:
@@ -569,10 +577,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
sha256: "7c99c0e1e2fa190b48d25c81ca5e42036d5cac81430ef249027d97b0935c553f"
url: "https://pub.dev"
source: hosted
version: "5.0.9"
version: "5.1.0"
xdg_directories:
dependency: transitive
description:
@@ -590,5 +598,5 @@ packages:
source: hosted
version: "3.5.0"
sdks:
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.11+1
version: 1.0.12+1
environment:
sdk: '>=3.1.0 <4.0.0'
@@ -33,8 +33,8 @@ dependencies:
xterm: ^3.5.0
flutter_pty: ^0.4.0
path_provider: ^2.1.0
webview_flutter: ^4.2.3
permission_handler: ^10.4.3
webview_flutter: ^4.4.2
permission_handler: ^11.0.1
http: ^1.1.0
retry: ^3.1.2
url_launcher: ^6.1.12
@@ -58,7 +58,7 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
flutter_lints: ^3.0.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

BIN
readme/img1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
readme/img2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

BIN
readme/img3.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 MiB

BIN
readme/img4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
readme/img5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB