Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d777234531 | ||
|
|
7f7b8700e9 | ||
|
|
8a55f1a898 | ||
|
|
8617dba406 | ||
|
|
8e07f57998 | ||
|
|
68ca11e7ed | ||
|
|
77b7973a9a | ||
|
|
8a5ce94abf | ||
|
|
ca398017e4 | ||
|
|
9f66f9e513 | ||
|
|
459154fdd4 | ||
|
|
464dd5afe7 | ||
|
|
551ccf18f1 | ||
|
|
364f842d08 | ||
|
|
bc77996904 | ||
|
|
f33c215327 | ||
|
|
7f59106252 | ||
|
|
34b2379a28 | ||
|
|
e523a044bb | ||
|
|
bd546e7da7 | ||
|
|
3009d059b3 | ||
|
|
5ebaab4126 | ||
|
|
4443b6e3f6 | ||
|
|
c4c875c6ef | ||
|
|
67dd396877 | ||
|
|
955801810c | ||
|
|
cc26e2d74d | ||
|
|
f3c0335973 | ||
|
|
8a9323a915 | ||
|
|
638e8e7007 | ||
|
|
04163ac987 | ||
|
|
64d3831c83 | ||
|
|
e19a3a55e9 | ||
|
|
6454a6b69f | ||
|
|
63a3bbd3dc | ||
|
|
ecb2880a8c | ||
|
|
5ae88252e7 | ||
|
|
c7dd1010e1 | ||
|
|
edae591755 | ||
|
|
1642affb30 | ||
|
|
b6af099255 | ||
|
|
c5feebec17 | ||
|
|
e07ba8a8ae | ||
|
|
517565e636 | ||
|
|
6c7d0a0421 | ||
|
|
725e13ebea | ||
|
|
7a6db4e4cf | ||
|
|
eeaccc3371 | ||
|
|
44eefd161c | ||
|
|
2f7c28019e | ||
|
|
2eff9392bf | ||
|
|
6f5109e74b | ||
|
|
dd0d938c36 | ||
|
|
79b1574677 | ||
|
|
091313f6d3 | ||
|
|
338a41ca1e | ||
|
|
62f1294f81 | ||
|
|
f20bcfb91b | ||
|
|
12997c8fd6 | ||
|
|
0a1d61ed46 | ||
|
|
9d0e48bb3e | ||
|
|
667eaa0706 | ||
|
|
018352b152 | ||
|
|
07224a73f6 | ||
|
|
91a2d94a9b | ||
|
|
bdd0888585 | ||
|
|
1408bd063e | ||
|
|
54b3d11431 | ||
|
|
b879d57f53 | ||
|
|
de73e1e586 | ||
|
|
bd5f742b31 | ||
|
|
e80e4a74c0 | ||
|
|
3c16f11c6d | ||
|
|
69dd1e6459 | ||
|
|
b067a90a17 | ||
|
|
2bb170a4e3 | ||
|
|
fd535f0e20 | ||
|
|
a5a381604d | ||
|
|
a911efdc54 | ||
|
|
49c2377e46 | ||
|
|
a117050fde | ||
|
|
958d7839ff | ||
|
|
106b5fc325 | ||
|
|
699f1eef37 | ||
|
|
905ff609b1 | ||
|
|
70c2018ddf | ||
|
|
b1895af653 | ||
|
|
62995e0a5d | ||
|
|
5ebbaf7073 | ||
|
|
cb1f4b23ee | ||
|
|
0d2f5f4e91 | ||
|
|
d54d1ef6f3 | ||
|
|
0377aa7b8f | ||
|
|
232afe9929 | ||
|
|
fcb472594d | ||
|
|
aa6d0feed7 | ||
|
|
1ee935105e | ||
|
|
7242c45e38 | ||
|
|
d0a539d6dc | ||
|
|
3e443ceedc | ||
|
|
b50622787d | ||
|
|
231d1167e0 | ||
|
|
a956d26f6d | ||
|
|
c2ee3b694c | ||
|
|
09bf75beed | ||
|
|
b00ede9483 | ||
|
|
b8393dacfd | ||
|
|
ce5ad3b758 | ||
|
|
cf15e2e07d | ||
|
|
938745036d | ||
|
|
b3428555c6 | ||
|
|
2a19c5eb78 | ||
|
|
54a941da63 | ||
|
|
87beedef68 | ||
|
|
c6afc4d468 | ||
|
|
6dbe710fdc | ||
|
|
cf8ce47662 | ||
|
|
86ce2315d4 | ||
|
|
6e51e5b2d2 | ||
|
|
0971059111 | ||
|
|
2cf19179f9 | ||
|
|
b6d4d2f11b | ||
|
|
5a6f04d094 | ||
|
|
195a2f50a3 | ||
|
|
16a14c8a3e | ||
|
|
f15899be95 | ||
|
|
27a5073551 | ||
|
|
b4ca9ae4f7 | ||
|
|
2ef590beb7 | ||
|
|
e6555b2166 | ||
|
|
bba56cc0ca | ||
|
|
f9d5818b91 |
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: Bug 报告
|
||||||
|
description: 报告软件异常行为(提交前请阅读所有说明文字)
|
||||||
|
title: "[Bug] "
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**必读须知:**
|
||||||
|
- 请先搜索[所有issue](https://github.com/Cateners/tiny_computer/issues?q=is%3Aissue),**相同问题重复提交会被直接关闭**
|
||||||
|
- 请先自查[常见使用问题](https://gitee.com/caten/tc-hints/blob/master/pool/faq.md),是否能解决你的问题
|
||||||
|
- 本模板中的每项要求都有其特定原因,请完整填写
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: "设备型号"
|
||||||
|
description: |
|
||||||
|
**为什么需要这个信息?**
|
||||||
|
许多Bug与设备强相关,例如:
|
||||||
|
- 三星OneUI 7无法使用v1.0.23及以下版本(issue #303)
|
||||||
|
- 鸿蒙4缺少无线调试选项
|
||||||
|
placeholder: "品牌+具体型号"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: os-version
|
||||||
|
attributes:
|
||||||
|
label: "操作系统版本"
|
||||||
|
description: |
|
||||||
|
**为什么需要这个信息?**
|
||||||
|
Android各版本存在兼容性差异
|
||||||
|
placeholder: "完整系统名称+版本号"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: app-version
|
||||||
|
attributes:
|
||||||
|
label: "小小电脑版本"
|
||||||
|
description: |
|
||||||
|
**为什么需要这个信息?**
|
||||||
|
1. 旧版问题可能已在新版修复(请始终使用最新版)
|
||||||
|
2. 不同桌面环境(XFCE/LXQT/GXDE)行为可能不同
|
||||||
|
**如果不是最新版,请做好问题被忽略的准备**
|
||||||
|
placeholder: "版本号+桌面环境(如:v1.0.23 GXDE)"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: is-latest
|
||||||
|
attributes:
|
||||||
|
label: "是否最新版?"
|
||||||
|
options:
|
||||||
|
- "是"
|
||||||
|
- "否"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: why-not-latest
|
||||||
|
attributes:
|
||||||
|
label: "若非最新版,必须说明不使用最新版的原因"
|
||||||
|
placeholder: "详细解释原因..."
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: "重现问题的操作过程"
|
||||||
|
description: |
|
||||||
|
**请注意:**
|
||||||
|
请提供从启动软件开始到问题发生的**完整屏幕录制视频**,而不要使用文字描述或截图,因为根据以往的issue来看,用户的描述会遗漏可能的细节。
|
||||||
|
由于Linux环境的复杂性,任何操作细节(如权限、环境配置等)都可能影响问题的重现。确保你的问题在新安装的小小电脑上可以复现。
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**问题优先级说明:**
|
||||||
|
本软件的初衷是安装PC级软件如WPS、CAJ Viewer、亿图图示。小小电脑本身的问题,以及和这些软件相关的问题会得到重视。如果是其他问题,尤其是第三方软件或Linux本身的使用方法等,请在[discussion](https://github.com/Cateners/tiny_computer/discussions)区发布讨论
|
||||||
81
.github/ISSUE_TEMPLATE/bug_report_eng.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Report abnormal software behavior (please read all instructions before submitting)
|
||||||
|
title: "[Bug] "
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**Important Notes:**
|
||||||
|
- First search [all issues](https://github.com/Cateners/tiny_computer/issues?q=is%3Aissue). **Duplicate reports will be closed immediately**
|
||||||
|
- Every requirement in this template has its specific purpose. Please complete all fields
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: "Device Model"
|
||||||
|
description: |
|
||||||
|
**Why is this needed?**
|
||||||
|
Many bugs are device-specific, such as:
|
||||||
|
- Samsung OneUI 7 incompatible with v1.0.23 and below (issue #303)
|
||||||
|
- HarmonyOS 4 missing wireless debugging option
|
||||||
|
placeholder: "Brand + specific model"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: os-version
|
||||||
|
attributes:
|
||||||
|
label: "Operating System Version"
|
||||||
|
description: |
|
||||||
|
**Why is this needed?**
|
||||||
|
Compatibility varies across Android versions
|
||||||
|
placeholder: "Full OS name + version number"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: app-version
|
||||||
|
attributes:
|
||||||
|
label: "Tiny Computer Version"
|
||||||
|
description: |
|
||||||
|
**Why is this needed?**
|
||||||
|
1. Old version issues may have been fixed in newer releases (always use the latest version)
|
||||||
|
2. Different desktop environments (XFCE/LXQT/GXDE) may behave differently
|
||||||
|
**If not using the latest version, be prepared for your issue to be ignored**
|
||||||
|
placeholder: "Version number + desktop environment (e.g., v1.0.23 GXDE)"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: is-latest
|
||||||
|
attributes:
|
||||||
|
label: "Is this the latest version?"
|
||||||
|
options:
|
||||||
|
- "Yes"
|
||||||
|
- "No"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: why-not-latest
|
||||||
|
attributes:
|
||||||
|
label: "If not using the latest version, you must explain the reason for not using the latest version"
|
||||||
|
placeholder: "Explain in detail..."
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: "Steps to reproduce the issue"
|
||||||
|
description: |
|
||||||
|
**Please note:**
|
||||||
|
Provide a **complete screen recording video** starting from launching the software until the issue occurs, rather than using text descriptions or screenshots. Based on past issues, user descriptions often omit potential details.
|
||||||
|
Due to the complexity of the Linux environment, any operational details (such as permissions, environment configurations, etc.) may affect issue reproduction. Ensure your issue can be reproduced on a freshly installed Tiny Computer.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**Issue Priority Explanation:**
|
||||||
|
The original purpose of this software is to install PC-level applications such as WPS, CAJ Viewer, and Edraw Max. Issues related to the Tiny Computer itself and problems associated with these software will be prioritized. For other issues, especially those involving third-party software or general Linux usage, please post in the [discussion](https://github.com/Cateners/tiny_computer/discussions) section.
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: 获取帮助或提问
|
||||||
|
url: https://github.com/Cateners/tiny_computer/discussions
|
||||||
|
about: 请在这里提问和讨论,不要将其作为 Issue。
|
||||||
21
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: 功能请求
|
||||||
|
description: "请先确认:该功能是否能显著提升小小电脑的使用体验?"
|
||||||
|
title: "[Feature] "
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**必读须知:**
|
||||||
|
- 请先搜索[所有issue](https://github.com/Cateners/tiny_computer/issues?q=is%3Aissue),**相同问题重复提交会被直接关闭**
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: rationale
|
||||||
|
attributes:
|
||||||
|
label: "必须说明使用场景和价值"
|
||||||
|
description: |
|
||||||
|
**为什么需要这个?实现这个会对其他用户带来什么好处?开发者会花费许多时间在上面,这对开发者有什么好处?**
|
||||||
|
(简单来说,就是不要许愿,用充分的理由来说服我或其他潜在(?)的开发者吧!如果你想要一个功能,要么有时间自己学自己开发,要么用钱雇人做,要么等待其他和你想法一致且有时间或有钱的人来做)
|
||||||
|
因为精力有限,我会更高可能采纳有价值且易实现的功能。没能处理的issue会保留以让更多人看到,也许网友会有更好的解决办法!
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
21
.github/ISSUE_TEMPLATE/feature_request_eng.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: "Please confirm first: Will this feature significantly improve the user experience of Tiny Computer?"
|
||||||
|
title: "[Feature] "
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
**Important Notes:**
|
||||||
|
- Please search [all issues](https://github.com/Cateners/tiny_computer/issues?q=is%3Aissue) first. **Duplicate submissions will be closed directly**
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: rationale
|
||||||
|
attributes:
|
||||||
|
label: "Must specify usage scenarios and value"
|
||||||
|
description: |
|
||||||
|
**Why is this needed? What benefits will implementing this bring to other users? Developers will spend a lot of time on this—what’s in it for them?**
|
||||||
|
(In short, don’t just make a wish—convince me or other potential (?) developers with solid reasoning! If you want a feature, either take the time to learn and develop it yourself, pay someone to do it, or wait for someone who shares your idea and has the time or money to implement it.)
|
||||||
|
Due to limited resources, I'm more likely to adopt valuable and easily implementable features. Unaddressed issues will remain visible for community solutions!
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
17
.gitignore
vendored
@@ -39,10 +39,27 @@ app.*.symbols
|
|||||||
app.*.map.json
|
app.*.map.json
|
||||||
|
|
||||||
# Android Studio will place build artifacts here
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/build
|
||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
/android/app/.cxx
|
||||||
|
|
||||||
/backup
|
/backup
|
||||||
|
|
||||||
assets/xa*
|
assets/xa*
|
||||||
|
assets/patch.tar.gz
|
||||||
|
|
||||||
|
android/app/src/main/jniLibs/*
|
||||||
|
|
||||||
|
devtools_options.yaml
|
||||||
|
|
||||||
|
lib/l10n/app_localizations*
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
|
||||||
|
# Configuration files
|
||||||
|
android/keystore.properties
|
||||||
|
android/local.properties
|
||||||
0
.gitmodules
vendored
Normal file
25
.metadata
@@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "efbf63d9c66b9f6ec30e9ad4611189aa80003d31"
|
revision: "edada7c56edf4a183c1735310e123c7f923584f1"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
@@ -13,26 +13,11 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
|
||||||
- platform: android
|
- platform: android
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
|
||||||
- platform: ios
|
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
- platform: linux
|
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
- platform: macos
|
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
- platform: web
|
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
- platform: windows
|
|
||||||
create_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
base_revision: efbf63d9c66b9f6ec30e9ad4611189aa80003d31
|
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|||||||
124
README.md
@@ -1,70 +1,112 @@
|
|||||||
|
[](https://github.com/Cateners/tiny_computer/blob/master/readme/cover0.png)
|
||||||
|
|
||||||
# 小小电脑
|
# 小小电脑
|
||||||
|
|
||||||
<img decoding="async" src="readme/cover0.png" width="50%">
|
给所有安卓 9 以上 arm64 设备的“PC 应用引擎”平替。你可以在小小电脑上安装 PC 级 WPS、CAJ Viewer、亿图图示等软件。
|
||||||
|
|
||||||
即开即用的类PC环境,内置WPS、火狐浏览器、VS Code等常用软件
|
|
||||||
|
|
||||||
Click-to-run ubuntu jammy xfce on android for Chinese users, with fcitx pinyin input method and wps office preinstalled. No termux required.
|
Run Debian Bookworm with XFCE, LXQt, or other desktop environments on Android—just with one click. Originally developed for Chinese users to run applications like WPS Office, it comes preinstalled with tools such as the Fcitx Pinyin input method. Please note that this app does not require Termux.
|
||||||
|
|
||||||
|
To change the language inside the container, simply run the `tmoe` command, select “Manager” and navigate to the locale settings. The root filesystem was built using [tmoe](https://github.com/2moe/tmoe), so locale configuration is handled through it. You will also need to update the `LANG=zh_CN.UTF-8` environment variable in the startup command (go to Control → Advanced Settings → Startup Command) when switching to another language.
|
||||||
|
|
||||||
|
Note: English UI is supported since version 1.0.23, though some hint texts may still appear in Chinese.
|
||||||
|
As of version 1.0.100, the container will automatically switch to English if it detects that your device is not using Chinese.
|
||||||
|
|
||||||
|
## 特点
|
||||||
|
|
||||||
|
- 一键安装,即开即用
|
||||||
|
- 来自 kali-undercover 的 win10 主题(仅 xfce 版本),友好的界面
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 提供常用软件的一键安装指令(点击图片可查看更多说明)
|
||||||
|
|
||||||
|
[](https://gitee.com/caten/tc-hints/blob/master/pool/solution.md)
|
||||||
|
|
||||||
|
- 可方便地改变屏幕缩放,不用担心屏幕过大或过小 (点击图片可查看更多说明)
|
||||||
|
|
||||||
|
[](https://gitee.com/caten/tc-hints/blob/master/pool/scale.md)
|
||||||
|
|
||||||
|
- 便捷访问设备文件,或通过设备 SAF 访问软件文件(点击图片可查看更多说明)
|
||||||
|
|
||||||
|
[](https://gitee.com/caten/tc-hints/blob/master/pool/fileaccess.md)
|
||||||
|
|
||||||
|
- 提供终端和众多可调节参数供高级用户使用
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 下载
|
||||||
|
|
||||||
|
小小电脑提供多个版本。要将小小电脑作为 PC 应用引擎使用,请在 [Releases](https://github.com/Cateners/tiny_computer/releases) 页面下载并安装 [XFCE](https://xfce.org/) 版本(tiny-computer-xfce.apk)。
|
||||||
|
|
||||||
|
如果遇到黑屏问题,请卸载后尝试 [LXQt](https://lxqt-project.org/) 版本([Releases](https://github.com/Cateners/tiny_computer/releases) 页寻找 tiny-computer-lxqt.apk)。
|
||||||
|
|
||||||
|
这些版本的区别在于桌面环境不同。你可以简单地理解为界面不一样,但功能基本一致。
|
||||||
|
|
||||||
|
LXQt 的界面示例:
|
||||||
|
|
||||||
|
[](https://camo.githubusercontent.com/016ff8803c228f26db750c8424777d8e04a3aebec4ff11d8436a0b22a2e6f58a/68747470733a2f2f6c7871742d70726f6a6563742e6f72672f696d616765732f73637265656e73686f74732f616d6269616e63652e706e67)
|
||||||
|
|
||||||
|
如果你下载小小电脑是为了体验更多桌面环境,享受折腾 Linux 的乐趣,这里也有一些其他版本供下载!
|
||||||
|
|
||||||
|
和 [GXDE](https://www.gxde.org/) 团队合作的版本 [#129](https://github.com/Cateners/tiny_computer/issues/129)。可在[此处](https://mirrors.sdu.edu.cn/spark-store-repository/GXDE-OS/APK/)下载。GXDE 的界面示例:
|
||||||
|
|
||||||
|
[](https://www.gxde.top/1.jpg)
|
||||||
|
|
||||||
|
由[灵墨桌面](https://www.lingmo.org/)开发者提供的版本[#218](https://github.com/Cateners/tiny_computer/issues/218)。灵墨桌面的界面[示例](https://www.bilibili.com/video/BV1Ci421R7AR)。
|
||||||
|
|
||||||
## 原理
|
## 原理
|
||||||
|
|
||||||
使用proot运行ubuntu环境
|
使用 proot 运行 debian 环境。
|
||||||
|
|
||||||
内置[noVNC](https://github.com/novnc/noVNC)显示图形界面
|
内置 [noVNC](https://github.com/novnc/noVNC)/[AVNC](https://github.com/gujjwal00/avnc)/[Termux:X11](https://github.com/termux/termux-x11) 显示图形界面。
|
||||||
|
|
||||||
初次启动由于解压的缘故要点时间
|
|
||||||
以后点开就能用
|
|
||||||
|
|
||||||
只支持arm64安卓
|
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
assets的文件来源如下:
|
assets 和 android/app/src/main/jniLibs 的文件源信息可以在[这里](https://github.com/Cateners/tiny_computer/blob/master/extra/readme.md)找到。
|
||||||
|
|
||||||
- [proot](https://github.com/termux/proot/), 使用[build-proot-android](https://github.com/green-green-avk/build-proot-android)脚本编译
|
完整的容器制作过程可以在[这里](https://github.com/Cateners/tiny_computer/blob/master/extra/build-tiny-rootfs.md)看到。
|
||||||
- [busybox](https://github.com/meefik/busybox)
|
|
||||||
- [Xserver XSDL, pulseaudio相关文件](https://github.com/pelya/commandergenius/tree/sdl_android/project/jni/application/xserver)
|
|
||||||
- [proot-distro, ubuntu包来源](https://github.com/termux/proot-distro)
|
|
||||||
|
|
||||||
其中busybox和pulseaudio相关文件都是直接用了二进制文件。
|
数据包、patch.tar.gz 以及 jniLibs 的文件不在代码仓更新,而是随 releases 提供,主要是为了避免 git 越来越大。
|
||||||
|
|
||||||
(pulseaudio我真的编译不来,如果你会的话请教教我吧)
|
|
||||||
|
|
||||||
对ubuntu容器进行了如下修改:
|
|
||||||
- 安装了xfce环境、tigerVNC、noVNC;
|
|
||||||
- 使用kali-undercover提供的Win10主题美化xfce;
|
|
||||||
- 安装了wps office, 对wps office进行了如下修改:
|
|
||||||
- 界面改成了多组件,避免无法打开wps;
|
|
||||||
- 补上了缺失的字体;
|
|
||||||
- 安装了VS Code和中文插件;
|
|
||||||
- 安装了fcitx输入法和云拼音组件。按<Ctrl+空格>切换输入法。
|
|
||||||
- 强烈建议**不要**使用安卓中文输入法直接输入中文,而是使用英文键盘通过容器的输入法输入中文,避免丢字错字。
|
|
||||||
- 对noVNC进行[修改](https://github.com/Cateners/noVNC) (scale_factor分支),添加了scale factor滑块控制缩放
|
|
||||||
- 在主目录下提供storage文件夹,通过此文件夹可以方便地访问手机存储(如果提供了存储权限的话)
|
|
||||||
- 启动时会尝试挂载手机的一些字体目录(AppFiles/Fonts、Fonts和/system/fonts), 如果这些目录下有字体文件的话会一并加载到系统中,无需额外安装
|
|
||||||
- 最后采用tar.xz压缩,用split命令分成了xa*等多个文件
|
|
||||||
|
|
||||||
数据包不再在assets中更新,而是随releases提供,主要是为了避免git越来越大
|
|
||||||
|
|
||||||
lib 目录:
|
lib 目录:
|
||||||
|
|
||||||
- main.dart文件,页面布局,老实说已经有点乱了
|
- main.dart 文件,页面布局,有点乱
|
||||||
- workflow.dart文件,逻辑部分,目前也还算简单
|
- workflow.dart 文件,逻辑部分,目前也还可以理解
|
||||||
- Util 工具类
|
- Util 工具类
|
||||||
|
- TermPty 一个终端
|
||||||
- G 全局变量类
|
- G 全局变量类
|
||||||
- Workflow 从软件点开到容器启动的所有步骤
|
- Workflow 从软件点开到容器启动的所有步骤
|
||||||
|
- l10n 文件夹,包含多语言文件
|
||||||
|
|
||||||
|
## 编译
|
||||||
|
|
||||||
|
你需要配置好 flutter 和安卓 sdk。
|
||||||
|
|
||||||
|
在编译之前,需要在 release 中下载 jniLibs.zip ,将里面的库文件解压后放到 android/app/src/main/jniLibs/arm64-v8a;下载 patch.tar.gz 拷贝到 assets。以及下载系统 rootfs(或者[自行制作](https://github.com/Cateners/tiny_computer/blob/master/extra/build-tiny-rootfs.md)),之后使用 split 命令分割,拷贝到 assets。一般我将其分为 98MB。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
split -b 98M debian.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
|
接下来就可以编译了。如果要编译release版本,需要设置发布密钥,可以参考android/keystore.properties.example文件。
|
||||||
|
|
||||||
|
我使用的编译命令如下:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flutter build apk --target-platform android-arm64 --split-per-abi --obfuscate --split-debug-info=tiny_computer/sdi
|
||||||
|
```
|
||||||
|
|
||||||
## 目前已知 bug
|
## 目前已知 bug
|
||||||
|
|
||||||
多用户/分身情形无法使用apt, 其它见issue
|
多用户/分身情形无法 sudo , 其它见 issue。
|
||||||
|
|
||||||
## 一些链接
|
## 一些链接
|
||||||
|
|
||||||
这是我的第一个 flutter 软件,感谢这些项目为我指路
|
这是我的第一个 flutter 软件,感谢这些项目为我指路
|
||||||
|
|
||||||
- 要一点基础的 [《Flutter实战·第二版》](https://book.flutterchina.club)
|
- 要一点基础的[《Flutter实战·第二版》](https://book.flutterchina.club/)
|
||||||
- 也许是零基础的Flutter视频课程 [freeCodeCamp Flutter Course](https://www.youtube.com/watch?v=wFn-m-OgKPU&list=PL6yRaaP0WPkVtoeNIGqILtRAgd3h2CNpT)
|
- 也许是零基础的Flutter视频课程 [freeCodeCamp Flutter Course](https://www.youtube.com/watch?v=wFn-m-OgKPU&list=PL6yRaaP0WPkVtoeNIGqILtRAgd3h2CNpT)
|
||||||
|
|
||||||
- 安卓上的 VS Code [Code FA](https://github.com/nightmare-space/vscode_for_android)
|
- 安卓上的 VS Code [Code FA](https://github.com/nightmare-space/vscode_for_android)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -76,6 +118,4 @@ A few resources to get you started if this is your first Flutter project:
|
|||||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
For help getting started with Flutter development, view the
|
For help getting started with Flutter development, view the [online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference.
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
|
||||||
samples, guidance on mobile development, and a full API reference.
|
|
||||||
|
|||||||
@@ -22,22 +22,29 @@ if (flutterVersionName == null) {
|
|||||||
flutterVersionName = '1.0'
|
flutterVersionName = '1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
def keystorePropertiesFile = rootProject.file('keystore.properties')
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace "com.example.tiny_computer"
|
namespace "com.example.tiny_computer"
|
||||||
compileSdkVersion flutter.compileSdkVersion
|
compileSdkVersion flutter.compileSdkVersion
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion "27.0.12077973" // flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
main.java.srcDirs += 'src/main/java'
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
@@ -45,28 +52,83 @@ android {
|
|||||||
applicationId "com.fct.tiny"
|
applicationId "com.fct.tiny"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdkVersion flutter.minSdkVersion
|
minSdk 28 // glob() version //proot version //ffmpeg_kit; flutter.minSdkVersion
|
||||||
targetSdkVersion 28 //https://github.com/termux/termux-app/issues/1072; native; linker; flutter.targetSdkVersion
|
targetSdk 28 //https://github.com/termux/termux-app/issues/1072; native; linker; flutter.targetSdkVersion
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
|
||||||
|
buildConfigField "String", "COMMIT", "\"" + ("git rev-parse HEAD\n".execute().getText().trim() ?: (System.getenv('CURRENT_COMMIT') ?: "NO_COMMIT")) + "\""
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags "-std=c++11"
|
||||||
|
arguments "-DANDROID_STL=c++_shared"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
keyAlias keystoreProperties['keyAlias']
|
||||||
|
keyPassword keystoreProperties['keyPassword']
|
||||||
|
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||||
|
storePassword keystoreProperties['storePassword']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
signingConfig signingConfigs.release
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
minifyEnabled true
|
||||||
signingConfig signingConfigs.debug
|
shrinkResources true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
|
minifyEnabled true
|
||||||
|
shrinkResources false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
aidl true
|
||||||
|
dataBinding true
|
||||||
|
viewBinding true
|
||||||
|
buildConfig true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lint {
|
||||||
|
disable "NullSafeMutableLiveData"
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
//checkReleaseBuilds false
|
//checkReleaseBuilds false
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "src/main/cpp/CMakeLists.txt"
|
||||||
|
version "3.22.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
pickFirst 'lib/arm64-v8a/libc++_shared.so'
|
||||||
|
pickFirst 'lib/x86_64/libc++_shared.so'
|
||||||
|
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
|
||||||
|
pickFirst 'lib/arm64-v8a/libc++_shared.so'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source '../..'
|
source '../..'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {}
|
dependencies {
|
||||||
|
implementation "androidx.core:core-ktx:1.15.0"
|
||||||
|
implementation "androidx.appcompat:appcompat:1.7.0"
|
||||||
|
implementation "com.google.android.material:material:1.7.0"
|
||||||
|
implementation 'com.github.tiann:FreeReflection:3.2.2'
|
||||||
|
}
|
||||||
|
|||||||
17
android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Please add these rules to your existing keep rules in order to suppress warnings.
|
||||||
|
# This is generated automatically by the Android Gradle plugin.
|
||||||
|
-dontwarn android.app.ActivityThread
|
||||||
|
-dontwarn android.app.ContextImpl
|
||||||
|
-dontwarn android.app.IActivityManager
|
||||||
|
-dontwarn android.content.IIntentReceiver$Stub
|
||||||
|
-dontwarn android.content.IIntentReceiver
|
||||||
|
-dontwarn android.content.IIntentSender
|
||||||
|
-dontwarn android.content.pm.IPackageManager
|
||||||
|
-dontwarn com.google.errorprone.annotations.CanIgnoreReturnValue
|
||||||
|
-dontwarn com.google.errorprone.annotations.Immutable
|
||||||
|
# 保持 Termux X11 所有内容
|
||||||
|
-keep class com.termux.x11.** { *; }
|
||||||
|
-keepclassmembers class com.termux.x11.** { *; }
|
||||||
|
|
||||||
|
|
||||||
|
-dontwarn javax.annotation.Nullable
|
||||||
@@ -1,18 +1,26 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="小小电脑"
|
android:label="@string/tc_app_name"
|
||||||
android:name="${applicationName}"
|
android:name=".MainApplication"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:theme="@style/App.Theme"
|
||||||
|
android:extractNativeLibs="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="navigation|orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
@@ -28,6 +36,20 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".Signal9Activity"
|
||||||
|
android:exported="true"
|
||||||
|
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
|
||||||
|
<provider
|
||||||
|
android:name="com.example.tiny_computer.filepicker.TinyDocumentsProvider"
|
||||||
|
android:authorities="com.example.tiny_computer.documents"
|
||||||
|
android:exported="true"
|
||||||
|
android:grantUriPermissions="true"
|
||||||
|
android:permission="android.permission.MANAGE_DOCUMENTS">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||||
|
</intent-filter>
|
||||||
|
</provider>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|||||||
11
android/app/src/main/cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18.1)
|
||||||
|
project("native-socket")
|
||||||
|
|
||||||
|
# 添加库
|
||||||
|
add_library(native-socket SHARED native-socket.cpp)
|
||||||
|
|
||||||
|
# 链接日志库
|
||||||
|
find_library(log-lib log)
|
||||||
|
|
||||||
|
# 指定目标属性
|
||||||
|
target_link_libraries(native-socket ${log-lib})
|
||||||
78
android/app/src/main/cpp/native-socket.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#define LOG_TAG "NativeAudio"
|
||||||
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||||
|
|
||||||
|
int server_fd = -1;
|
||||||
|
int client_fd = -1;
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_com_example_tiny_1computer_AudioStream_nativeInit(JNIEnv *env, jobject thiz, jstring path) {
|
||||||
|
const char *socket_path = env->GetStringUTFChars(path, 0);
|
||||||
|
|
||||||
|
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (server_fd == -1) {
|
||||||
|
LOGE("Socket creation failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||||
|
unlink(socket_path); // Remove existing file if any
|
||||||
|
|
||||||
|
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||||
|
LOGE("Bind failed: %s", strerror(errno));
|
||||||
|
close(server_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(server_fd, 1) == -1) {
|
||||||
|
LOGE("Listen failed");
|
||||||
|
close(server_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(path, socket_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_com_example_tiny_1computer_AudioStream_nativeAccept(JNIEnv *env, jobject thiz) {
|
||||||
|
if (server_fd == -1) return -1;
|
||||||
|
// Blocks here until Linux connects
|
||||||
|
client_fd = accept(server_fd, NULL, NULL);
|
||||||
|
if (client_fd == -1) {
|
||||||
|
LOGE("Accept failed: %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
|
Java_com_example_tiny_1computer_AudioStream_nativeSend(JNIEnv *env, jobject thiz, jbyteArray data, jint size) {
|
||||||
|
if (client_fd == -1) return -1;
|
||||||
|
|
||||||
|
jbyte *buffer = env->GetByteArrayElements(data, NULL);
|
||||||
|
ssize_t sent = write(client_fd, buffer, size);
|
||||||
|
env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
|
||||||
|
|
||||||
|
if (sent == -1 && errno != EAGAIN) {
|
||||||
|
LOGE("Write failed (Broken Pipe?)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_com_example_tiny_1computer_AudioStream_nativeClose(JNIEnv *env, jobject thiz) {
|
||||||
|
if (client_fd != -1) { close(client_fd); client_fd = -1; }
|
||||||
|
if (server_fd != -1) { close(server_fd); server_fd = -1; }
|
||||||
|
}
|
||||||
BIN
android/app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
@@ -0,0 +1,270 @@
|
|||||||
|
package com.example.tiny_computer.filepicker;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.CancellationSignal;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.provider.DocumentsContract.Document;
|
||||||
|
import android.provider.DocumentsContract.Root;
|
||||||
|
import android.provider.DocumentsProvider;
|
||||||
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
|
import com.example.tiny_computer.R;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
//This file is mainly copied from Termux :P
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A document provider for the Storage Access Framework which exposes the files in the
|
||||||
|
* $HOME/ directory to other apps.
|
||||||
|
* <p/>
|
||||||
|
* Note that this replaces providing an activity matching the ACTION_GET_CONTENT intent:
|
||||||
|
* <p/>
|
||||||
|
* "A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you
|
||||||
|
* support both of them simultaneously, your app will appear twice in the system picker UI,
|
||||||
|
* offering two different ways of accessing your stored data. This would be confusing for users."
|
||||||
|
* - http://developer.android.com/guide/topics/providers/document-provider.html#43
|
||||||
|
*/
|
||||||
|
public class TinyDocumentsProvider extends DocumentsProvider {
|
||||||
|
|
||||||
|
private static final String ALL_MIME_TYPES = "*/*";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The default columns to return information about a root if no specific
|
||||||
|
// columns are requested in a query.
|
||||||
|
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
|
||||||
|
Root.COLUMN_ROOT_ID,
|
||||||
|
Root.COLUMN_MIME_TYPES,
|
||||||
|
Root.COLUMN_FLAGS,
|
||||||
|
Root.COLUMN_ICON,
|
||||||
|
Root.COLUMN_TITLE,
|
||||||
|
Root.COLUMN_SUMMARY,
|
||||||
|
Root.COLUMN_DOCUMENT_ID,
|
||||||
|
Root.COLUMN_AVAILABLE_BYTES
|
||||||
|
};
|
||||||
|
|
||||||
|
// The default columns to return information about a document if no specific
|
||||||
|
// columns are requested in a query.
|
||||||
|
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[]{
|
||||||
|
Document.COLUMN_DOCUMENT_ID,
|
||||||
|
Document.COLUMN_MIME_TYPE,
|
||||||
|
Document.COLUMN_DISPLAY_NAME,
|
||||||
|
Document.COLUMN_LAST_MODIFIED,
|
||||||
|
Document.COLUMN_FLAGS,
|
||||||
|
Document.COLUMN_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor queryRoots(String[] projection) {
|
||||||
|
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
||||||
|
final String applicationName = getContext().getString(R.string.tc_app_name);
|
||||||
|
final File BASE_DIR = new File(getContext().getFilesDir(), "containers");
|
||||||
|
final MatrixCursor.RowBuilder row = result.newRow();
|
||||||
|
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
|
||||||
|
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
|
||||||
|
row.add(Root.COLUMN_SUMMARY, null);
|
||||||
|
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
|
||||||
|
row.add(Root.COLUMN_TITLE, applicationName);
|
||||||
|
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
|
||||||
|
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
|
||||||
|
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
|
||||||
|
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
|
includeFile(result, documentId, null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
|
||||||
|
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
|
final File parent = getFileForDocId(parentDocumentId);
|
||||||
|
for (File file : parent.listFiles()) {
|
||||||
|
includeFile(result, null, file);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParcelFileDescriptor openDocument(final String documentId, String mode, CancellationSignal signal) throws FileNotFoundException {
|
||||||
|
final File file = getFileForDocId(documentId);
|
||||||
|
final int accessMode = ParcelFileDescriptor.parseMode(mode);
|
||||||
|
return ParcelFileDescriptor.open(file, accessMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
|
||||||
|
final File file = getFileForDocId(documentId);
|
||||||
|
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
return new AssetFileDescriptor(pfd, 0, file.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException {
|
||||||
|
File newFile = new File(parentDocumentId, displayName);
|
||||||
|
int noConflictId = 2;
|
||||||
|
while (newFile.exists()) {
|
||||||
|
newFile = new File(parentDocumentId, displayName + " (" + noConflictId++ + ")");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
boolean succeeded;
|
||||||
|
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||||
|
succeeded = newFile.mkdir();
|
||||||
|
} else {
|
||||||
|
succeeded = newFile.createNewFile();
|
||||||
|
}
|
||||||
|
if (!succeeded) {
|
||||||
|
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||||
|
}
|
||||||
|
return newFile.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteDocument(String documentId) throws FileNotFoundException {
|
||||||
|
File file = getFileForDocId(documentId);
|
||||||
|
if (!file.delete()) {
|
||||||
|
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDocumentType(String documentId) throws FileNotFoundException {
|
||||||
|
File file = getFileForDocId(documentId);
|
||||||
|
return getMimeType(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException {
|
||||||
|
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
|
final File parent = getFileForDocId(rootId);
|
||||||
|
|
||||||
|
// This example implementation searches file names for the query and doesn't rank search
|
||||||
|
// results, so we can stop as soon as we find a sufficient number of matches. Other
|
||||||
|
// implementations might rank results and use other data about files, rather than the file
|
||||||
|
// name, to produce a match.
|
||||||
|
final LinkedList<File> pending = new LinkedList<>();
|
||||||
|
pending.add(parent);
|
||||||
|
|
||||||
|
final int MAX_SEARCH_RESULTS = 50;
|
||||||
|
while (!pending.isEmpty() && result.getCount() < MAX_SEARCH_RESULTS) {
|
||||||
|
final File file = pending.removeFirst();
|
||||||
|
// Avoid directories outside the $HOME directory linked with symlinks (to avoid e.g. search
|
||||||
|
// through the whole SD card).
|
||||||
|
boolean isInsideHome;
|
||||||
|
try {
|
||||||
|
isInsideHome = file.getCanonicalPath().startsWith(new File(getContext().getFilesDir(), "containers").getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
isInsideHome = true;
|
||||||
|
}
|
||||||
|
if (isInsideHome) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
Collections.addAll(pending, file.listFiles());
|
||||||
|
} else {
|
||||||
|
if (file.getName().toLowerCase().contains(query)) {
|
||||||
|
includeFile(result, null, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
||||||
|
return documentId.startsWith(parentDocumentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the document id given a file. This document id must be consistent across time as other
|
||||||
|
* applications may save the ID and use it to reference documents later.
|
||||||
|
* <p/>
|
||||||
|
* The reverse of @{link #getFileForDocId}.
|
||||||
|
*/
|
||||||
|
private static String getDocIdForFile(File file) {
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file given a document id (the reverse of {@link #getDocIdForFile(File)}).
|
||||||
|
*/
|
||||||
|
private static File getFileForDocId(String docId) throws FileNotFoundException {
|
||||||
|
final File f = new File(docId);
|
||||||
|
if (!f.exists()) throw new FileNotFoundException(f.getAbsolutePath() + " not found");
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getMimeType(File file) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
return Document.MIME_TYPE_DIR;
|
||||||
|
} else {
|
||||||
|
final String name = file.getName();
|
||||||
|
final int lastDot = name.lastIndexOf('.');
|
||||||
|
if (lastDot >= 0) {
|
||||||
|
final String extension = name.substring(lastDot + 1).toLowerCase();
|
||||||
|
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||||
|
if (mime != null) return mime;
|
||||||
|
}
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a representation of a file to a cursor.
|
||||||
|
*
|
||||||
|
* @param result the cursor to modify
|
||||||
|
* @param docId the document ID representing the desired file (may be null if given file)
|
||||||
|
* @param file the File object representing the desired file (may be null if given docID)
|
||||||
|
*/
|
||||||
|
private void includeFile(MatrixCursor result, String docId, File file)
|
||||||
|
throws FileNotFoundException {
|
||||||
|
if (docId == null) {
|
||||||
|
docId = getDocIdForFile(file);
|
||||||
|
} else {
|
||||||
|
file = getFileForDocId(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = 0;
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||||
|
} else if (file.canWrite()) {
|
||||||
|
flags |= Document.FLAG_SUPPORTS_WRITE;
|
||||||
|
}
|
||||||
|
if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE;
|
||||||
|
|
||||||
|
final String displayName = file.getName();
|
||||||
|
final String mimeType = getMimeType(file);
|
||||||
|
if (mimeType.startsWith("image/")) flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
|
||||||
|
|
||||||
|
final MatrixCursor.RowBuilder row = result.newRow();
|
||||||
|
row.add(Document.COLUMN_DOCUMENT_ID, docId);
|
||||||
|
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
|
||||||
|
row.add(Document.COLUMN_SIZE, file.length());
|
||||||
|
row.add(Document.COLUMN_MIME_TYPE, mimeType);
|
||||||
|
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
||||||
|
row.add(Document.COLUMN_FLAGS, flags);
|
||||||
|
row.add(Document.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package com.example.tiny_computer
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.media.AudioFormat
|
||||||
|
import android.media.AudioRecord
|
||||||
|
import android.media.MediaRecorder
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
object AudioStream {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("native-socket")
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isStreaming = false
|
||||||
|
private var recordingThread: Thread? = null
|
||||||
|
|
||||||
|
// Native functions
|
||||||
|
private external fun nativeInit(path: String): Int
|
||||||
|
private external fun nativeAccept(): Int
|
||||||
|
private external fun nativeSend(data: ByteArray, size: Int): Int
|
||||||
|
private external fun nativeClose()
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission") // Ensure RECORD_AUDIO is granted in Manifest
|
||||||
|
fun startStreaming(path: String) {
|
||||||
|
if (isStreaming) return
|
||||||
|
isStreaming = true
|
||||||
|
|
||||||
|
recordingThread = Thread {
|
||||||
|
// 1. Initialize Socket Server
|
||||||
|
if (nativeInit(path) < 0) {
|
||||||
|
Log.e("AudioStream", "Failed to bind socket")
|
||||||
|
isStreaming = false
|
||||||
|
return@Thread
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Wait for Linux client to connect (Blocking)
|
||||||
|
Log.d("AudioStream", "Waiting for connection on $path...")
|
||||||
|
if (nativeAccept() < 0) {
|
||||||
|
Log.e("AudioStream", "Accept failed")
|
||||||
|
isStreaming = false
|
||||||
|
return@Thread
|
||||||
|
}
|
||||||
|
Log.d("AudioStream", "Client connected!")
|
||||||
|
|
||||||
|
// 3. Setup AudioRecord
|
||||||
|
val sampleRate = 44100
|
||||||
|
val bufferSize = AudioRecord.getMinBufferSize(
|
||||||
|
sampleRate,
|
||||||
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
|
AudioFormat.ENCODING_PCM_16BIT
|
||||||
|
)
|
||||||
|
|
||||||
|
val recorder = AudioRecord(
|
||||||
|
MediaRecorder.AudioSource.MIC,
|
||||||
|
sampleRate,
|
||||||
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
|
AudioFormat.ENCODING_PCM_16BIT,
|
||||||
|
bufferSize
|
||||||
|
)
|
||||||
|
|
||||||
|
val data = ByteArray(bufferSize)
|
||||||
|
recorder.startRecording()
|
||||||
|
|
||||||
|
val discardMillis = 5000 // 丢弃前5秒
|
||||||
|
val discardBytes = (sampleRate * 2 * discardMillis / 1000).toInt() // 16bit = 2字节
|
||||||
|
var bytesRead = 0
|
||||||
|
|
||||||
|
// 先读取并丢弃初始数据
|
||||||
|
while (bytesRead < discardBytes && isStreaming) {
|
||||||
|
val readBytes = recorder.read(data, 0, minOf(bufferSize, discardBytes - bytesRead))
|
||||||
|
if (readBytes > 0) {
|
||||||
|
bytesRead += readBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Streaming Loop
|
||||||
|
while (isStreaming) {
|
||||||
|
val readBytes = recorder.read(data, 0, bufferSize)
|
||||||
|
if (readBytes > 0) {
|
||||||
|
val sent = nativeSend(data, readBytes)
|
||||||
|
if (sent < 0) break // Socket broken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
recorder.stop()
|
||||||
|
recorder.release()
|
||||||
|
nativeClose()
|
||||||
|
}
|
||||||
|
recordingThread?.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopStreaming() {
|
||||||
|
isStreaming = false
|
||||||
|
nativeClose() // Unblocks the native Accept/Send if hung
|
||||||
|
recordingThread?.join()
|
||||||
|
recordingThread = null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,44 @@
|
|||||||
package com.example.tiny_computer
|
package com.example.tiny_computer
|
||||||
|
|
||||||
|
import android.system.Os.setenv
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
|
|
||||||
class MainActivity: FlutterActivity() {
|
class MainActivity: FlutterActivity() {
|
||||||
|
|
||||||
|
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||||
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "android").setMethodCallHandler {
|
||||||
|
// 注册通道并设置方法调用处理器
|
||||||
|
call, result ->
|
||||||
|
// 判断方法名
|
||||||
|
when (call.method) {
|
||||||
|
"launchSignal9Page" -> {
|
||||||
|
startActivity(Intent(this, Signal9Activity::class.java))
|
||||||
|
result.success(0)
|
||||||
|
}
|
||||||
|
"getNativeLibraryPath" -> {
|
||||||
|
result.success(getApplicationInfo().nativeLibraryDir)
|
||||||
|
}
|
||||||
|
"startStreaming" -> {
|
||||||
|
AudioStream.startStreaming(call.argument("path")!!)
|
||||||
|
}
|
||||||
|
"stopStreaming" -> {
|
||||||
|
AudioStream.stopStreaming()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// 不支持的方法名
|
||||||
|
result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.tiny_computer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
import io.flutter.app.FlutterApplication
|
||||||
|
import me.weishu.reflection.Reflection
|
||||||
|
|
||||||
|
class MainApplication : FlutterApplication() {
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
DynamicColors.applyToActivitiesIfAvailable(this@MainApplication)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context?) {
|
||||||
|
super.attachBaseContext(base)
|
||||||
|
Reflection.unseal(base)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.example.tiny_computer
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.example.tiny_computer.databinding.ActivitySignal9Binding
|
||||||
|
|
||||||
|
class Signal9Activity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var binding: ActivitySignal9Binding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivitySignal9Binding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// 设置状态栏和导航栏颜色匹配蓝屏背景
|
||||||
|
window.statusBarColor = ContextCompat.getColor(this, R.color.tc_s9a_blue_screen_blue)
|
||||||
|
window.navigationBarColor = ContextCompat.getColor(this, R.color.tc_s9a_blue_screen_blue)
|
||||||
|
|
||||||
|
setupContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupContent() {
|
||||||
|
// 设置错误信息
|
||||||
|
binding.errorDetails.text = getString(R.string.tc_s9a_error_message)
|
||||||
|
|
||||||
|
// 根据Android版本显示不同的解决方案
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
// Android 14以下版本
|
||||||
|
binding.preAndroid14Layout.isVisible = true
|
||||||
|
binding.solutionIntro.text = getString(R.string.tc_s9a_solution_intro)
|
||||||
|
binding.solutionAlternative.text = getString(R.string.tc_s9a_solution_alternative)
|
||||||
|
binding.toolButton.text = getString(R.string.tc_s9a_tool_button)
|
||||||
|
binding.tutorialButton.text = getString(R.string.tc_s9a_tutorial_button)
|
||||||
|
|
||||||
|
binding.toolButton.setOnClickListener {
|
||||||
|
openBrowserLink("https://www.vmos.cn/zhushou.htm")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tutorialButton.setOnClickListener {
|
||||||
|
openBrowserLink("https://gitee.com/caten/tc-hints/blob/master/pool/signal9fix.md")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Android 14及以上版本
|
||||||
|
binding.solutionAndroid14.isVisible = true
|
||||||
|
binding.solutionAndroid14.text = getString(R.string.tc_s9a_solution_android14)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openBrowserLink(url: String) {
|
||||||
|
if (url.isNotEmpty()) {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
// 如果URL为空,则不执行任何操作(等待后续补充链接)
|
||||||
|
}
|
||||||
|
}
|
||||||
85
android/app/src/main/res/layout/activity_signal_9.xml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/tc_s9a_blue_screen_blue"
|
||||||
|
tools:context=".Signal9Activity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/kaomoji_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/tc_s9a_kaomoji"
|
||||||
|
android:textColor="@color/tc_s9a_white"
|
||||||
|
android:textSize="96sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/error_details"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textColor="@color/tc_s9a_white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<!-- Android 14以下版本的内容 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/pre_android14_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/solution_intro"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:textColor="@color/tc_s9a_white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/tool_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:backgroundTint="@color/tc_s9a_white"
|
||||||
|
android:textColor="@color/tc_s9a_blue_screen_blue" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/solution_alternative"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:textColor="@color/tc_s9a_white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/tutorial_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:backgroundTint="@color/tc_s9a_white"
|
||||||
|
android:textColor="@color/tc_s9a_blue_screen_blue" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Android 14及以上版本的内容 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/solution_android14"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:textColor="@color/tc_s9a_white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 7.4 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 11 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 14 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 24 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 15 KiB |
12
android/app/src/main/res/values-zh-rCN/strings.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="tc_app_name">小小电脑</string>
|
||||||
|
|
||||||
|
<string name="tc_s9a_error_message">终端异常终止,返回错误码9。此错误是安卓12+系统限制子进程数量造成的,需要手动关闭限制。</string>
|
||||||
|
<string name="tc_s9a_kaomoji">:(</string>
|
||||||
|
<string name="tc_s9a_solution_intro">可以使用以下工具修复:</string>
|
||||||
|
<string name="tc_s9a_solution_alternative">如果以上工具无法修复,或者设备为鸿蒙设备,请按照以下教程解决(需要电脑和数据线):</string>
|
||||||
|
<string name="tc_s9a_tool_button">修复工具</string>
|
||||||
|
<string name="tc_s9a_tutorial_button">教程链接</string>
|
||||||
|
<string name="tc_s9a_solution_android14">请在设置应用中启用开发者选项(通常步骤是找到关于设备->系统版本->连续点击系统版本5次),然后在开发者选项中找到\"停止限制子进程\",打开开关即可。不同机型开启开发者选项的步骤可能略有不同,具体方法可在网络搜索。</string>
|
||||||
|
</resources>
|
||||||
12
android/app/src/main/res/values-zh-rTW/strings.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="tc_app_name">小小電腦</string>
|
||||||
|
|
||||||
|
<string name="tc_s9a_error_message">終端異常終止,返回錯誤碼9。此錯誤是安卓12+系統限制子進程數量造成的,需要手動關閉限制。</string>
|
||||||
|
<string name="tc_s9a_kaomoji">:(</string>
|
||||||
|
<string name="tc_s9a_solution_intro">可以使用以下工具修復:</string>
|
||||||
|
<string name="tc_s9a_solution_alternative">如果以上工具無法修復,或者設備為鴻蒙設備,請按照以下教程解決(需要電腦和數據線):</string>
|
||||||
|
<string name="tc_s9a_tool_button">修復工具</string>
|
||||||
|
<string name="tc_s9a_tutorial_button">教程鏈接</string>
|
||||||
|
<string name="tc_s9a_solution_android14">請在設置應用中啟用開發者選項(通常步驟是找到關於設備->系統版本->連續點擊系統版本5次),然後在開發者選項中找到\"停止限制子進程\",打開開關即可。不同機型開啟開發者選項的步驟可能略有不同,具體方法可在網絡搜尋。</string>
|
||||||
|
</resources>
|
||||||
5
android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="tc_s9a_blue_screen_blue">#FF6F43C0</color>
|
||||||
|
<color name="tc_s9a_white">#FFFFFFFF</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#F17FA5</color>
|
||||||
|
</resources>
|
||||||
12
android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="tc_app_name">Tiny Computer</string>
|
||||||
|
|
||||||
|
<string name="tc_s9a_error_message">Terminal terminated abnormally with signal 9. This error is caused by Android 12+ system limiting the number of child processes and requires manual removal of the restriction.</string>
|
||||||
|
<string name="tc_s9a_kaomoji">:(</string>
|
||||||
|
<string name="tc_s9a_solution_intro">You can use the following tool to fix:</string>
|
||||||
|
<string name="tc_s9a_solution_alternative">If the above tool cannot fix the issue, or if the device is a HarmonyOS device, please follow the tutorial below (requires a computer and data cable):</string>
|
||||||
|
<string name="tc_s9a_tool_button">Repair Tool</string>
|
||||||
|
<string name="tc_s9a_tutorial_button">Tutorial Link</string>
|
||||||
|
<string name="tc_s9a_solution_android14">Please enable developer options in the Settings app (usually by going to About device -> System version -> tap System version 5 times continuously), then find "Stop restricting child processes" in developer options and turn on the switch. The steps to enable Developer Options may vary slightly depending on the device model. For specific methods, you can search online.</string>
|
||||||
|
</resources>
|
||||||
@@ -1,20 +1,8 @@
|
|||||||
buildscript {
|
|
||||||
ext.kotlin_version = '1.7.10'
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||||
|
|||||||
4
android/keystore.properties.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
storePassword=your_store_password_here
|
||||||
|
keyPassword=your_key_password_here
|
||||||
|
keyAlias=upload
|
||||||
|
storeFile=../upload-keystore.jks
|
||||||
@@ -10,11 +10,18 @@ pluginManagement {
|
|||||||
|
|
||||||
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
}
|
id "com.android.application" version "8.9.1" apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rootProject.name = "TinyComputer"
|
||||||
include ":app"
|
include ":app"
|
||||||
|
|
||||||
apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
|
||||||
|
|||||||
BIN
assets/busybox
147
build.ps1
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)]
|
||||||
|
[ValidateSet("xfce", "lxqt", "gxde")]
|
||||||
|
[string[]]$DesktopEnvs,
|
||||||
|
|
||||||
|
[string]$NameSuffix
|
||||||
|
)
|
||||||
|
|
||||||
|
# 设置路径
|
||||||
|
$SourceDir = "C:\Users\29513\Downloads"
|
||||||
|
$AssetsDir = "assets"
|
||||||
|
|
||||||
|
# 分割文件函数 - 使用xaa, xab, xac...命名
|
||||||
|
function Split-File {
|
||||||
|
param(
|
||||||
|
[string]$Path,
|
||||||
|
[long]$PartSizeBytes,
|
||||||
|
[string]$DestinationPath
|
||||||
|
)
|
||||||
|
|
||||||
|
$stream = [System.IO.File]::OpenRead($Path)
|
||||||
|
$buffer = New-Object byte[] $PartSizeBytes
|
||||||
|
$partNumber = 0
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (($bytesRead = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
||||||
|
# 生成类似xaa, xab, xac...的文件名
|
||||||
|
$partName = Get-SplitFileName $partNumber
|
||||||
|
$partPath = Join-Path $DestinationPath $partName
|
||||||
|
|
||||||
|
$partStream = [System.IO.File]::OpenWrite($partPath)
|
||||||
|
try {
|
||||||
|
$partStream.Write($buffer, 0, $bytesRead)
|
||||||
|
} finally {
|
||||||
|
$partStream.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "创建分片: $partName"
|
||||||
|
$partNumber++
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$stream.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return $partNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
# 生成split风格的文件名 (xaa, xab, xac, ..., xaz)
|
||||||
|
function Get-SplitFileName {
|
||||||
|
param([int]$index)
|
||||||
|
|
||||||
|
# 计算字母偏移量(0-25对应a-z)
|
||||||
|
$charOffset = $index % 26
|
||||||
|
# 将数字转换为对应的字母字符
|
||||||
|
$char = [char]([byte][char]'a' + $charOffset)
|
||||||
|
|
||||||
|
return "xa$char"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 处理每个桌面环境
|
||||||
|
foreach ($DesktopEnv in $DesktopEnvs) {
|
||||||
|
Write-Host "`n开始处理 $DesktopEnv 桌面环境..." -ForegroundColor Green
|
||||||
|
|
||||||
|
# 设置文件路径
|
||||||
|
$TarFile = "debian-$DesktopEnv.tar.xz"
|
||||||
|
$SourcePath = Join-Path $SourceDir $TarFile
|
||||||
|
|
||||||
|
# 检查源文件是否存在
|
||||||
|
if (-not (Test-Path $SourcePath)) {
|
||||||
|
Write-Error "错误:找不到文件 $SourcePath"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# 删除assets文件夹中已有的xa*文件
|
||||||
|
if (Test-Path $AssetsDir) {
|
||||||
|
Write-Host "正在清理assets文件夹中的旧文件..."
|
||||||
|
Get-ChildItem -Path $AssetsDir -Filter "xa*" | Remove-Item -Force
|
||||||
|
} else {
|
||||||
|
Write-Host "创建assets文件夹..."
|
||||||
|
New-Item -ItemType Directory -Path $AssetsDir | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# 分割文件 (98MB = 98 * 1024 * 1024 = 102760448 bytes)
|
||||||
|
Write-Host "正在分割 $TarFile 文件..."
|
||||||
|
$partCount = Split-File -Path $SourcePath -PartSizeBytes 102760448 -DestinationPath $AssetsDir
|
||||||
|
|
||||||
|
Write-Host "文件分割完成,共创建 $partCount 个分片文件"
|
||||||
|
|
||||||
|
# 运行Flutter构建
|
||||||
|
Write-Host "正在运行Flutter构建..."
|
||||||
|
flutter build apk --target-platform android-arm64 --split-per-abi --obfuscate --split-debug-info=tiny_computer/sdi
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "错误:Flutter构建失败"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建APK文件名
|
||||||
|
$ApkBaseName = "tiny-computer-$DesktopEnv"
|
||||||
|
if (-not [string]::IsNullOrEmpty($NameSuffix)) {
|
||||||
|
$ApkBaseName += "-$NameSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 重命名APK和SHA1文件
|
||||||
|
$ApkSource = "build\app\outputs\flutter-apk\app-arm64-v8a-release.apk"
|
||||||
|
$Sha1Source = "build\app\outputs\flutter-apk\app-arm64-v8a-release.apk.sha1"
|
||||||
|
|
||||||
|
if (Test-Path $ApkSource) {
|
||||||
|
Rename-Item -Path $ApkSource -NewName "$ApkBaseName.apk"
|
||||||
|
Write-Host "已重命名APK文件: $ApkBaseName.apk"
|
||||||
|
} else {
|
||||||
|
Write-Error "错误:找不到APK文件 $ApkSource"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $Sha1Source) {
|
||||||
|
Rename-Item -Path $Sha1Source -NewName "$ApkBaseName.apk.sha1"
|
||||||
|
Write-Host "已重命名SHA1文件: $ApkBaseName.apk.sha1"
|
||||||
|
} else {
|
||||||
|
Write-Warning "警告:找不到SHA1文件 $Sha1Source"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "$DesktopEnv 处理完成!" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n所有桌面环境处理完成!" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# 既然是开源,我认为应该把prompt开源出来才算,毕竟这个脚本更像编译后的产物,而不是源代码本身。
|
||||||
|
|
||||||
|
# 帮我写一个自动化脚本,做以下几件事:
|
||||||
|
# 1. 脚本所在目录是项目的根目录,脚本应该运行在windows电脑上,接收一个参数,这个参数的值会是xfce, lxqt或gxde。
|
||||||
|
# 2. 在C:\Users\29513\Downloads文件夹有debian-xfce.tar.xz,debian-lxqt.tar.xz和debian-gxde.tar.xz,需要根据之前的参数对应选择,然后分成98MB的小份,命名为xa*(就像linux上的split -b 98M debian.tar.xz),放到项目的assets文件夹。注意这个文件夹可能有之前残留的xa*文件,需要先彻底删除这些xa*文件。
|
||||||
|
# 3. 然后在当前目录运行flutter build apk --target-platform android-arm64 --split-per-abi --obfuscate --split-debug-info=tiny_computer/sdi编译。
|
||||||
|
# 4. 在build\app\outputs\flutter-apk文件夹会有app-arm64-v8a-release.apk和app-arm64-v8a-release.apk.sha1两个文件,需要重命名为tiny-computer-xfce.apk和tiny-computer-xfce.apk.sha1(以xfce为例,具体名称根据参数来定)
|
||||||
|
|
||||||
|
# 直接写成一个ps1脚本行吗
|
||||||
|
|
||||||
|
# 请再添加一些功能:首先可以传入多个选项,比如传入xfce lxqt就可以自动进行这两个构建;其实需要一个新参数允许在生成的apk名字加入后缀,比如添加targetSdk35后缀,就会生成tiny-computer-xfce-targetSdk35.apk和tiny-computer-xfce-targetSdk35.apk.sha1
|
||||||
|
|
||||||
|
# xa*文件的命名不对。要按照split命令默认的那样,命名为xaa,xab,xac... 另外我确定分割后的文件数量不多,不会超过xaz。
|
||||||
|
|
||||||
|
# Cannot convert value "97" to type "System.Char". Error: "Invalid cast from 'Decimal' to 'Char'."
|
||||||
|
# At C:\Users\29513\FlutterProjects\tiny_computer\build.ps1:52 char:5
|
||||||
|
# + $firstChar = [char](97 + [math]::Floor($index / 26)) # a-z
|
||||||
|
# + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# + CategoryInfo : InvalidArgument: (:) [], RuntimeException
|
||||||
|
# + FullyQualifiedErrorId : InvalidCastIConvertible
|
||||||
285
extra/build-tiny-rootfs.md
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
# build-tiny-rootfs
|
||||||
|
对小小电脑项目rootfs制作的说明
|
||||||
|
|
||||||
|
### 为什么不直接制作一个脚本呢?
|
||||||
|
|
||||||
|
因为我不会,所以只能用自然语言记录一下制作步骤。
|
||||||
|
|
||||||
|
## 制作步骤(xfce和lxqt)
|
||||||
|
|
||||||
|
### 安装Debian容器
|
||||||
|
|
||||||
|
- 安装Termux
|
||||||
|
- 在Termux内安装tmoe
|
||||||
|
- 在tmoe内安装Debian Bookworm的proot容器
|
||||||
|
- 是否新建sudo用户-是-用户名tiny-密码tiny
|
||||||
|
- 是否设置tiny为默认用户-是
|
||||||
|
- 是否为root配置zsh-否
|
||||||
|
- 是否删除zsh.sh等-是
|
||||||
|
- 是否启动tmoe tools-是
|
||||||
|
- 其余对话框默认直接按回车
|
||||||
|
- 来到tmoe tool界面时取消,退出
|
||||||
|
|
||||||
|
### 安装其他软件
|
||||||
|
|
||||||
|
安装xfce部分是根据记忆写的,如果有误请指出。
|
||||||
|
|
||||||
|
桌面环境只安装一个。
|
||||||
|
|
||||||
|
#### 安装桌面环境(lxqt)
|
||||||
|
|
||||||
|
- 输入debian-i进入tmoe tools
|
||||||
|
- 图形界面-rootless-lxqt-core
|
||||||
|
- 不安装electron apps
|
||||||
|
- 不安装chromium
|
||||||
|
|
||||||
|
- 按需调整
|
||||||
|
|
||||||
|
#### 安装桌面环境(xfce)
|
||||||
|
|
||||||
|
前面的部分和lxqt一致,只是选桌面环境时选了xfce-lite。
|
||||||
|
|
||||||
|
下面是额外的美化部分。推荐先安装软件再做这个,因为使用kali-undercover时可能有依赖报错,但我忘记是哪些依赖了。但后面安装的某个软件会帮我们把依赖补上。
|
||||||
|
|
||||||
|
- xfce美化
|
||||||
|
- 前往kali源下载kali-undercover包并apt install安装
|
||||||
|
- 修改kali-undercover脚本中检测xfce环境的地方,强制允许
|
||||||
|
- 即注释第一个if里的exit 1
|
||||||
|
- 执行kali-undercover
|
||||||
|
- 按需调整
|
||||||
|
- 注释.bashrc中把bash风格改为windows风格的语句
|
||||||
|
- 调整状态栏
|
||||||
|
- ......
|
||||||
|
|
||||||
|
#### 安装VNC
|
||||||
|
|
||||||
|
安装桌面环境后会自动进行这一步,使用tmoe tools全部安装即可。
|
||||||
|
|
||||||
|
- 选择tigervnc
|
||||||
|
- 密码12345678
|
||||||
|
|
||||||
|
安装完成后,输入debian-i回到tmoe继续修改一些参数,主要目的是避免与termux的容器端口一致产生冲突
|
||||||
|
|
||||||
|
- 修改显示端口到5904
|
||||||
|
- 远程桌面-tigervnc-显示端口-4
|
||||||
|
- 修改novnc端口到36082
|
||||||
|
- 远程桌面-novnc-端口-36082
|
||||||
|
- 修改startnovnc启动脚本(避免每次启动novnc时打开浏览器,虽然不是windows)
|
||||||
|
- 注释start_win10_edge_novnc_addr(大概在倒数第五行)
|
||||||
|
|
||||||
|
接下来对novnc应用补丁,以添加"通过滑块修改分辨率"等功能
|
||||||
|
|
||||||
|
- [下载novnc.patch](https://github.com/Cateners/noVNC/releases/tag/1.2)
|
||||||
|
- 切换目录到/usr/local/etc/tmoe-linux/novnc
|
||||||
|
- `patch -p1 < novnc.patch`
|
||||||
|
- ```bash
|
||||||
|
find . '(' \
|
||||||
|
-name \*-baseline -o \
|
||||||
|
-name \*-merge -o \
|
||||||
|
-name \*-original -o \
|
||||||
|
-name \*.orig -o \
|
||||||
|
-name \*.rej \
|
||||||
|
')' -delete
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 修复tmoe不能下载软件
|
||||||
|
|
||||||
|
在我发布的xfce版本中,我给每个aria2c调用都添加了--async-dns=false参数。
|
||||||
|
|
||||||
|
先切换到tmoe目录`/usr/local/etc/tmoe-linux/git/share`,然后执行脚本`./replace.sh old-version`:
|
||||||
|
```shell
|
||||||
|
#!/bin/bash
|
||||||
|
# 用法: ./replace.sh 目录
|
||||||
|
# 该脚本会递归地在给定目录下的所有文件中替换文本
|
||||||
|
# 原文本: aria2c --console-log-level
|
||||||
|
# 新文本: aria2c --async-dns=false --console-log-level
|
||||||
|
|
||||||
|
# 检查参数是否正确
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "错误: 需要一个目录作为参数"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查目录是否存在
|
||||||
|
if [ ! -d "$1" ]; then
|
||||||
|
echo "错误: 目录 $1 不存在"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 遍历目录下的所有文件
|
||||||
|
find "$1" -type f | while read file; do
|
||||||
|
# 使用sed命令替换文本
|
||||||
|
sed -i 's/aria2c --console-log-level/aria2c --async-dns=false --console-log-level/g' "$file"
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
用完后删除replace.sh;
|
||||||
|
|
||||||
|
另外现在tmoe官方给出了[解决办法](https://gitee.com/mo2/linux/issues/I8BQG3),不过我测试似乎还是不行,所以就先这样了
|
||||||
|
|
||||||
|
#### 修改apt源
|
||||||
|
|
||||||
|
按需修改/etc/apt/sources.list,另外把non-free改为non-free-firmware
|
||||||
|
|
||||||
|
#### 安装火狐浏览器
|
||||||
|
|
||||||
|
`sudo apt install firefox-esr firefox-esr-l10n-zh-cn`
|
||||||
|
|
||||||
|
#### 安装输入法
|
||||||
|
|
||||||
|
- debian-i
|
||||||
|
- 03秘密花园-10输入法-fcitx4-安装4libpinyin和6云拼音模块
|
||||||
|
- 在图形界面应用找到fcitx配置-附加组件-云拼音-配置-云拼音来源,把Google改为百度,确认
|
||||||
|
- 启动图形界面:输入startnovnc,会出现一个类似xxx.xxx.xxx.xxx:36082/vnc.html的网址,复制到本机的浏览器中输入vnc密码12345678就可以访问了。
|
||||||
|
|
||||||
|
#### 安装gdebi
|
||||||
|
|
||||||
|
这个软件包能使用户通过图形界面安装deb安装包
|
||||||
|
|
||||||
|
安装:`sudo apt install gdebi`
|
||||||
|
|
||||||
|
修改启动器:在/usr/share/applications/gdebi.desktop的Exec=后加上sudo
|
||||||
|
|
||||||
|
#### 安装VSCode
|
||||||
|
|
||||||
|
VSCode使用tmoe安装,正好测试一下不能下载软件的问题是否存在
|
||||||
|
|
||||||
|
- 2软件-2开发-1VSCode-1Official
|
||||||
|
|
||||||
|
tmoe还会安装gnome-keyring,由于之前我做xfce包时会造成VSCode反复弹窗更新密钥环所以被我卸载了,这个按需决定是否保留吧
|
||||||
|
|
||||||
|
#### 安装ffmpeg
|
||||||
|
|
||||||
|
这个是为了预览推流用的,按需安装
|
||||||
|
|
||||||
|
`sudo apt install ffmpeg`
|
||||||
|
|
||||||
|
### 其他修补
|
||||||
|
|
||||||
|
#### cmatrix
|
||||||
|
|
||||||
|
这个是给快捷指令的彩蛋。下载cmatrix的包,并将cmatrix文件提取放到/home/tiny/.local/bin里即可,记得添加执行权限
|
||||||
|
|
||||||
|
#### WPS
|
||||||
|
|
||||||
|
**(20241112)注意,新版wps不再需要将整合模式改为多组件模式也能正常使用,所以可以跳过软件设置修改的步骤**
|
||||||
|
|
||||||
|
- 软件设置修改
|
||||||
|
- 从官网下载WPS linux arm64 deb安装包,直接在图形界面点开用gdebi安装(正好测试一下gdebi是否能用)
|
||||||
|
- 打开WPS-右上角设置-其他-切换窗口管理模式-整合模式改为多组件模式(否则一些设备在新建文档等操作时卡死,目前原因不明)
|
||||||
|
- 使用gdebi(或自行)卸载WPS
|
||||||
|
- libtiff.so.5库修补
|
||||||
|
- 切换到/lib/aarch64-linux-gnu文件夹,创建软链把libtiff.so.6链接到libtiff.so.5
|
||||||
|
- 或者找libtiff.so.5的包并安装,这样可能更好一些
|
||||||
|
- 预装ttf-mscorefonts-installer
|
||||||
|
- 这个包是WPS的依赖,会在sourceforge下载字体,可能会非常慢,所以提前apt装好
|
||||||
|
|
||||||
|
|
||||||
|
### 额外步骤
|
||||||
|
|
||||||
|
- 升级到Debian 13(xfce, lxqt,v1.1.0):
|
||||||
|
- 更换内存分配器([原因](https://github.com/termux/proot/issues/313)。不过截至目前这个bug可能已经被修了,虽然issue没关)安装libtcmalloc-minimal4包,并设置库/usr/lib/aarch64-linux-gnu/libtcmalloc_minimal.so.4到/etc/ld.so.preload
|
||||||
|
- 把/etc/apt/source.list的bookworm改为trixie
|
||||||
|
- sudo apt update, sudo apt full-upgrade, sudo apt autoremove
|
||||||
|
- 取消内存分配器的更改
|
||||||
|
- xfce版本重新修补了libtiff.so.5库
|
||||||
|
- 升级到GXDE 25:
|
||||||
|
- 更换内存分配器
|
||||||
|
- 使用AI重写的升级脚本(gxde-25-upgrade.sh),以便在不启动图形界面的情况下升级
|
||||||
|
- 禁用MIT-SHM扩展(v1.1.0):/usr/local/bin/startvnc第372行添加set "${a}" "-extension" "MIT-SHM"
|
||||||
|
- 将桌面壁纸的配置从monitorBuiltinDisplay改为monitorbuiltin(xfce,v1.0.99),疑似Termux:X11显示器名称改变导致壁纸失效
|
||||||
|
- 修复用vscode打开文件时只打开了vscode本身(v1.0.25):去掉/usr/share/applications/code-no-sandbox.desktop的Exec的--unity-launch
|
||||||
|
- 修复选择文本时会把文本发送到剪切板(v1.0.25):在/usr/local/bin/startvnc文件的start_tmoe_xvnc()的start_win10_tigervnc行前面加入`vncconfig -set SendPrimary=0 SetPrimary=0`
|
||||||
|
- 修复系统更新时变英文(v1.0.19):把/etc/locale.gen文件里包含zh_CN.UTF-8的那行代码解除注释
|
||||||
|
- 修复了xfce使用Termux:X11时占用过高(v1.0.19):把底部面板的电量管理插件移除(右键-面板-面板首选项-项目)
|
||||||
|
- 不弹出终端窗口(v1.0.18):把/etc/X11/xinit/Xsession文件倒数第二行open_terminal删掉
|
||||||
|
- 关闭垂直同步以使用Turnip+Zink(v1.0.17):把文件~/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml内vblank_mode值从auto改为off
|
||||||
|
- xfce版本安装了图片查看器ristretto和压缩文件管理器xarchiver(v1.0.16)
|
||||||
|
|
||||||
|
### 打包
|
||||||
|
|
||||||
|
- 首先退出容器,在容器挂载选项里取消对sd和termux的挂载,之后进入容器删除termux软连接
|
||||||
|
- 在后面使用tar打包时,即使指定了exclude,tar也会尝试把它们打包进去
|
||||||
|
- 这个很可能因为我自己没用对参数,如果你非常自信的话就不需要这么做,自行打包即可=v=
|
||||||
|
- 在[这里](https://github.com/meefik/busybox/releases)下载提取busybox的可执行文件,并放到系统根目录
|
||||||
|
- 我使用busybox的tar来打包,而不是容器自带的tar,原因是容器自带的tar会把硬链接打包成单独的文件,导致打包解包后占用多出1GB
|
||||||
|
- 这个也很可能是我自己没用对参数,如果你非常自信就不用这么做......
|
||||||
|
- 尽可能多地删除使用痕迹,包括但不限于
|
||||||
|
- apt clean
|
||||||
|
- /tmp下的文件,退出容器后删
|
||||||
|
- tiny和root目录下的
|
||||||
|
- .cache
|
||||||
|
- .vnc/vnc.log, .vnc/x.log
|
||||||
|
- .bash_history
|
||||||
|
- .ICEauthority
|
||||||
|
- .Xauthority
|
||||||
|
- 等等
|
||||||
|
- 切换到root用户,切换到根目录,`/busybox tar -Jcpvf /debian.tar.xz --exclude=".l2s.*" bin boot etc home lib media mnt opt root run sbin sd srv tmp usr var`
|
||||||
|
|
||||||
|
|
||||||
|
## 制作步骤(GXDE OS)
|
||||||
|
|
||||||
|
### 咕咕咕
|
||||||
|
|
||||||
|
其实流程和前面差不多。基本上就是 装图形界面->修复中文->修复tmoe->修non-free-firmware->(随便看看空间占用,略)->修wps->准备busybox以便打包->添加Xsession文件以便启动
|
||||||
|
|
||||||
|
请看VCR:
|
||||||
|
```
|
||||||
|
1 exit
|
||||||
|
2 sudo apt install sd/Download/gxde-source_1.0.1_all.deb
|
||||||
|
3 sudo apt install ./sd/Download/gxde-source_1.0.1_all.deb
|
||||||
|
4 sudo apt update
|
||||||
|
5 sudo apt install gxde-testing-source
|
||||||
|
6 sudo apt update
|
||||||
|
7 sudo apt install gxde-desktop-android --no-install-recommends
|
||||||
|
8 sudo apt install spark-store gxde-terminal
|
||||||
|
9 nano /etc/locale.gen
|
||||||
|
10 cd /usr/local/etc/tmoe-linux/git/share
|
||||||
|
11 nano replace.sh
|
||||||
|
12 ./replace.sh old-version
|
||||||
|
13 chmod +x replace.sh
|
||||||
|
14 ./replace.sh old-version
|
||||||
|
15 rm replace.sh
|
||||||
|
16 cd
|
||||||
|
17 tmoe
|
||||||
|
18 nano /etc/apt/sources.list
|
||||||
|
19 sudo apt update
|
||||||
|
20 nano /etc/apt/sources.list
|
||||||
|
21 sudo apt update
|
||||||
|
22 cd /var/log
|
||||||
|
23 ls -l
|
||||||
|
24 du -h --max-depth=1 | sort -h
|
||||||
|
25 cd ..
|
||||||
|
26 du -h --max-depth=1 | sort -h
|
||||||
|
27 cd cache/
|
||||||
|
28 ls -l
|
||||||
|
29 sudo apt update ttf-mscorefonts-installer
|
||||||
|
30 sudo apt install ttf-mscorefonts-installer
|
||||||
|
31 cd /usr/lib/aarch64-linux-gnu/
|
||||||
|
32 ln -s libtiff.so.6 libtiff.so.5
|
||||||
|
33 history
|
||||||
|
34 cd /
|
||||||
|
35 cp home/tiny/termux/home/.local/share/tmoe-linux/containers/proot/debian-bookworm_arm64/busybox .
|
||||||
|
36 cd /etc/X11/xinit/
|
||||||
|
37 ls
|
||||||
|
38 cp ~/termux/home/.local/share/tmoe-linux/containers/proot/debian-bookworm_arm64/etc/X11/xinit/Xsession .
|
||||||
|
39 ls -l Xsession
|
||||||
|
40 cd /
|
||||||
|
41 ls -l busybox
|
||||||
|
42 exit
|
||||||
|
43 sudo apt clean;sudo apt autoclean;sudo apt autoremove --purge || sudo apt autoremove
|
||||||
|
44 history
|
||||||
|
45 history > /sd/history.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
关于Xsession文件:
|
||||||
|
|
||||||
|
因为当前小小电脑代码写死了启动X11图形界面就通过执行/etc/X11/xinit/Xsession,如果通过tmoe安装图形界面这个文件是自带的,但安装GXDE没有通过tmoe,所以随便写了个:
|
||||||
|
```
|
||||||
|
rm -rf /run/dbus/pid
|
||||||
|
sudo dbus-daemon --system
|
||||||
|
export $(dbus-launch)
|
||||||
|
startgxde_android
|
||||||
|
```
|
||||||
247
extra/cross/chn_fonts.reg
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
REGEDIT4
|
||||||
|
|
||||||
|
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink]
|
||||||
|
"Agency FB"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Alef"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Algerian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Amiri Quran"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Amiri"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Arial Rounded MT Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Arial"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bahnschrift"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Baskerville Old Face"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bauhaus 93"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bell MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Berlin Sans FB Demi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Berlin Sans FB"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bernard MT Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Blackadder ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bodoni MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Book Antiqua"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bookman Old Style"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bookshelf Symbol 7"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Bradley Hand ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Britannic Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Broadway"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Brush Script MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Caladea"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Calibri"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Californian FB"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Calisto MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Cambria"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Candara"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Carlito"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Cascadia Code"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Cascadia Mono"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Castellar"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Centaur"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Century Gothic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Century Schoolbook"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Century"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Chiller"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Colonna MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Comic Sans MS"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Consolas"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Constantia"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Cooper Black"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Copperplate Gothic Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Copperplate Gothic Light"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Corbel"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Courier New"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Curlz MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"David CLM"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"David Libre"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"DejaVu Math TeX Gyre"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"DejaVu Sans Mono"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"DejaVu Sans"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"DejaVu Serif"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"DengXian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Dubai"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Ebrima"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Edwardian Script ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Elephant"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Engravers MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Eras Bold ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Eras Demi ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Eras Light ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Eras Medium ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"FZShuTi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"FZYaoTi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"FangSong"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Felix Titling"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Footlight MT Light"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Forte"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Frank Ruehl CLM"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Frank Ruhl Hofshi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Book"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Demi Cond"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Demi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Heavy"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Medium Cond"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Franklin Gothic Medium"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Freestyle Script"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"French Script MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gabriola"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gadugi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Garamond"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gentium Basic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gentium Book Basic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Georgia"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gigi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gill Sans MT Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gill Sans MT Ext Condensed Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gill Sans MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gill Sans Ultra Bold Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gill Sans Ultra Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Gloucester MT Extra Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Goudy Old Style"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Goudy Stout"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Haettenschweiler"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Harlow Solid Italic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Harrington"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"High Tower Text"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"HoloLens MDL2 Assets"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Impact"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Imprint MT Shadow"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Informal Roman"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Ink Free"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Javanese Text"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Jokerman"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Juice ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"KaiTi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Kristen ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Kunstler Script"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Leelawadee UI"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Leelawadee"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"LiSu"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Liberation Mono"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Liberation Sans Narrow"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Liberation Sans"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Liberation Serif"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Linux Biolinum G"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Linux Libertine Display G"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Linux Libertine G"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Bright"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Calligraphy"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Console"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Fax"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Handwriting"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Sans Typewriter"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Sans Unicode"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Lucida Sans"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MS Gothic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MS Outlook"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MS Reference Sans Serif"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MS Reference Specialty"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MT Extra"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MV Boli"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Magneto"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Maiandra GD"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Malgun Gothic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Marlett"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Matura MT Script Capitals"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft Himalaya"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft JhengHei"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft New Tai Lue"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft PhagsPa"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft Sans Serif"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft Tai Le"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft Uighur"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft YaHei"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Microsoft Yi Baiti"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"MingLiU-ExtB"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Miriam CLM"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Miriam Libre"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Miriam Mono CLM"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Mistral"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Modern No. 20"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Mongolian Baiti"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Monotype Corsiva"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Myanmar Text"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Nachlieli CLM"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Niagara Engraved"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Niagara Solid"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Nirmala UI"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Kufi Arabic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Naskh Arabic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Arabic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Armenian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Georgian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Hebrew"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Lao"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans Lisu"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Sans"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Serif Armenian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Serif Georgian"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Serif Hebrew"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Serif Lao"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Noto Serif"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"OCR A Extended"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Old English Text MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Onyx"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"OpenSymbol"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Palace Script MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Palatino Linotype"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Papyrus"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Parchment"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Perpetua Titling MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Perpetua"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Playbill"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Poor Richard"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Pristina"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Rage Italic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Ravie"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Reem Kufi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Rockwell Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Rockwell Extra Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Rockwell"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Rubik"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STCaiyun"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STFangsong"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STHupo"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STKaiti"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STLiti"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STSong"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STXihei"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STXingkai"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STXinwei"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"STZhongsong"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Sans Serif Collection"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Scheherazade"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Script MT Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe Fluent Icons"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe MDL2 Assets"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe Print"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe Script"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe UI Emoji"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe UI Historic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe UI Symbol"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe UI Variable"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Segoe UI"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Showcard Gothic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"SimHei"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"SimSun"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"SimSun-ExtB"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Sitka"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Snap ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Stencil"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Sylfaen"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Symbol"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Tahoma"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Tempus Sans ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Times New Roman"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Trebuchet MS"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Tw Cen MT Condensed Extra Bold"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Tw Cen MT Condensed"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Tw Cen MT"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Verdana"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Viner Hand ITC"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Vivaldi"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Vladimir Script"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Webdings"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Wide Latin"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Wingdings 2"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Wingdings 3"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Wingdings"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"YouYuan"="XiaolaiMonoSC-Regular.ttf"
|
||||||
|
"Yu Gothic"="XiaolaiMonoSC-Regular.ttf"
|
||||||
76
extra/cross/install-hangover
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "正在更新软件包..."
|
||||||
|
sudo apt update
|
||||||
|
sudo apt upgrade -y
|
||||||
|
|
||||||
|
|
||||||
|
REPO="AndreRH/hangover"
|
||||||
|
API_URL="https://api.github.com/repos/$REPO/releases/latest"
|
||||||
|
|
||||||
|
# 获取最新release的版本号并储存在变量中
|
||||||
|
latest_version=$(wget -qO- $API_URL | grep -oP '"tag_name": "\Khangover-\K([^"]+)' )
|
||||||
|
|
||||||
|
# 检查是否成功获取版本号
|
||||||
|
if [ -z "$latest_version" ]; then
|
||||||
|
echo "无法获取到最新版本号。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "最新版本: $latest_version"
|
||||||
|
|
||||||
|
hangover_url="https://github.com/AndreRH/hangover/releases/download/hangover-${latest_version}/hangover_${latest_version}_debian13_trixie_arm64.tar"
|
||||||
|
|
||||||
|
mirror_sites=(
|
||||||
|
"https://gh-proxy.org/"
|
||||||
|
"https://cdn.gh-proxy.org/"
|
||||||
|
"https://edgeone.gh-proxy.org/"
|
||||||
|
"https://gh.llkk.cc/"
|
||||||
|
"https://github.moeyy.xyz/"
|
||||||
|
"https://mirror.ghproxy.com/"
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p /tmp/hangover
|
||||||
|
cd /tmp/hangover
|
||||||
|
|
||||||
|
for mirror in "${mirror_sites[@]}"; do
|
||||||
|
url="${mirror}${hangover_url}"
|
||||||
|
echo "尝试从 $url 下载Hangover..."
|
||||||
|
wget "${url}" -O hangover.tar
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "成功下载Hangover"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ -z "$mirror" ]; then
|
||||||
|
cd /tmp
|
||||||
|
rm -rf /tmp/hangover
|
||||||
|
echo "下载失败...退出安装..."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "正在安装Hangover..."
|
||||||
|
tar xvf hangover.tar
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt install -y ./hangover*.deb
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
cd /tmp
|
||||||
|
rm -rf /tmp/hangover
|
||||||
|
echo "安装失败...退出安装..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "正在初始化Wine..."
|
||||||
|
wineboot --init
|
||||||
|
|
||||||
|
echo "正在安装DXVK..."
|
||||||
|
tar xvf dxvk-v*.tar.gz
|
||||||
|
mv dxvk-v*/x32/* /home/tiny/.wine/drive_c/windows/syswow64
|
||||||
|
mv dxvk-v*/arm64ec/* /home/tiny/.wine/drive_c/windows/system32
|
||||||
|
|
||||||
|
echo "正在修复字体..."
|
||||||
|
regedit "Z:\\home\\tiny\\.local\\share\\tiny\\extra\\chn_fonts.reg" && wine reg delete "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes" /va /f
|
||||||
|
|
||||||
|
cd /tmp
|
||||||
|
rm -rf /tmp/hangover
|
||||||
|
echo "安装完成"
|
||||||
60
extra/cross/install-hangover-stable
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "正在更新软件包..."
|
||||||
|
sudo apt update
|
||||||
|
sudo apt upgrade -y
|
||||||
|
|
||||||
|
hangover_url="https://github.com/AndreRH/hangover/releases/download/hangover-11.0/hangover_11.0_debian13_trixie_arm64.tar"
|
||||||
|
latest_version="11.0"
|
||||||
|
|
||||||
|
mirror_sites=(
|
||||||
|
"https://gh-proxy.org/"
|
||||||
|
"https://cdn.gh-proxy.org/"
|
||||||
|
"https://edgeone.gh-proxy.org/"
|
||||||
|
"https://gh.llkk.cc/"
|
||||||
|
"https://github.moeyy.xyz/"
|
||||||
|
"https://mirror.ghproxy.com/"
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p /tmp/hangover
|
||||||
|
cd /tmp/hangover
|
||||||
|
|
||||||
|
for mirror in "${mirror_sites[@]}"; do
|
||||||
|
url="${mirror}${hangover_url}"
|
||||||
|
echo "尝试从 $url 下载Hangover..."
|
||||||
|
wget "${url}" -O hangover.tar
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "成功下载Hangover"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ -z "$mirror" ]; then
|
||||||
|
cd /tmp
|
||||||
|
rm -rf /tmp/hangover
|
||||||
|
echo "下载失败...退出安装..."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "正在安装Hangover..."
|
||||||
|
tar xvf hangover.tar
|
||||||
|
sudo DEBIAN_FRONTEND=noninteractive apt install -y ./hangover*.deb
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
cd /tmp
|
||||||
|
rm -rf /tmp/hangover
|
||||||
|
echo "安装失败...退出安装..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "正在初始化Wine..."
|
||||||
|
wineboot --init
|
||||||
|
|
||||||
|
echo "正在安装DXVK..."
|
||||||
|
tar xvf dxvk-v*.tar.gz
|
||||||
|
mv dxvk-v*/x32/* /home/tiny/.wine/drive_c/windows/syswow64
|
||||||
|
mv dxvk-v*/arm64ec/* /home/tiny/.wine/drive_c/windows/system32
|
||||||
|
|
||||||
|
echo "正在修复字体..."
|
||||||
|
regedit "Z:\\home\\tiny\\.local\\share\\tiny\\extra\\chn_fonts.reg" && wine reg delete "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes" /va /f
|
||||||
|
|
||||||
|
echo "安装完成"
|
||||||
243
extra/getifaddrs_bridge/getifaddrs_bridge_client_lib.c
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
// getifaddrs_bridge_client_lib.c -- This file is part of tiny_computer.
|
||||||
|
|
||||||
|
// Copyright (C) 2023 Caten Hu
|
||||||
|
|
||||||
|
// Tiny Computer is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License,
|
||||||
|
// or any later version.
|
||||||
|
|
||||||
|
// Tiny Computer is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
/* this file is mainly generated by Bing */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#define BUFSIZE 1024 // 定义缓冲区大小
|
||||||
|
|
||||||
|
// 定义一个反序列化函数,将字节数组转换为ifaddrs结构体
|
||||||
|
int TINY_deserialize_ifaddrs(char *buf, int size, struct ifaddrs **ifap) {
|
||||||
|
int len = 0; // 记录已经读取的字节数
|
||||||
|
struct ifaddrs *head = NULL; // 链表头指针
|
||||||
|
struct ifaddrs *tail = NULL; // 链表尾指针
|
||||||
|
while (len < size) {
|
||||||
|
// 为当前接口分配内存
|
||||||
|
struct ifaddrs *ifa = (struct ifaddrs *)malloc(sizeof(struct ifaddrs));
|
||||||
|
if (ifa == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
// 读取接口名称
|
||||||
|
int namelen = strlen(buf + len) + 1; // 包括结束符
|
||||||
|
if (len + namelen > size) break; // 缓冲区不足
|
||||||
|
ifa->ifa_name = (char *)malloc(namelen); // 为名称分配内存
|
||||||
|
if (ifa->ifa_name == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
free(ifa);
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
memcpy(ifa->ifa_name, buf + len, namelen); // 复制名称
|
||||||
|
len += namelen;
|
||||||
|
// 读取接口标志
|
||||||
|
if (len + sizeof(unsigned int) > size) break; // 缓冲区不足
|
||||||
|
memcpy(&ifa->ifa_flags, buf + len, sizeof(unsigned int)); // 复制标志
|
||||||
|
len += sizeof(unsigned int);
|
||||||
|
// 读取接口地址
|
||||||
|
if (buf[len] != '\0') {
|
||||||
|
// 如果有地址
|
||||||
|
int addrlen = sizeof(struct sockaddr); // 地址结构体长度
|
||||||
|
if (len + addrlen > size) break; // 缓冲区不足
|
||||||
|
ifa->ifa_addr = (struct sockaddr *)malloc(addrlen); // 为地址分配内存
|
||||||
|
if (ifa->ifa_addr == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
free(ifa->ifa_name);
|
||||||
|
free(ifa);
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
memcpy(ifa->ifa_addr, buf + len, addrlen); // 复制地址
|
||||||
|
len += addrlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有地址,跳过一个空字节
|
||||||
|
ifa->ifa_addr = NULL;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 读取接口掩码
|
||||||
|
if (buf[len] != '\0') {
|
||||||
|
// 如果有掩码
|
||||||
|
int masklen = sizeof(struct sockaddr); // 掩码结构体长度
|
||||||
|
if (len + masklen > size) break; // 缓冲区不足
|
||||||
|
ifa->ifa_netmask = (struct sockaddr *)malloc(masklen); // 为掩码分配内存
|
||||||
|
if (ifa->ifa_netmask == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
free(ifa->ifa_addr);
|
||||||
|
free(ifa->ifa_name);
|
||||||
|
free(ifa);
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
memcpy(ifa->ifa_netmask, buf + len, masklen); // 复制
|
||||||
|
len += masklen;
|
||||||
|
} else {
|
||||||
|
// 如果没有掩码,跳过一个空字节
|
||||||
|
ifa->ifa_netmask = NULL;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 读取接口广播地址或点对点地址
|
||||||
|
if (ifa->ifa_flags & IFF_BROADCAST) {
|
||||||
|
// 如果有广播地址
|
||||||
|
if (buf[len] != '\0') {
|
||||||
|
// 如果有广播地址
|
||||||
|
int broadlen = sizeof(struct sockaddr); // 广播地址结构体长度
|
||||||
|
if (len + broadlen > size) break; // 缓冲区不足
|
||||||
|
ifa->ifa_broadaddr = (struct sockaddr *)malloc(broadlen); // 为广播地址分配内存
|
||||||
|
if (ifa->ifa_broadaddr == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
free(ifa->ifa_netmask);
|
||||||
|
free(ifa->ifa_addr);
|
||||||
|
free(ifa->ifa_name);
|
||||||
|
free(ifa);
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
memcpy(ifa->ifa_broadaddr, buf + len, broadlen); // 复制广播地址
|
||||||
|
len += broadlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有广播地址,跳过一个空字节
|
||||||
|
ifa->ifa_broadaddr = NULL;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
} else if (ifa->ifa_flags & IFF_POINTOPOINT) {
|
||||||
|
// 如果有点对点地址
|
||||||
|
if (buf[len] != '\0') {
|
||||||
|
// 如果有点对点地址
|
||||||
|
int dstlen = sizeof(struct sockaddr); // 点对点地址结构体长度
|
||||||
|
if (len + dstlen > size) break; // 缓冲区不足
|
||||||
|
ifa->ifa_dstaddr = (struct sockaddr *)malloc(dstlen); // 为点对点地址分配内存
|
||||||
|
if (ifa->ifa_dstaddr == NULL) {
|
||||||
|
// 分配失败,释放已分配的内存
|
||||||
|
free(ifa->ifa_netmask);
|
||||||
|
free(ifa->ifa_addr);
|
||||||
|
free(ifa->ifa_name);
|
||||||
|
free(ifa);
|
||||||
|
freeifaddrs(head);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
memcpy(ifa->ifa_dstaddr, buf + len, dstlen); // 复制点对点地址
|
||||||
|
len += dstlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有点对点地址,跳过一个空字节
|
||||||
|
ifa->ifa_dstaddr = NULL;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有广播地址或点对点地址,跳过两个空字节
|
||||||
|
ifa->ifa_broadaddr = NULL;
|
||||||
|
ifa->ifa_dstaddr = NULL;
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
// 读取接口数据
|
||||||
|
if (buf[len] != '\0') {
|
||||||
|
// 如果有数据
|
||||||
|
// TODO: 根据不同的地址族,读取不同的数据
|
||||||
|
// 这里暂时省略,只跳过一个空字节
|
||||||
|
ifa->ifa_data = NULL;
|
||||||
|
len += 1;
|
||||||
|
} else {
|
||||||
|
// 如果没有数据,跳过一个空字节
|
||||||
|
ifa->ifa_data = NULL;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 将当前接口插入链表
|
||||||
|
ifa->ifa_next = NULL;
|
||||||
|
if (head == NULL) {
|
||||||
|
// 如果是第一个接口,设置头指针
|
||||||
|
head = ifa;
|
||||||
|
} else {
|
||||||
|
// 如果不是第一个接口,设置尾指针的下一个指针
|
||||||
|
tail->ifa_next = ifa;
|
||||||
|
}
|
||||||
|
// 更新尾指针
|
||||||
|
tail = ifa;
|
||||||
|
}
|
||||||
|
*ifap = head; // 返回链表头指针
|
||||||
|
return len; // 返回读取的总字节数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个发送信号的函数,向服务器发送一个信号
|
||||||
|
int TINY_send_signal(int sockfd) {
|
||||||
|
char sig = 'S'; // 定义信号为一个字符S
|
||||||
|
int n = write(sockfd, &sig, 1); // 向套接字写入一个字节
|
||||||
|
if (n < 0) {
|
||||||
|
perror("write");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
return 0; // 返回成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个接收数据的函数,从服务器接收数据并反序列化
|
||||||
|
int TINY_receive_data(int sockfd, struct ifaddrs **ifap) {
|
||||||
|
char buf[BUFSIZE]; // 定义缓冲区
|
||||||
|
int n = read(sockfd, buf, BUFSIZE); // 从套接字读取数据
|
||||||
|
if (n < 0) {
|
||||||
|
perror("read");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
int len = TINY_deserialize_ifaddrs(buf, n, ifap); // 反序列化数据
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "deserialize_ifaddrs failed\n");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
return 0; // 返回成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
int getifaddrs(struct ifaddrs **ifap) {
|
||||||
|
// 创建一个套接字
|
||||||
|
int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 定义服务器地址结构体
|
||||||
|
struct sockaddr_un un;
|
||||||
|
memset(&un, 0, sizeof(un));
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
snprintf(un.sun_path, sizeof(un.sun_path), "%s", "/tmp/.getifaddrs-bridge");
|
||||||
|
// 连接到服务器
|
||||||
|
if (connect(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) {
|
||||||
|
perror("connect");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 发送信号给服务器
|
||||||
|
if (TINY_send_signal(sockfd) < 0) {
|
||||||
|
fprintf(stderr, "send_signal failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 接收数据并反序列化
|
||||||
|
if (TINY_receive_data(sockfd, ifap) < 0) {
|
||||||
|
fprintf(stderr, "receive_data failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 关闭套接字
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
222
extra/getifaddrs_bridge/getifaddrs_bridge_server.c
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
// getifaddrs_bridge_server.c -- This file is part of tiny_computer.
|
||||||
|
|
||||||
|
// Copyright (C) 2023 Caten Hu
|
||||||
|
|
||||||
|
// Tiny Computer is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License,
|
||||||
|
// or any later version.
|
||||||
|
|
||||||
|
// Tiny Computer is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
// See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
/* this file is mainly generated by Bing */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#define BUFSIZE 1024 // 定义缓冲区大小
|
||||||
|
|
||||||
|
// 定义一个序列化函数,将ifaddrs结构体转换为字节数组
|
||||||
|
int serialize_ifaddrs(struct ifaddrs *ifa, char *buf, int size) {
|
||||||
|
int len = 0; // 记录已经写入的字节数
|
||||||
|
while (ifa != NULL && len < size) {
|
||||||
|
// 写入接口名称
|
||||||
|
int namelen = strlen(ifa->ifa_name) + 1; // 包括结束符
|
||||||
|
if (len + namelen > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, ifa->ifa_name, namelen);
|
||||||
|
len += namelen;
|
||||||
|
// 写入接口标志
|
||||||
|
if (len + sizeof(unsigned int) > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, &ifa->ifa_flags, sizeof(unsigned int));
|
||||||
|
len += sizeof(unsigned int);
|
||||||
|
// 写入接口地址
|
||||||
|
if (ifa->ifa_addr != NULL) {
|
||||||
|
int addrlen = sizeof(struct sockaddr); // 地址结构体长度
|
||||||
|
if (len + addrlen > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, ifa->ifa_addr, addrlen);
|
||||||
|
len += addrlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有地址,写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 写入接口掩码
|
||||||
|
if (ifa->ifa_netmask != NULL) {
|
||||||
|
int masklen = sizeof(struct sockaddr); // 掩码结构体长度
|
||||||
|
if (len + masklen > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, ifa->ifa_netmask, masklen);
|
||||||
|
len += masklen;
|
||||||
|
} else {
|
||||||
|
// 如果没有掩码,写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 写入接口广播地址或点对点地址
|
||||||
|
if (ifa->ifa_flags & IFF_BROADCAST) {
|
||||||
|
// 如果有广播地址
|
||||||
|
if (ifa->ifa_broadaddr != NULL) {
|
||||||
|
int broadlen = sizeof(struct sockaddr); // 广播地址结构体长度
|
||||||
|
if (len + broadlen > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, ifa->ifa_broadaddr, broadlen);
|
||||||
|
len += broadlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有广播地址,写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
} else if (ifa->ifa_flags & IFF_POINTOPOINT) {
|
||||||
|
// 如果有点对点地址
|
||||||
|
if (ifa->ifa_dstaddr != NULL) {
|
||||||
|
int dstlen = sizeof(struct sockaddr); // 点对点地址结构体长度
|
||||||
|
if (len + dstlen > size) break; // 缓冲区不足
|
||||||
|
memcpy(buf + len, ifa->ifa_dstaddr, dstlen);
|
||||||
|
len += dstlen;
|
||||||
|
} else {
|
||||||
|
// 如果没有点对点地址,写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有广播地址或点对点地址,写入两个空字节
|
||||||
|
if (len + 2 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
buf[len + 1] = '\0';
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
// 写入接口数据
|
||||||
|
if (ifa->ifa_data != NULL) {
|
||||||
|
// TODO: 根据不同的地址族,写入不同的数据
|
||||||
|
// 这里暂时省略,只写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
} else {
|
||||||
|
// 如果没有数据,写入一个空字节
|
||||||
|
if (len + 1 > size) break; // 缓冲区不足
|
||||||
|
buf[len] = '\0';
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
// 跳到下一个接口
|
||||||
|
ifa = ifa->ifa_next;
|
||||||
|
}
|
||||||
|
return len; // 返回写入的总字节数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个接收信号的函数,从客户端接收一个信号
|
||||||
|
int receive_signal(int sockfd) {
|
||||||
|
char sig; // 定义信号变量
|
||||||
|
int n = read(sockfd, &sig, 1); // 从套接字读取一个字节
|
||||||
|
if (n < 0) {
|
||||||
|
perror("read");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
if (sig == 'S') {
|
||||||
|
// 如果收到信号S,表示客户端需要数据
|
||||||
|
return 0; // 返回成功
|
||||||
|
} else {
|
||||||
|
// 如果收到其他信号,表示无效信号
|
||||||
|
fprintf(stderr, "invalid signal: %c\n", sig);
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个发送数据的函数,向客户端发送数据并序列化
|
||||||
|
int send_data(int sockfd) {
|
||||||
|
struct ifaddrs *ifap = NULL; // 定义ifaddrs结构体指针
|
||||||
|
// 调用getifaddrs函数,获取本地接口信息
|
||||||
|
if (getifaddrs(&ifap) < 0) {
|
||||||
|
perror("getifaddrs");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
char buf[BUFSIZE]; // 定义缓冲区
|
||||||
|
// 调用序列化函数,将ifaddrs结构体转换为字节数组
|
||||||
|
int len = serialize_ifaddrs(ifap, buf, BUFSIZE);
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "serialize_ifaddrs failed\n");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
// 向套接字写入数据
|
||||||
|
int n = write(sockfd, buf, len);
|
||||||
|
if (n < 0) {
|
||||||
|
perror("write");
|
||||||
|
return -1; // 返回错误
|
||||||
|
}
|
||||||
|
// 释放ifaddrs结构体
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return 0; // 返回成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("usage: %s <socket_path>\n", argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 创建一个套接字
|
||||||
|
int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 定义服务器地址结构体
|
||||||
|
struct sockaddr_un un;
|
||||||
|
memset(&un, 0, sizeof(un));
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
snprintf(un.sun_path, sizeof(un.sun_path), "%s", argv[1]);
|
||||||
|
unlink(un.sun_path);
|
||||||
|
// 绑定套接字到服务器地址
|
||||||
|
if (bind(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 监听套接字
|
||||||
|
if (listen(sockfd, 5) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// 循环接受客户端连接
|
||||||
|
while (1) {
|
||||||
|
int connfd = accept(sockfd, NULL, NULL);
|
||||||
|
if (connfd < 0) {
|
||||||
|
perror("accept");
|
||||||
|
continue; // 如果接受失败,继续循环
|
||||||
|
}
|
||||||
|
// 循环接收和发送数据
|
||||||
|
while (1) {
|
||||||
|
// 接收信号
|
||||||
|
if (receive_signal(connfd) < 0) {
|
||||||
|
fprintf(stderr, "receive_signal failed\n");
|
||||||
|
close(connfd); // 如果接收失败,关闭连接套接字
|
||||||
|
break; // 跳出循环
|
||||||
|
}
|
||||||
|
// 发送数据
|
||||||
|
if (send_data(connfd) < 0) {
|
||||||
|
fprintf(stderr, "send_data failed\n");
|
||||||
|
close(connfd); // 如果发送失败,关闭连接套接字
|
||||||
|
break; // 跳出循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 关闭监听套接字
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
19
extra/getifaddrs_bridge/readme.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
### 编译
|
||||||
|
|
||||||
|
使用NDK编译getifaddrs_bridge_server.c:
|
||||||
|
|
||||||
|
`aarch64-linux-android-clang getifaddrs_bridge_server.c -o getifaddrs_bridge_server`
|
||||||
|
|
||||||
|
在小小电脑上编译getifaddrs_bridge_client_lib.c:
|
||||||
|
|
||||||
|
`gcc getifaddrs_bridge_client_lib.c -o getifaddrs_bridge_client_lib.so -shared`
|
||||||
|
|
||||||
|
### 使用
|
||||||
|
|
||||||
|
在安卓端:
|
||||||
|
|
||||||
|
`getifaddrs_bridge_server /path/to/container/tmp/.getifaddrs-bridge`
|
||||||
|
|
||||||
|
在proot容器:
|
||||||
|
|
||||||
|
`LD_PRELOAD=/path/to/getifaddrs_bridge_client_lib.so <your_program>`
|
||||||
146
extra/gxde-25-upgrade.sh
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 定义颜色以便于阅读
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}=== GXDE OS 15 -> 25 命令行升级工具 ===${NC}"
|
||||||
|
|
||||||
|
# 1. 检查 root 权限
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo -e "${RED}错误: 请使用 root 权限运行此脚本 (例如: sudo $0)${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 风险确认 (替代 Zenity)
|
||||||
|
echo -e "${YELLOW}警告:您即将执行 GXDE OS 15 到 25 的升级${NC}"
|
||||||
|
echo "• 该操作不可逆且存在风险"
|
||||||
|
echo "• 请确保系统已经更新到最新"
|
||||||
|
echo "• 请确保已做好数据备份"
|
||||||
|
echo "• 升级过程可能需要 1-3 小时,期间请勿关闭终端"
|
||||||
|
echo ""
|
||||||
|
read -p "您确定要继续吗?(输入 yes 继续,其他键取消): " confirm
|
||||||
|
if [ "$confirm" != "yes" ]; then
|
||||||
|
echo "操作已取消。"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YELLOW}再次确认:这是一个高风险操作!!!${NC}"
|
||||||
|
read -p "请输入 'I AGREE' (大写) 以确认并开始升级: " confirm_final
|
||||||
|
if [ "$confirm_final" != "I AGREE" ]; then
|
||||||
|
echo "操作已取消。"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}>>> 开始预处理...${NC}"
|
||||||
|
|
||||||
|
# 刷新缓存与修复依赖
|
||||||
|
echo "正在刷新系统包缓存..."
|
||||||
|
apt update
|
||||||
|
aptss update
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
echo "正在检查和修复系统依赖问题..."
|
||||||
|
aptss install -f -yqq
|
||||||
|
|
||||||
|
# 删除冲突包
|
||||||
|
echo "正在移除 qtbase5-dev..."
|
||||||
|
apt autopurge qtbase5-dev -y
|
||||||
|
|
||||||
|
# 3. 替换软件源 (核心逻辑)
|
||||||
|
echo "正在替换软件源..."
|
||||||
|
# 备份并替换主源
|
||||||
|
sed -i 's/bookworm/trixie/g' /etc/apt/sources.list
|
||||||
|
|
||||||
|
# 处理 PPA 源
|
||||||
|
declare -A ppa_map=(
|
||||||
|
["/etc/apt/sources.list.d/gxde.list"]='s/bixie/lizhi/g'
|
||||||
|
["/etc/apt/sources.list.d/gxde-testing.list"]='s/tianlu/zhuangzhuang/g'
|
||||||
|
)
|
||||||
|
rm -vf /etc/apt/sources.list.d/gxde-bpo.list
|
||||||
|
|
||||||
|
for file in "${!ppa_map[@]}"; do
|
||||||
|
if [[ -f "$file" ]]; then
|
||||||
|
sed -i "${ppa_map[$file]}" "$file"
|
||||||
|
echo "已更新源文件: $file"
|
||||||
|
else
|
||||||
|
[[ "$file" =~ testing ]] && continue
|
||||||
|
echo -e "${RED}严重错误:关键源文件缺失 $file${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 屏蔽旧的更新器
|
||||||
|
echo "正在屏蔽旧版更新器..."
|
||||||
|
rm -fv /usr/bin/gxde-app-upgrader
|
||||||
|
cat > /usr/bin/gxde-app-upgrader << EOF
|
||||||
|
#!/bin/bash
|
||||||
|
echo "警告:检测到您尚未完成系统大版本更新,请完成 CLI 更新流程!"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/bin/gxde-app-upgrader
|
||||||
|
|
||||||
|
# 刷新新源
|
||||||
|
echo "正在刷新新源缓存..."
|
||||||
|
apt update
|
||||||
|
aptss update
|
||||||
|
yes n | aptss install gxde-25-upgrader -yqq
|
||||||
|
|
||||||
|
echo -e "${GREEN}>>> 预处理完成,准备开始核心升级...${NC}"
|
||||||
|
echo -e "${YELLOW}注意:接下来的过程请保持网络畅通,不要中断脚本运行。${NC}"
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# 4. 执行核心升级逻辑 (原 gxde-post-upgrade-fix 内容)
|
||||||
|
|
||||||
|
# 检查当前桌面环境状态
|
||||||
|
ANDROID_INSTALLED=0
|
||||||
|
DESKTOP_MISSING=0
|
||||||
|
dpkg -s gxde-desktop-android &>/dev/null && ANDROID_INSTALLED=1
|
||||||
|
dpkg -s gxde-desktop &>/dev/null || DESKTOP_MISSING=1
|
||||||
|
|
||||||
|
# 确定要安装的桌面包
|
||||||
|
DESKTOP_PKG="gxde-desktop"
|
||||||
|
if [ "$ANDROID_INSTALLED" -eq 1 ] && [ "$DESKTOP_MISSING" -eq 1 ]; then
|
||||||
|
DESKTOP_PKG="gxde-desktop-android"
|
||||||
|
echo "检测到 Android 环境,将安装: $DESKTOP_PKG"
|
||||||
|
else
|
||||||
|
echo "将在升级后安装: $DESKTOP_PKG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 执行 Full Upgrade
|
||||||
|
echo -e "${GREEN}>>> 正在执行系统全面升级 (Full Upgrade)...这可能需要很长时间${NC}"
|
||||||
|
yes n | env DEBIAN_FRONTEND=noninteractive aptss full-upgrade \
|
||||||
|
-o DPkg::options::="--force-confdef" \
|
||||||
|
-o DPkg::options::="--force-confold" \
|
||||||
|
-o DPkg::options::="--force-overwrite" \
|
||||||
|
-yqq --assume-yes
|
||||||
|
|
||||||
|
# 处理 grub 配置问题 (Hack)
|
||||||
|
echo "正在处理 GRUB 配置..."
|
||||||
|
if [ -f /var/lib/dpkg/info/grub-pc.postinst ]; then
|
||||||
|
mv -v /var/lib/dpkg/info/grub-pc.postinst /var/lib/dpkg/info/grub-pc.postinst.bak
|
||||||
|
dpkg --configure -a
|
||||||
|
mv -v /var/lib/dpkg/info/grub-pc.postinst.bak /var/lib/dpkg/info/grub-pc.postinst
|
||||||
|
else
|
||||||
|
dpkg --configure -a
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 安装/更新核心软件包
|
||||||
|
echo -e "${GREEN}>>> 正在安装/重装核心组件...${NC}"
|
||||||
|
yes n | env DEBIAN_FRONTEND=noninteractive aptss install gxde-app-upgrader --reinstall -yqq
|
||||||
|
|
||||||
|
if yes n | env DEBIAN_FRONTEND=noninteractive aptss install $DESKTOP_PKG deepin-kwin-x11 libdtkcore-dev deepin-desktop-base spark-store gxde-control-center --reinstall -yqq; then
|
||||||
|
|
||||||
|
# 启用服务
|
||||||
|
systemctl enable dde-filemanager-daemon.service || true
|
||||||
|
|
||||||
|
echo -e "${GREEN}-----------------------${NC}"
|
||||||
|
echo -e "${GREEN}升级成功完成!${NC}"
|
||||||
|
echo -e "${YELLOW}请按回车键重启您的计算机,或者按 Ctrl+C 稍后手动重启。${NC}"
|
||||||
|
read
|
||||||
|
reboot
|
||||||
|
else
|
||||||
|
echo -e "${RED}!!!!!! 升级过程中出现错误 !!!!!!${NC}"
|
||||||
|
echo "请保留此终端输出,并反馈给 QQ 群 881201853"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
58
extra/readme.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
## 这个readme介绍assets文件夹中文件的制作方式。
|
||||||
|
|
||||||
|
### assets.zip中的文件:
|
||||||
|
|
||||||
|
- [Xserver XSDL, pulseaudio相关文件](https://github.com/pelya/commandergenius/tree/sdl_android/project/jni/application/xserver)。直接从Xserver XSDL的apk中的lib解包获得,并还原了名称。
|
||||||
|
- [Tmoe Linux, debian包来源](https://github.com/2moe/tmoe),制作了[容器文件xa*](build-tiny-rootfs.md)
|
||||||
|
- getifaddrs_bridge_server,见下面的介绍和getifaddrs_bridge子文件夹
|
||||||
|
|
||||||
|
### jniLibs中的文件
|
||||||
|
|
||||||
|
除libexec_pulseaudio.so(pulseaudio可执行文件)来自Xserver XSDL的apk外,所有文件均通过[termux-packages](https://github.com/termux-play-store/termux-packages)构建。[见这个修改后的仓库](https://github.com/tiny-computer/termux-packages)
|
||||||
|
|
||||||
|
运行scripts/generate-bootstraps.sh即可获得bootstraps压缩包,其中会包含busybox、proot、tar、virglrenderer的可执行文件和依赖库。将可执行文件全部重命名为libexec_xxx.so的格式,将依赖库全部抹去版本号,放到jniLibs/arm64-v8a。
|
||||||
|
|
||||||
|
运行build-package.sh proot,可在output文件夹找到loader和loader32,重命名为libproot-loader.so和libproot-loader32.so,放到jniLibs/arm64-v8a。
|
||||||
|
|
||||||
|
|
||||||
|
### patch.tar.gz中的文件:
|
||||||
|
|
||||||
|
#### extra/getifaddrs_bridge_client_lib.so:
|
||||||
|
|
||||||
|
在安卓13以上的系统中,proot容器无权使用默认的getifaddrs,而这个库包含了一个getifaddrs实现。
|
||||||
|
|
||||||
|
linux在需要数据时,使用socket通知位于安卓的getifaddrs_bridge_server,让getifaddrs_bridge_server执行getifaddrs函数,并将结构体数据序列化后发送回linux端,这边接收数据并反序列化还原成指针结构体。简单来说就是用安卓的getifaddrs代替linux的getifaddrs。
|
||||||
|
|
||||||
|
源码和编译信息在getifaddrs_bridge文件夹查看。
|
||||||
|
|
||||||
|
#### extra/install-hangover, extra/install-hangover-stable:
|
||||||
|
|
||||||
|
这些是用于Windows应用支持的Hangover安装脚本。
|
||||||
|
|
||||||
|
#### extra/chn_fonts.reg:
|
||||||
|
|
||||||
|
修复wine显示方块字的注册表文件。
|
||||||
|
|
||||||
|
#### extra/libvulkan_freedreno.so, extra/freedreno_icd.aarch64.json:
|
||||||
|
|
||||||
|
Turnip驱动。根据[这里](https://github.com/xDoge26/proot-setup/issues/26#issuecomment-1712404849)和[这里](https://github.com/MastaG/mesa-turnip-ppa)编译
|
||||||
|
|
||||||
|
#### extra/cmatrix
|
||||||
|
|
||||||
|
快捷指令的彩蛋。原本放在容器里,但显然放这里更为合适
|
||||||
|
|
||||||
|
#### extra/tiny_virtual_mic
|
||||||
|
|
||||||
|
麦克风客户端。实现见tiny_virtual_mic.c
|
||||||
|
|
||||||
|
#### caj, edraw
|
||||||
|
|
||||||
|
这些分别是cajviewer,亿图图示的补丁
|
||||||
|
|
||||||
|
- 亿图图示补丁的库文件是在小小电脑上下载了Qt对应版本源码后编译得到的;
|
||||||
|
- 编译进行了两次,第一次直接编译,可以得到Gui和Widgets两个库。第二次编译带上XcbQpa,虽然会编译失败,但在这之前就可以得到XcbQpa的库。
|
||||||
|
|
||||||
|
#### font
|
||||||
|
|
||||||
|
[小赖字体](https://github.com/lxgw/kose-font)用于修复wine的方块字
|
||||||
|
其他字体用于避免wps报字体缺失的错误
|
||||||
74
extra/tiny_virtual_mic.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <pulse/simple.h>
|
||||||
|
#include <pulse/error.h>
|
||||||
|
|
||||||
|
#define BUFSIZE 4096
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s <socket_path> <target_device>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Setup PulseAudio
|
||||||
|
static const pa_sample_spec ss = {
|
||||||
|
.format = PA_SAMPLE_S16LE,
|
||||||
|
.rate = 44100,
|
||||||
|
.channels = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
pa_buffer_attr attr;
|
||||||
|
attr.maxlength = (uint32_t) -1;
|
||||||
|
attr.tlength = pa_usec_to_bytes(60000, &ss); // 目标延迟设为 60ms
|
||||||
|
attr.prebuf = (uint32_t) -1;
|
||||||
|
attr.minreq = (uint32_t) -1;
|
||||||
|
attr.fragsize = (uint32_t) -1;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
pa_simple *s = pa_simple_new(NULL, "AndroidStream", PA_STREAM_PLAYBACK, argv[2], "live_audio", &ss, NULL, &attr, &error);
|
||||||
|
if (!s) {
|
||||||
|
fprintf(stderr, "pa_simple_new() failed: %s\n", pa_strerror(error));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Connect to Android Socket
|
||||||
|
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sock_fd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
printf("Connecting to %s...\n", argv[1]);
|
||||||
|
while (connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||||
|
printf("Waiting for server...\n");
|
||||||
|
sleep(1); // Retry logic since Android might start later
|
||||||
|
}
|
||||||
|
printf("Connected! Playing audio...\n");
|
||||||
|
|
||||||
|
// 3. Stream Loop
|
||||||
|
uint8_t buf[BUFSIZE];
|
||||||
|
while (1) {
|
||||||
|
ssize_t r = read(sock_fd, buf, sizeof(buf));
|
||||||
|
if (r <= 0) break;
|
||||||
|
|
||||||
|
if (pa_simple_write(s, buf, (size_t)r, &error) < 0) {
|
||||||
|
fprintf(stderr, "pa_simple_write() failed: %s\n", pa_strerror(error));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
pa_simple_free(s);
|
||||||
|
close(sock_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
363
extra/turnip.patch
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc
|
||||||
|
index edc0ce1f6fe..e5b8e9bc44d 100644
|
||||||
|
--- a/src/freedreno/vulkan/tu_shader.cc
|
||||||
|
+++ b/src/freedreno/vulkan/tu_shader.cc
|
||||||
|
@@ -2556,10 +2556,10 @@ tu_upload_shader(struct tu_device *dev,
|
||||||
|
size += vpc_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
- pthread_mutex_lock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_lock(&dev->pipeline_mutex);
|
||||||
|
VkResult result = tu_suballoc_bo_alloc(&shader->bo, &dev->pipeline_suballoc,
|
||||||
|
size * 4, 128);
|
||||||
|
- pthread_mutex_unlock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_unlock(&dev->pipeline_mutex);
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
return result;
|
||||||
|
@@ -2589,9 +2589,9 @@ tu_upload_shader(struct tu_device *dev,
|
||||||
|
|
||||||
|
result = tu_setup_pvtmem(dev, shader, &pvtmem_config, pvtmem_size, per_wave);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
- pthread_mutex_lock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_lock(&dev->pipeline_mutex);
|
||||||
|
tu_suballoc_bo_free(&dev->pipeline_suballoc, &shader->bo);
|
||||||
|
- pthread_mutex_unlock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_unlock(&dev->pipeline_mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3427,10 +3427,10 @@ tu_empty_shader_create(struct tu_device *dev,
|
||||||
|
if (!shader)
|
||||||
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||||
|
|
||||||
|
- pthread_mutex_lock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_lock(&dev->pipeline_mutex);
|
||||||
|
VkResult result = tu_suballoc_bo_alloc(&shader->bo, &dev->pipeline_suballoc,
|
||||||
|
32 * 4, 128);
|
||||||
|
- pthread_mutex_unlock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_unlock(&dev->pipeline_mutex);
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
vk_free(&dev->vk.alloc, shader);
|
||||||
|
@@ -3541,9 +3541,9 @@ tu_shader_destroy(struct tu_device *dev,
|
||||||
|
tu_cs_finish(&shader->cs);
|
||||||
|
TU_RMV(resource_destroy, dev, &shader->bo);
|
||||||
|
|
||||||
|
- pthread_mutex_lock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_lock(&dev->pipeline_mutex);
|
||||||
|
tu_suballoc_bo_free(&dev->pipeline_suballoc, &shader->bo);
|
||||||
|
- pthread_mutex_unlock(&dev->pipeline_mutex);
|
||||||
|
+ mtx_unlock(&dev->pipeline_mutex);
|
||||||
|
|
||||||
|
if (shader->pvtmem_bo)
|
||||||
|
tu_bo_finish(dev, shader->pvtmem_bo);
|
||||||
|
diff --git a/src/freedreno/vulkan/tu_wsi.cc b/src/freedreno/vulkan/tu_wsi.cc
|
||||||
|
index 57cf9048b07..246a95dd894 100644
|
||||||
|
--- a/src/freedreno/vulkan/tu_wsi.cc
|
||||||
|
+++ b/src/freedreno/vulkan/tu_wsi.cc
|
||||||
|
@@ -47,6 +47,10 @@ tu_wsi_init(struct tu_physical_device *physical_device)
|
||||||
|
&options);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
return result;
|
||||||
|
+
|
||||||
|
+ if (strcmp(physical_device->instance->knl->name, "kgsl") == 0) {
|
||||||
|
+ physical_device->wsi_device.is_tu_kgsl = true;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
physical_device->wsi_device.supports_modifiers = true;
|
||||||
|
physical_device->wsi_device.can_present_on_device =
|
||||||
|
diff --git a/src/util/anon_file.c b/src/util/anon_file.c
|
||||||
|
index a9ad2a2aad8..f5dcd5b3b48 100644
|
||||||
|
--- a/src/util/anon_file.c
|
||||||
|
+++ b/src/util/anon_file.c
|
||||||
|
@@ -117,6 +117,11 @@ get_or_create_user_temp_dir(char* buf, size_t len) {
|
||||||
|
int uid = getuid();
|
||||||
|
|
||||||
|
env = os_get_option("XDG_RUNTIME_DIR");
|
||||||
|
+#ifdef __linux__
|
||||||
|
+ if (!env) {
|
||||||
|
+ env = "/tmp";
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
if (env && env[0] != '\0') {
|
||||||
|
snprintf(buf, len, "%s", env);
|
||||||
|
return buf;
|
||||||
|
diff --git a/src/util/u_process.c b/src/util/u_process.c
|
||||||
|
index 6846acd2e0b..8551c227b88 100644
|
||||||
|
--- a/src/util/u_process.c
|
||||||
|
+++ b/src/util/u_process.c
|
||||||
|
@@ -101,7 +101,7 @@ __getProgramName()
|
||||||
|
{
|
||||||
|
return strdup(program_invocation_short_name);
|
||||||
|
}
|
||||||
|
-#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) || DETECT_OS_ANDROID || defined(__NetBSD__)
|
||||||
|
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) || DETECT_OS_ANDROID || defined(__NetBSD__) || defined(__linux__)
|
||||||
|
#if defined(__NetBSD__)
|
||||||
|
# include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c
|
||||||
|
index 6783fbd6efb..3a81c200c2a 100644
|
||||||
|
--- a/src/vulkan/wsi/wsi_common.c
|
||||||
|
+++ b/src/vulkan/wsi/wsi_common.c
|
||||||
|
@@ -2491,7 +2491,7 @@ wsi_common_queue_present(const struct wsi_device *wsi,
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (wsi->sw) {
|
||||||
|
+ if (wsi->sw || (wsi->is_tu_kgsl && (swapchain->dma_buf_semaphore == VK_NULL_HANDLE))) {
|
||||||
|
wsi->WaitForFences(vk_device_to_handle(dev),
|
||||||
|
1, &swapchain->fences[image_index], true, ~0ull);
|
||||||
|
}
|
||||||
|
@@ -3217,7 +3217,7 @@ wsi_configure_cpu_image(const struct wsi_swapchain *chain,
|
||||||
|
const struct wsi_cpu_image_params *params,
|
||||||
|
struct wsi_image_info *info)
|
||||||
|
{
|
||||||
|
- assert(params->base.image_type == WSI_IMAGE_TYPE_CPU);
|
||||||
|
+ // assert(params->base.image_type == WSI_IMAGE_TYPE_CPU);
|
||||||
|
assert(chain->blit.type == WSI_SWAPCHAIN_NO_BLIT ||
|
||||||
|
chain->blit.type == WSI_SWAPCHAIN_BUFFER_BLIT);
|
||||||
|
|
||||||
|
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
|
||||||
|
index c17a79c6b13..20c480babbc 100644
|
||||||
|
--- a/src/vulkan/wsi/wsi_common.h
|
||||||
|
+++ b/src/vulkan/wsi/wsi_common.h
|
||||||
|
@@ -152,6 +152,7 @@ struct wsi_device {
|
||||||
|
|
||||||
|
|
||||||
|
bool sw;
|
||||||
|
+ bool is_tu_kgsl;
|
||||||
|
|
||||||
|
/* Set to true if the implementation is ok with linear WSI images. */
|
||||||
|
bool wants_linear;
|
||||||
|
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
|
||||||
|
index f72e85c5e66..ac83c92236a 100644
|
||||||
|
--- a/src/vulkan/wsi/wsi_common_display.c
|
||||||
|
+++ b/src/vulkan/wsi/wsi_common_display.c
|
||||||
|
@@ -516,6 +516,12 @@ struct wsi_display_sync {
|
||||||
|
|
||||||
|
static uint64_t fence_sequence;
|
||||||
|
|
||||||
|
+#ifdef __linux__
|
||||||
|
+static void thread_signal_handler (int signum) {
|
||||||
|
+ pthread_exit (0);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
_wsi_display_cleanup_state(struct wsi_display_swapchain *chain);
|
||||||
|
|
||||||
|
@@ -2024,7 +2030,9 @@ wsi_display_wait_thread(void *data)
|
||||||
|
.events = POLLIN
|
||||||
|
};
|
||||||
|
|
||||||
|
+#ifndef __linux__
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||||
|
+#endif
|
||||||
|
for (;;) {
|
||||||
|
int ret = poll(&pollfd, 1, -1);
|
||||||
|
if (ret > 0) {
|
||||||
|
@@ -2052,9 +2060,21 @@ wsi_display_start_wait_thread(struct wsi_display *wsi)
|
||||||
|
static void
|
||||||
|
wsi_display_stop_wait_thread(struct wsi_display *wsi)
|
||||||
|
{
|
||||||
|
+#ifdef __linux__
|
||||||
|
+ struct sigaction actions;
|
||||||
|
+ memset (&actions, 0, sizeof (actions));
|
||||||
|
+ sigemptyset (&actions.sa_mask);
|
||||||
|
+ actions.sa_flags = 0;
|
||||||
|
+ actions.sa_handler = thread_signal_handler;
|
||||||
|
+ sigaction (SIGUSR2, &actions, NULL);
|
||||||
|
+#endif
|
||||||
|
mtx_lock(&wsi->wait_mutex);
|
||||||
|
if (wsi->wait_thread) {
|
||||||
|
+#ifndef __linux__
|
||||||
|
pthread_cancel(wsi->wait_thread);
|
||||||
|
+#else
|
||||||
|
+ pthread_kill(wsi->wait_thread, SIGUSR2);
|
||||||
|
+#endif
|
||||||
|
pthread_join(wsi->wait_thread, NULL);
|
||||||
|
wsi->wait_thread = 0;
|
||||||
|
}
|
||||||
|
@@ -3456,7 +3476,9 @@ udev_event_listener_thread(void *data)
|
||||||
|
|
||||||
|
int udev_fd = udev_monitor_get_fd(mon);
|
||||||
|
|
||||||
|
+#ifndef __linux__
|
||||||
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
nfds_t nfds = 1;
|
||||||
|
@@ -3603,6 +3625,15 @@ wsi_display_finish_wsi(struct wsi_device *wsi_device,
|
||||||
|
struct wsi_display *wsi =
|
||||||
|
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
|
||||||
|
|
||||||
|
+#ifdef __linux__
|
||||||
|
+ struct sigaction actions;
|
||||||
|
+ memset (&actions, 0, sizeof (actions));
|
||||||
|
+ sigemptyset (&actions.sa_mask);
|
||||||
|
+ actions.sa_flags = 0;
|
||||||
|
+ actions.sa_handler = thread_signal_handler;
|
||||||
|
+ sigaction (SIGUSR2, &actions, NULL);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (wsi) {
|
||||||
|
wsi_for_each_connector(connector, wsi)
|
||||||
|
wsi_display_free_connector(wsi, connector);
|
||||||
|
@@ -3610,7 +3641,11 @@ wsi_display_finish_wsi(struct wsi_device *wsi_device,
|
||||||
|
wsi_display_stop_wait_thread(wsi);
|
||||||
|
|
||||||
|
if (wsi->hotplug_thread) {
|
||||||
|
+#ifndef __linux__
|
||||||
|
pthread_cancel(wsi->hotplug_thread);
|
||||||
|
+#else
|
||||||
|
+ pthread_kill(wsi->hotplug_thread, SIGUSR2);
|
||||||
|
+#endif
|
||||||
|
pthread_join(wsi->hotplug_thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/vulkan/wsi/wsi_common_drm.c b/src/vulkan/wsi/wsi_common_drm.c
|
||||||
|
index fe297d3ca01..8c48b29d733 100644
|
||||||
|
--- a/src/vulkan/wsi/wsi_common_drm.c
|
||||||
|
+++ b/src/vulkan/wsi/wsi_common_drm.c
|
||||||
|
@@ -47,6 +47,9 @@
|
||||||
|
static VkResult
|
||||||
|
wsi_dma_buf_export_sync_file(int dma_buf_fd, int *sync_file_fd)
|
||||||
|
{
|
||||||
|
+ #if defined (__linux__)
|
||||||
|
+ return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||||
|
+ #else
|
||||||
|
struct dma_buf_export_sync_file export = {
|
||||||
|
.flags = DMA_BUF_SYNC_RW,
|
||||||
|
.fd = -1,
|
||||||
|
@@ -64,11 +67,15 @@ wsi_dma_buf_export_sync_file(int dma_buf_fd, int *sync_file_fd)
|
||||||
|
*sync_file_fd = export.fd;
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
+ #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static VkResult
|
||||||
|
wsi_dma_buf_import_sync_file(int dma_buf_fd, int sync_file_fd)
|
||||||
|
{
|
||||||
|
+ #if defined (__linux__)
|
||||||
|
+ return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||||
|
+ #else
|
||||||
|
struct dma_buf_import_sync_file import = {
|
||||||
|
.flags = DMA_BUF_SYNC_RW,
|
||||||
|
.fd = sync_file_fd,
|
||||||
|
@@ -84,6 +91,7 @@ wsi_dma_buf_import_sync_file(int dma_buf_fd, int sync_file_fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
+ #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
|
||||||
|
index 5e4b3a68d07..d19b8faa196 100644
|
||||||
|
--- a/src/vulkan/wsi/wsi_common_x11.c
|
||||||
|
+++ b/src/vulkan/wsi/wsi_common_x11.c
|
||||||
|
@@ -149,22 +149,7 @@ static bool
|
||||||
|
wsi_x11_check_dri3_compatible(const struct wsi_device *wsi_dev,
|
||||||
|
xcb_connection_t *conn)
|
||||||
|
{
|
||||||
|
- xcb_screen_iterator_t screen_iter =
|
||||||
|
- xcb_setup_roots_iterator(xcb_get_setup(conn));
|
||||||
|
- xcb_screen_t *screen = screen_iter.data;
|
||||||
|
-
|
||||||
|
- /* Open the DRI3 device from the X server. If we do not retrieve one we
|
||||||
|
- * assume our local device is compatible.
|
||||||
|
- */
|
||||||
|
- int dri3_fd = wsi_dri3_open(conn, screen->root, None);
|
||||||
|
- if (dri3_fd == -1)
|
||||||
|
- return true;
|
||||||
|
-
|
||||||
|
- bool match = wsi_dev->can_present_on_device(wsi_dev->pdevice, dri3_fd);
|
||||||
|
-
|
||||||
|
- close(dri3_fd);
|
||||||
|
-
|
||||||
|
- return match;
|
||||||
|
+ return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -1453,8 +1438,6 @@ x11_present_to_x11_dri3(struct x11_swapchain *chain, uint32_t image_index,
|
||||||
|
!wsi_device->x11.ignore_suboptimal)
|
||||||
|
options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
|
||||||
|
|
||||||
|
- xshmfence_reset(image->shm_fence);
|
||||||
|
-
|
||||||
|
if (!chain->base.image_info.explicit_sync) {
|
||||||
|
++chain->sent_image_count;
|
||||||
|
assert(chain->sent_image_count <= chain->base.image_count);
|
||||||
|
@@ -1832,11 +1815,6 @@ x11_acquire_next_image(struct wsi_swapchain *wsi_chain,
|
||||||
|
return result;
|
||||||
|
|
||||||
|
assert(*image_index < chain->base.image_count);
|
||||||
|
-#ifdef HAVE_X11_DRM
|
||||||
|
- if (chain->images[*image_index].shm_fence &&
|
||||||
|
- !chain->base.image_info.explicit_sync)
|
||||||
|
- xshmfence_await(chain->images[*image_index].shm_fence);
|
||||||
|
-#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@@ -2201,15 +2179,24 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
|
||||||
|
if (fd == -1)
|
||||||
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||||
|
|
||||||
|
- cookie =
|
||||||
|
- xcb_dri3_pixmap_from_buffer_checked(chain->conn,
|
||||||
|
- image->pixmap,
|
||||||
|
- chain->window,
|
||||||
|
- image->base.sizes[0],
|
||||||
|
- pCreateInfo->imageExtent.width,
|
||||||
|
- pCreateInfo->imageExtent.height,
|
||||||
|
- image->base.row_pitches[0],
|
||||||
|
- chain->depth, bpp, fd);
|
||||||
|
+ cookie = xcb_dri3_pixmap_from_buffers_checked(chain->conn,
|
||||||
|
+ image->pixmap,
|
||||||
|
+ chain->window,
|
||||||
|
+ image->base.num_planes,
|
||||||
|
+ pCreateInfo->imageExtent.width,
|
||||||
|
+ pCreateInfo->imageExtent.height,
|
||||||
|
+ image->base.row_pitches[0],
|
||||||
|
+ image->base.offsets[0],
|
||||||
|
+ 0,
|
||||||
|
+ 0,
|
||||||
|
+ 0,
|
||||||
|
+ 0,
|
||||||
|
+ 0,
|
||||||
|
+ 0,
|
||||||
|
+ chain->depth,
|
||||||
|
+ bpp,
|
||||||
|
+ 1274,
|
||||||
|
+ &fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = xcb_request_check(chain->conn, cookie);
|
||||||
|
@@ -2239,6 +2226,9 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ image->sync_fence = 0;
|
||||||
|
+ return VK_SUCCESS;
|
||||||
|
+
|
||||||
|
out_fence:
|
||||||
|
fence_fd = xshmfence_alloc_shm();
|
||||||
|
if (fence_fd < 0)
|
||||||
|
@@ -2281,12 +2271,6 @@ x11_image_finish(struct x11_swapchain *chain,
|
||||||
|
{
|
||||||
|
xcb_void_cookie_t cookie;
|
||||||
|
if (!chain->base.wsi->sw || chain->has_mit_shm) {
|
||||||
|
-#ifdef HAVE_X11_DRM
|
||||||
|
- cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
|
||||||
|
- xcb_discard_reply(chain->conn, cookie.sequence);
|
||||||
|
- xshmfence_unmap_shm(image->shm_fence);
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
|
||||||
|
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||||
|
#ifdef HAVE_X11_DRM
|
||||||
|
Before Width: | Height: | Size: 168 KiB |
BIN
images/icon.png
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 86 KiB |
34
ios/.gitignore
vendored
@@ -1,34 +0,0 @@
|
|||||||
**/dgph
|
|
||||||
*.mode1v3
|
|
||||||
*.mode2v3
|
|
||||||
*.moved-aside
|
|
||||||
*.pbxuser
|
|
||||||
*.perspectivev3
|
|
||||||
**/*sync/
|
|
||||||
.sconsign.dblite
|
|
||||||
.tags*
|
|
||||||
**/.vagrant/
|
|
||||||
**/DerivedData/
|
|
||||||
Icon?
|
|
||||||
**/Pods/
|
|
||||||
**/.symlinks/
|
|
||||||
profile
|
|
||||||
xcuserdata
|
|
||||||
**/.generated/
|
|
||||||
Flutter/App.framework
|
|
||||||
Flutter/Flutter.framework
|
|
||||||
Flutter/Flutter.podspec
|
|
||||||
Flutter/Generated.xcconfig
|
|
||||||
Flutter/ephemeral/
|
|
||||||
Flutter/app.flx
|
|
||||||
Flutter/app.zip
|
|
||||||
Flutter/flutter_assets/
|
|
||||||
Flutter/flutter_export_environment.sh
|
|
||||||
ServiceDefinitions.json
|
|
||||||
Runner/GeneratedPluginRegistrant.*
|
|
||||||
|
|
||||||
# Exceptions to above rules.
|
|
||||||
!default.mode1v3
|
|
||||||
!default.mode2v3
|
|
||||||
!default.pbxuser
|
|
||||||
!default.perspectivev3
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>io.flutter.flutter.app</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>MinimumOSVersion</key>
|
|
||||||
<string>11.0</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
||||||
@@ -1,614 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 54;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
|
||||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
|
||||||
remoteInfo = Runner;
|
|
||||||
};
|
|
||||||
/* End PBXContainerItemProxy section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 10;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
name = "Embed Frameworks";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Flutter;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
|
||||||
);
|
|
||||||
path = RunnerTests;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146E51CF9000F007C117D = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146EF1CF9000F007C117D /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
|
||||||
);
|
|
||||||
path = Runner;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
|
||||||
buildPhases = (
|
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
|
||||||
331C807E294A63A400263BE5 /* Frameworks */,
|
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
|
||||||
);
|
|
||||||
name = RunnerTests;
|
|
||||||
productName = RunnerTests;
|
|
||||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
|
||||||
};
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
|
||||||
buildPhases = (
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = Runner;
|
|
||||||
productName = Runner;
|
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
BuildIndependentTargetsInParallel = YES;
|
|
||||||
LastUpgradeCheck = 1430;
|
|
||||||
ORGANIZATIONNAME = "";
|
|
||||||
TargetAttributes = {
|
|
||||||
331C8080294A63A400263BE5 = {
|
|
||||||
CreatedOnToolsVersion = 14.0;
|
|
||||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
|
||||||
};
|
|
||||||
97C146ED1CF9000F007C117D = {
|
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
|
||||||
LastSwiftMigration = 1100;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
|
||||||
compatibilityVersion = "Xcode 9.3";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
331C807F294A63A400263BE5 /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
|
||||||
);
|
|
||||||
name = "Thin Binary";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
|
||||||
};
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Run Script";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
331C807D294A63A400263BE5 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
|
||||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
|
||||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C146FB1CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = Main.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C147001CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = LaunchScreen.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer.RunnerTests;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
97C147031CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147041CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
97C147061CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147071CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.tinyComputer;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
331C8088294A63A400263BE5 /* Debug */,
|
|
||||||
331C8089294A63A400263BE5 /* Release */,
|
|
||||||
331C808A294A63A400263BE5 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147031CF9000F007C117D /* Debug */,
|
|
||||||
97C147041CF9000F007C117D /* Release */,
|
|
||||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147061CF9000F007C117D /* Debug */,
|
|
||||||
97C147071CF9000F007C117D /* Release */,
|
|
||||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>PreviewsEnabled</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1430"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO"
|
|
||||||
parallelizable = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
|
||||||
BuildableName = "RunnerTests.xctest"
|
|
||||||
BlueprintName = "RunnerTests"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Profile"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
7
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:Runner.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>PreviewsEnabled</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import UIKit
|
|
||||||
import Flutter
|
|
||||||
|
|
||||||
@UIApplicationMain
|
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
|
||||||
override func application(
|
|
||||||
_ application: UIApplication,
|
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
||||||
) -> Bool {
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "83.5x83.5",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "1024x1024",
|
|
||||||
"idiom" : "ios-marketing",
|
|
||||||
"filename" : "Icon-App-1024x1024@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 862 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 762 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "LaunchImage@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 68 B |