This commit is contained in:
oneao committed 2026-03-18 17:14:34 +08:00
1 parent 52cef511d6
commit 68f08d921a
184 files changed
+19499 -1

No files matched your search

Submodule code/docusaurus deleted from 76067c88ed.
+2
View File
@@ -0,0 +1,2 @@
ALGOLIA_APP_ID=OQQO4TVA7K
ALGOLIA_API_KEY=941fbfc44df709cad3220294b747ed91
+20
View File
@@ -0,0 +1,20 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+4
View File
@@ -0,0 +1,4 @@
{
"recommendations": [
]
}
+57
View File
@@ -0,0 +1,57 @@
{
"editor.defaultFormatter": "oxc.oxc-vscode",
" editor.formatOnSave": true,
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in your IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"json5",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
],
"markdown.copyFiles.destination": {
"**/*.md": "${documentDirName}/assets/${unixTime}.${fileExtName}"
}
}
+41
View File
@@ -0,0 +1,41 @@
# Website
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
## Installation
```bash
yarn
```
## Local Development
```bash
yarn start
```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
## Build
```bash
yarn build
```
This command generates static content into the `build` directory and can be served using any static contents hosting service.
## Deployment
Using SSH:
```bash
USE_SSH=true yarn deploy
```
Not using SSH:
```bash
GIT_USER=<Your GitHub username> yarn deploy
```
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.
@@ -0,0 +1,5 @@
---
authors: oneao
---
欢迎访问 www.oneao.cn
+8
View File
@@ -0,0 +1,8 @@
oneao:
name: oneao
url: https://www.oneao.cn
image_url: https://avatars.githubusercontent.com/u/133963070?v=4
page: true
socials:
github: oneao
email: hi_itao@163.com
+19
View File
@@ -0,0 +1,19 @@
facebook:
label: Facebook
permalink: /facebook
description: Facebook tag description
hello:
label: Hello
permalink: /hello
description: Hello tag description
docusaurus:
label: Docusaurus
permalink: /docusaurus
description: Docusaurus tag description
hola:
label: Hola
permalink: /hola
description: Hola tag description
@@ -0,0 +1,100 @@
golang 下载地址:https://go.dev/dl/
## Windows
直接安装即可
可将 `golang\bin` 添加到环境变量中,输入校验是否安装成功
```bash
go version
```
## 配置
### GoPath
GOPATH 是 Go 语言的工作目录(工作区),它是 Go 项目存放代码、依赖和编译后的二进制文件的地方。
```bash
go env -w GOPATH="gopath路径"
```
### GoModule
**开启模块支持**
```bash
go env -w GO111MODULE=on
```
**设置代理**
```bash
# 官网全球代理
go env -w GOPROXY=https://goproxy.io,direct
# 七牛云代理(推荐)
go env -w GOPROXY=https://goproxy.cn,direct
```
> 检查是否生效 ,打开 `cmd` 输入
>
> ```bash
> go env GOPROXY
> ```
>
> 输出 `https://goproxy.cn,direct` 的话即代表成功
**取消代理**
```bash
go env -w GOPROXY=direct
```
## 编程工具
### Goland
**设置 GoModule**
![alt text](assets/1768281360563.png)
**设置 GoPath**
![alt text](assets/1768281382629.png)
#### 错误处理
- 运行报错:WARNING: undefined behavior - version of Delve is too old for Go version go1.25.0 (maximum supported version 1.24)
安装:
```bash
go install github.com/go-delve/delve/cmd/dlv@master
```
修改 goland 配置:`Help\Edit Custom Properties`,新增配置:
```
dlv.path=D:\\devtool\\golang\\gopath\\bin\\dlv.exe
```
这个路径是 `gopath` 配置后的路径,默认在c盘 `dlv.path=C:\\Users\\_user_\\go\\bin\\dlv.exe`
### VSCode
安装必要扩展 `go` ,可选扩展 `Code Runner`
修改配置
```json title=".vscode/settings.json"
{
"go.gopath": "D:\\devtool\\golang\\gopath",
// goroot 是go的安装路径
"go.goroot": "D:\\devtool\\golang\\go1.25.3"
}
```
记得配置 `GoModule` 的代理
@@ -0,0 +1,36 @@
## golang 同一个包中函数互相调用报错 undefined
demo 文件夹下有两个文件,分别为 hello.go 和 main.go ,结构如下:
```
demo/
├── hello.go
└── main.go
```
文件内容如下:
```go title="hello.go"
package main
import "fmt"
func hello() {
fmt.Println("hello, world")
}
```
```go title="main.go"
package main
func main() {
hello()
}
```
允许代码后报错:./main.go:4:2: undefined: hello
**原因**:Go 中 main 包默认不会加载其他文件, 而其他包都是默认加载的。
**解决方法**:
1. 执行 `go run main.go hello.go`
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@@ -0,0 +1,44 @@
## 介绍
Anaconda 是一个免费、易于安装的包管理器、环境管理器和 Python 发行版,包含 1,500 多个开源包,并提供 免费社区支持。Anaconda 与平台无关,因此无论您在 Windows、macOS 还是 Linux 上都可以使用它。
## 安装
下载地址:https://www.anaconda.com/download/success?reg=skipped
下载 Miniconda 即可
### Windows
下载 exe 文件按照步骤安装即可。
#### 设置环境变量
将 `D:\devtool\anaconda3\condabin` 添加到环境变量中即可
## 常用命令
**创建环境**
```bash
conda create -n myenv python=3.9
```
**激活环境**
```bash
conda activate myenv
```
**退出环境**
```bash
conda deactivate
```
**删除环境**
```bash
conda remove -n myenv --all
```
**查看所有环境**
```bash
conda env list
```
@@ -0,0 +1,73 @@
[飞桨(PaddlePaddle)](https://www.paddlepaddle.org.cn/)以百度多年的深度学习技术研究和业务应用为基础,集深度学习核心训练和推理框架、基础模型库、端到端开发套件、丰富的工具组件于一体,是中国首个自主研发、功能丰富、开源开放的产业级深度学习平台。 飞桨于2016 年正式开源,是主流深度学习框架中一款完全国产化的产品。
ORC 识别能力比较强
## 安装
网站:https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/develop/install/pip/linux-pip.html
安装 GPU 版本:
```bash
python -m pip install paddlepaddle-gpu==3.3.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
```
安装 CPU 版本
```bash
python -m pip install paddlepaddle==3.3.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
```
如果是 **GPU版本** 需要注意自己的 `CUDA` 版本,不要过高即可,查看命令:
```bash
nvidia-smi
```
输出如下:
```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.105.17 Driver Version: 525.105.17 CUDA Version: 12.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla T4 On | 00000000:00:09.0 Off | 0 |
| N/A 27C P8 8W / 70W | 4MiB / 15360MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
```
当前电脑的 CUDA 版本为 12.0,所以下载 小于等于 12.0 版本的 `paddlepaddle` 即可:
```bash
python -m pip install paddlepaddle-gpu==3.1.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
```
检查是否安装成功:
```bash
python -c "import paddle; paddle.utils.run_check()"
```
输出以下内容即代表成功:
```
(ocr) root@VM-0-80-ubuntu:/workspace# python -c "import paddle; paddle.utils.run_check()"
/root/miniforge3/envs/ocr/lib/python3.11/site-packages/paddle/utils/cpp_extension/extension_utils.py:715: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
warnings.warn(warning_message)
Running verify PaddlePaddle program ...
I0710 06:19:32.810492 2651 pir_interpreter.cc:1524] New Executor is Running ...
W0710 06:19:32.813128 2651 gpu_resources.cc:114] Please NOTE: device: 0, GPU Compute Capability: 7.5, Driver API Version: 12.0, Runtime API Version: 11.7
I0710 06:19:35.382279 2651 pir_interpreter.cc:1547] pir interpreter is running by multi-thread mode ...
PaddlePaddle works well on 1 GPU.
PaddlePaddle is installed successfully! Let's start deep learning with PaddlePaddle now.
```
@@ -0,0 +1,124 @@
[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR/blob/main/readme/README_cn.md) 是业界领先、可直接部署的 OCR 与文档智能引擎,提供从文本识别到文档理解的全流程解决方案
> 项目背景:识别集装箱号
## 1 环境配置
当前使用的是虚拟环境:
- python:3.11
- paddlepaddle:3.1
- paddleocr:3.1.0
### 1.1 安装paddlepaddle
参考 [安装paddlepaddle](./01-介绍.md)
### 1.2 下载paddleocr
下载网站:https://github.com/PaddlePaddle/PaddleOCR/releases
当前使用的版本是 3.1.0
下载后解压
```bash
unzip PaddleOCR-3.1.0.zip
```
安装依赖
```bash
cd PaddleOCR-3.1.0
pip install -r requirements.txt --user
```
测试是否能正常运行:
```bash
python tools/infer/predict_system.py --image_dir="/workspace/img/" --use_angle_cls=True --use_space_char=True
```
输出以下内容即成功:
```
ppocr INFO: not find det model file path None
```
## 2 准备数据集
### 2.1 标注工具
1. [**PPOcrLabel**](https://github.com/PFCCLab/PPOCRLabel),专门为 PPOCR 制作的标注工具,**推荐。**
> 存在问题:EXE 安装包运行会报错。但是该工具在本地运行标注的话还是比较推荐的。
2. [**X-AnyLabeling**](https://github.com/CVHub520/X-AnyLabeling),支持多种导出格式,其中就支持 PPOCR 的格式。
### 2.2 标注完毕后的数据集
```bash
conno/1b4e2845-e9ba-4233-9268-bf07801ace0e.jpg [{"transcription": "RKSU5020243", "points": [[233, 317], [299, 317], [258, 833], [181, 839]], "difficult": false}]
conno/6ffd244b-1d27-4084-998b-e4d7ac076c5f.jpg [{"transcription": "ZGXU6173701", "points": [[717, 448], [781, 419], [835, 980], [751, 996]], "difficult": false}]
conno/0ba730a8-052b-4662-88fa-bfd3c7dbd118.jpg [{"transcription": "WHLU5706937", "points": [[565, 567], [915, 485], [915, 551], [578, 635]], "difficult": false}]
conno/8f50bf55-f825-43ac-87a5-f744aa3c2099.jpg [{"transcription": "EISU9420010", "points": [[295, 744], [624, 747], [618, 813], [299, 806]], "difficult": false}]
conno/33e22c52-64b6-4715-87d9-d3a7823b97f7.jpg [{"transcription": "SSKU1302201", "points": [[660, 676], [960, 671], [966, 724], [662, 737]], "difficult": false}]
conno/34a24249-7670-4be2-981f-19c502ee7da2.jpg [{"transcription": "TKRU4507940", "points": [[660, 395], [724, 395], [717, 882], [619, 902]], "difficult": false}]
conno/67ead2d0-89c0-455c-aef0-49a76a3492aa.jpg [{"transcription": "待识别", "points": [[585, 415], [589, 415], [593, 501], [917, 341], [893, 263]], "difficult": false}]
conno/78c58cfa-ff0f-4890-9fd9-07a0b639b9ca.jpg [{"transcription": "LYGU3568255", "points": [[553, 393], [587, 491], [972, 334], [983, 245]], "difficult": false}]
conno/481aee74-f9ce-4145-a8c7-f4c1f45fcc75.jpg [{"transcription": "RKSU4005584", "points": [[56, 298], [19, 935], [101, 937], [115, 280]], "difficult": false}]
conno/630d6e72-f99d-4922-8886-ea14f9e1a9bd.jpg [{"transcription": "FCIU2682384", "points": [[562, 737], [572, 803], [867, 712], [858, 655]], "difficult": false}]
conno/9751b358-0b48-4006-8a73-89e816d37b67.jpg [{"transcription": "CNIU2452605", "points": [[608, 801], [606, 867], [908, 837], [906, 773]], "difficult": false}]
```
## 3 准备预训练模型
如果已经有预训练模型的话,可以忽略这一步。
下载地址:https://github.com/PaddlePaddle/PaddleOCR/blob/release/3.1/docs/version3.x/model_list.md
如果报 404 的话,根据 版本 + 路径 进行查找即可。
根据情况选择 mobile 和 server 模型
- mobile: 训练速度快,精度较低,识别速度快
- server: 训练速度慢,精度较高,识别速度慢
### 3.1 文本检测训练模型
![alt text](assets/1773821823514.png)
### 3.2 文本识别训练模型
![alt text](assets/1773821856182.png)
## 错误情况
### ImportError: libGL.so.1: cannot open shared object file: No such file or directory
原因:缺少 `libGL.so.1` 库
解决方案:
```bash
sudo apt update
sudo apt install libgl1-mesa-glx
```
### all input arrays must have the same shap
原因:图像尺寸不一致
解决方案:
将 batch_size_per_card 设置为 1
```yaml
Eval:
loader:
batch_size_per_card: 1
```
### OSError: cannot open resource
原因:字体路径无效
解决方案:将paddleocr里面的字体放到系统字体路径下
```bash
cp /workspace/PaddleOCR-3.1.0/doc/fonts/simfang.ttf /usr/share/fonts/
```
@@ -0,0 +1,430 @@
[PaddleX 3.0](https://paddlepaddle.github.io/PaddleX/latest/index.html) 是基于飞桨框架构建的低代码开发工具,它集成了众多**开箱即用的预训练模型**,可以实现模型从训练到推理的**全流程开发**,支持国内外**多款主流硬件**,助力AI 开发者进行产业实践。
## 1 环境配置
当前使用的是虚拟环境:
- python:3.11
- paddlepaddle:3.1
- paddleocr:3.1.0
### 1.1 安装paddlepaddle
参考 [安装paddlepaddle](./01-介绍.md)
### 1.2 安装paddlex
```bash
pip install "paddlex[base]"
```
## 2 部署项目
参考文档:https://paddlepaddle.github.io/PaddleX/latest/pipeline_deploy/serving.html#12
### 2.1 安装服务化部署插件
方便 java 等语言接口的调用
```bash
paddlex --install serving
```
### 2.2 生成配置文件
使用相关命令,其中 OCR 当前为通用 OCR 产线,需要不同的产线就修改不同的名称即可。
```bash
paddlex --get_pipeline_config OCR --save_path ./OCR.yaml
```
生成成功会提示
```bash
The pipeline config has been saved to: OCR.yaml
```
生成的默认配置如下:
```yaml
pipeline_name: OCR
text_type: general
use_doc_preprocessor: True
use_textline_orientation: True
SubPipelines:
DocPreprocessor:
pipeline_name: doc_preprocessor
use_doc_orientation_classify: True
use_doc_unwarping: True
SubModules:
DocOrientationClassify:
module_name: doc_text_orientation
model_name: PP-LCNet_x1_0_doc_ori
model_dir: null
DocUnwarping:
module_name: image_unwarping
model_name: UVDoc
model_dir: null
SubModules:
TextDetection:
module_name: text_detection
model_name: PP-OCRv5_server_det
model_dir: null
limit_side_len: 64
limit_type: min
max_side_limit: 4000
thresh: 0.3
box_thresh: 0.6
unclip_ratio: 1.5
TextLineOrientation:
module_name: textline_orientation
model_name: PP-LCNet_x1_0_textline_ori
model_dir: null
batch_size: 6
TextRecognition:
module_name: text_recognition
model_name: PP-OCRv5_server_rec
model_dir: null
batch_size: 6
score_thresh: 0.0
```
**修改配置文件**
注意将训练好的模型路径配置 `./pipeline/rec_inference` 和 `./pipeline/det_inference`
```yaml
# 整体 pipeline 名称,用于识别产线名称
pipeline_name: OCR
# 文本类型,可选 general(通用)或 others,决定一些后处理策略
text_type: general
# 是否使用文档预处理模块(方向分类 + 扭曲矫正)
# 如无严重倾斜/扫描件,建议设为 False,可显著提升速度
use_doc_preprocessor: False
# 是否对检测出的文本行进行角度分类(如 0° / 90° / 180°)
# mobile 模型一般建议关闭
use_textline_orientation: False
# 正式的 OCR 主流程模块
SubModules:
# 文本检测模块(通常是基于 DB 的检测器)
TextDetection:
module_name: text_detection
model_name: PP-OCRv5_server_det # 使用的是 server 版大模型,精度高但速度慢
model_dir: ./pipeline/det_inference # 本地模型文件夹路径(需包含 model.pdmodel 等)
limit_side_len: 64 # 输入图最短边 resize 到此尺寸(可适当调大提高效果)
limit_type: min
max_side_limit: 4000 # 最长边最大不超过此值
thresh: 0.3 # 检测 binarize 阈值
box_thresh: 0.6 # 文本框置信度阈值
unclip_ratio: 1.5 # DB 算法的后处理参数,控制框扩大比例
# 文本识别模块(通常是 CRNN + CTC 或 SVTR 模型)
TextRecognition:
module_name: text_recognition
model_name: PP-OCRv5_server_rec # 同样使用的是 server 版识别模型
model_dir: ./pipeline/rec_inference
batch_size: 6 # 一次识别图块的数量,适当调大可提高 GPU 利用率
score_thresh: 0.0 # 识别结果置信度下限,低于此不输出
```
### 2.3 运行服务器
通过 PaddleX CLI 运行服务器:
```bash
paddlex --serve --pipeline {产线名称或产线配置文件路径} [{其他命令行选项}]
```
参考命令:
```bash
paddlex --serve --pipeline .\OCR.yaml --device gpu:0 --port 8866
```
可以看到类似以下展示的信息,即代表成功
```
INFO: Started server process [63108]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
```
### 2.4 调用服务
对于服务提供的主要操作:
- HTTP请求方法为POST。
- 请求体和响应体均为JSON数据(JSON对象)。
- 当请求处理成功时,响应状态码为`200`,响应体的属性如下:
| 名称 | 类型 | 含义 |
| :---------- | :-------- | :---------------------------- |
| `logId` | `string` | 请求的UUID。 |
| `errorCode` | `integer` | 错误码。固定为`0`。 |
| `errorMsg` | `string` | 错误说明。固定为`"Success"`。 |
| `result` | `object` | 操作结果。 |
- 当请求处理未成功时,响应体的属性如下:
| 名称 | 类型 | 含义 |
| :---------- | :-------- | :------------------------- |
| `logId` | `string` | 请求的UUID。 |
| `errorCode` | `integer` | 错误码。与响应状态码相同。 |
| `errorMsg` | `string` | 错误说明。 |
服务提供的主要操作如下:
- **`infer`**
获取图像OCR结果。
```
POST /ocr
```
- 请求体的属性如下:
| 名称 | 类型 | 含义 | 是否必填 |
| :-------------------------- | :-------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| `file` | `string` | 服务器可访问的图像文件或PDF文件的URL,或上述类型文件内容的Base64编码结果。默认对于超过10页的PDF文件,只有前10页的内容会被处理。 要解除页数限制,请在产线配置文件中添加以下配置:`Serving: extra: max_num_input_imgs: null ` | 是 |
| `fileType` | `integer` | `null` | 文件类型。`0`表示PDF文件,`1`表示图像文件。若请求体无此属性,则将根据URL推断文件类型。 |
| `visualize` | `boolean` | `null` | 是否返回可视化结果图以及处理过程中的中间图像等。传入 `true`:返回图像。传入 `false`:不返回图像。若请求体中未提供该参数或传入 `null`:遵循产线配置文件`Serving.visualize` 的设置。 例如,在产线配置文件中添加如下字段: `Serving: visualize: False `将默认不返回图像,通过请求体中的`visualize`参数可以覆盖默认行为。如果请求体和配置文件中均未设置(或请求体传入`null`、配置文件中未设置),则默认返回图像。 |
| `useDocOrientationClassify` | `boolean` | `null` | 请参阅产线对象中 `predict` 方法的 `use_doc_orientation_classify` 参数相关说明。 |
| `useDocUnwarping` | `boolean` | `null` | 请参阅产线对象中 `predict` 方法的 `use_doc_unwarping` 参数相关说明。 |
| | | | |
| `useTextlineOrientation` | `boolean` | `null` | 请参阅产线对象中 `predict` 方法的 `use_textline_orientation` 参数相关说明。 |
| `textDetLimitSideLen` | `integer` | `null` | 请参阅产线对象中 `predict` 方法的 `text_det_limit_side_len` 参数相关说明。 |
| `textDetLimitType` | `string` | `null` | 请参阅产线对象中 `predict` 方法的 `text_det_limit_type` 参数相关说明。 |
| `textDetThresh` | `number` | `null` | 请参阅产线对象中 `predict` 方法的 `text_det_thresh` 参数相关说明。 |
| `textDetBoxThresh` | `number` | `null` | 请参阅产线对象中 `predict` 方法的 `text_det_box_thresh` 参数相关说明。 |
| `textDetUnclipRatio` | `number` | `null` | 请参阅产线对象中 `predict` 方法的 `text_det_unclip_ratio` 参数相关说明。 |
| `textRecScoreThresh` | `number` | `null` | 请参阅产线对象中 `predict` 方法的 `text_rec_score_thresh` 参数相关说明。 |
- 请求处理成功时,响应体的`result`具有如下属性:
| 名称 | 类型 | 含义 |
| :----------- | :------- | :----------------------------------------------------------- |
| `ocrResults` | `object` | OCR结果。数组长度为1(对于图像输入)或实际处理的文档页数(对于PDF输入)。对于PDF输入,数组中的每个元素依次表示PDF文件中实际处理的每一页的结果。 |
| `dataInfo` | `object` | 输入数据信息。 |
`ocrResults`中的每个元素为一个`object`,具有如下属性:
| 名称 | 类型 | 含义 |
| :---------------------- | :------- | :----------------------------------------------------------- |
| `prunedResult` | `object` | 产线对象的 `predict` 方法生成结果的 JSON 表示中 `res` 字段的简化版本,其中去除了 `input_path` 和 `page_index` 字段。 |
| `ocrImage` | `string` | `null` |
| `docPreprocessingImage` | `string` | `null` |
| `inputImage` | `string` | `null` |
**Java调用实例**
```java
package cn.g3soft;
import okhttp3.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
public class Test {
public static void main(String[] args) throws IOException {
String API_URL = "http://localhost:8866/ocr";
String imagePath = "D:\\code\\python-project\\boxocr\\100-2\\20241004082017A007.jpg";
// 压缩并限制最大500KB大小
long maxSizeBytes = 500 * 1024;
long compressStart = System.currentTimeMillis();
byte[] compressedBytes = compressImageToMaxSize(imagePath, maxSizeBytes);
long compressEnd = System.currentTimeMillis();
System.out.println("Image compression time: " + (compressEnd - compressStart) + " ms");
System.out.println("Compressed image size: " + compressedBytes.length + " bytes");
String base64Image = Base64.getEncoder().encodeToString(compressedBytes);
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode payload = objectMapper.createObjectNode();
payload.put("file", base64Image);
payload.put("fileType", 1);
OkHttpClient client = new OkHttpClient();
MediaType JSON = MediaType.get("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSON, payload.toString());
long ocrStart = System.currentTimeMillis();
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
long ocrEnd = System.currentTimeMillis();
System.out.println("OCR request elapsed time: " + (ocrEnd - ocrStart) + " ms");
if (response.isSuccessful()) {
String responseBody = response.body().string();
JsonNode root = objectMapper.readTree(responseBody);
JsonNode result = root.get("result");
JsonNode ocrResults = result.get("ocrResults");
for (int i = 0; i < ocrResults.size(); i++) {
JsonNode item = ocrResults.get(i);
JsonNode prunedResult = item.get("prunedResult");
System.out.println("Pruned Result [" + i + "]: " + prunedResult.toString());
// 提取 rec_texts 和 rec_scores
JsonNode recTextsNode = prunedResult.get("rec_texts");
JsonNode recScoresNode = prunedResult.get("rec_scores");
if (recTextsNode != null && recScoresNode != null && recTextsNode.isArray() && recScoresNode.isArray()) {
System.out.println("rec_texts:");
for (JsonNode textNode : recTextsNode) {
System.out.println(" " + textNode.asText());
}
System.out.println("rec_scores:");
for (JsonNode scoreNode : recScoresNode) {
System.out.println(" " + scoreNode.asDouble());
}
} else {
System.out.println("rec_texts or rec_scores not found or invalid format.");
}
// 保存 OCR 图片为文件
String ocrImageBase64 = item.get("ocrImage").asText();
byte[] ocrImageBytes = Base64.getDecoder().decode(ocrImageBase64);
String ocrImgPath = "ocr_result_" + i + ".jpg";
try (FileOutputStream fos = new FileOutputStream(ocrImgPath)) {
fos.write(ocrImageBytes);
System.out.println("Saved OCR image to: " + ocrImgPath);
}
}
} else {
System.err.println("Request failed with HTTP code: " + response.code());
}
}
}
/**
* 压缩图片,最大限制文件大小,不超过maxFileSizeBytes
* 通过递减压缩质量尝试实现大小限制,最低质量0.1
*/
public static byte[] compressImageToMaxSize(String imagePath, long maxFileSizeBytes) throws IOException {
File file = new File(imagePath);
BufferedImage image = ImageIO.read(file);
if (image == null) {
throw new IOException("Failed to read image from " + imagePath);
}
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
float quality = 0.9f;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (quality >= 0.1f) {
baos.reset();
jpgWriteParam.setCompressionQuality(quality);
try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
jpgWriter.setOutput(ios);
jpgWriter.write(null, new IIOImage(image, null, null), jpgWriteParam);
}
if (baos.size() <= maxFileSizeBytes) {
jpgWriter.dispose();
return baos.toByteArray();
}
quality -= 0.05f;
}
// 质量降至最低仍未达到限制,返回最后压缩结果
jpgWriter.dispose();
return baos.toByteArray();
}
}
```
## 错误情况
### Please use PaddlePaddle with GPU version.
原因:当前 PaddlePaddle 版本不是GPU的,而是CPU的。
解决方法:安装GPU版本的PaddlePaddle
### ImportError:DLL load failed while importing cv2:找不到指定的模块
当前环境:Windows Server 2012
**安装 Microsoft Visual C++ Redistributable**
- OpenCV 依赖于 Microsoft Visual C++ Redistributable 运行时库。如果这些库缺失,可能会导致 DLL 加载失败。
- 下载并安装最新版本的 Microsoft Visual C++ Redistributable:
- [Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019(64 位系统)](https://aka.ms/vs/16/release/vc_redist.x64.exe)
- [Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019(32 位系统)](https://aka.ms/vs/16/release/vc_redist.x86.exe)
**检查 Python 和 OpenCV 的位数是否匹配**
- 确保你安装的 Python 版本(32 位或 64 位)与 OpenCV 的位数一致。
- 你可以通过以下命令检查 Python 的位数:
```bash
python -c "import struct; print(struct.calcsize('P') * 8)"
```
- 如果不匹配,卸载并重新安装正确位数的 Python 和 OpenCV。
安装完成后,重启计算机。
**一定要打开桌面实验**
1. 打开服务器面板,选择 **添加角色和功能**
![alt text](assets/1773823099348.png)
2. 在功能处开启 **桌面体验**
![alt text](assets/1773823189917.png)
如果开启 桌面体验 报错:**尚未开启 WinRM 服务**, 这个时候需要开启 `Windows Remote Management (WS-Management) `
![alt text](assets/1773823507355.png)
如果在开启过程中报错:**错误1068:依存服务或组无法启动**
点击属性,找到 **依存关系**,确保依赖的服务已开启
![alt text](assets/1773823676516.png)
检查 `HTTP Service` 服务是否启动
```bash
sc query http
```
如果出现 `STATE : 1 STOPPED` ,那么就代表该服务已被禁用,解决方案如下:
1. 启用 HTTP 服务
```bash
sc config http start= auto
```
2. 启动 HTTP
```bash
net start http
```
3. 验证,应该输出 `STATE : RUNNING`
```bash
sc query http
```
4. 重建 WinRM(必须)
```bash
winrm invoke Restore winrm/Config @{}
winrm quickconfig -q
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@@ -0,0 +1,9 @@
[React Native](https://reactnative.dev/) 是一个开源框架,用于构建跨平台的移动应用。它允许开发者使用 React 来构建原生的 iOS 和 Android 应用。
主要特点:
- 跨平台开发:通过一次编写代码,React Native 可以在 iOS 和 Android 上运行,大大减少开发时间和成本。
- 原生性能:React Native 使用原生组件(如按钮、文本框等),提供接近原生应用的性能和用户体验。
- 热重载:开发者可以实时查看代码修改的效果,而无需重新加载整个应用。
- 组件化开发:通过 React 的组件化理念,开发者可以更高效地构建和维护应用界面。
- 丰富的生态系统:React Native 拥有大量的第三方库和工具,帮助开发者快速实现功能。
@@ -0,0 +1,8 @@
[Expo](https://docs.expo.dev/) 是一个基于 React Native 的框架,旨在简化移动应用开发。它提供了一套工具和服务,让开发者可以更快速地构建、测试和发布 React Native 应用。
主要特点:
- 快速上手:无需复杂配置,直接在手机上查看代码效果。
- 内置功能:相机、位置服务、推送通知等常用功能,免去手动集成。
- 跨平台支持:同一套代码可在 iOS 和 Android 上运行。
- 热重载:修改代码后,应用会即时更新,提升开发效率。
@@ -0,0 +1,22 @@
创建项目命令:
```bash
pnpm create expo-app@latest --template blank-typescript
```
[官网模板](https://docs.expo.dev/more/create-expo/) 如下:
| 模板名称 | 描述 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`default`](https://github.com/expo/expo/tree/main/templates/expo-template-default) | 默认模板,用于构建多页面应用。包含推荐工具,如 **Expo CLI**、**Expo Router** 路由库,并启用 **TypeScript** 配置。适合大多数应用。 |
| [`blank`](https://github.com/expo/expo/tree/main/templates/expo-template-blank) | 最简模板,仅安装最基本依赖,不包含导航配置。 |
| [`blank-typescript`](https://github.com/expo/expo/tree/main/templates/expo-template-blank-typescript) | 空白模板,但启用了 **TypeScript** 支持。 |
| [`tabs`](https://github.com/expo/expo/tree/main/templates/expo-template-tabs) | 启用基于文件的路由系统(Expo Router),并默认使用 **TypeScript**,适合多标签页结构的应用。 |
| [`bare-minimum`](https://github.com/expo/expo/tree/main/templates/expo-template-bare-minimum) | 带有原生目录(`android` 与 `ios`)的空白模板,创建时会自动运行 [`npx expo prebuild`](https://docs.expo.dev/workflow/prebuild)。适合需要直接修改原生代码的项目。 |
**启动项目:**
```bash
npx expo start
```
@@ -0,0 +1,166 @@
**生成基础文件**,后面要用到:
```bash
npx expo customize babel.config.js
npx expo customize metro.config.js
```
## 配置eslint格式化
可以使用快捷命令(推荐):
```bash
pnpm dlx @antfu/eslint-config@latest
```
安装:
```bash
pnpm i -D eslint @antfu/eslint-config
```
新建 `eslint.config.mjs` 文件:
```js
import antfu from '@antfu/eslint-config'
export default antfu({
stylistic: {
indent: 2, // 缩进为 2 个空格(可选 4 或 'tab')
quotes: 'single', // 使用单引号(可选 'double')
},
rules: {
'unused-imports/no-unused-imports': 'warn',
'unused-imports/no-unused-vars': 'warn',
'@typescript-eslint/no-use-before-define': 'off', // 关闭 TS 的“定义前使用”警告
'no-console': 'off', // 关闭 console 报错
},
})
```
配置 vscode 模板,修改 `.vscode/settings.json` :
> 注意安装 eslint 插件
```json
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}
```
## 配置深度链接
作用:通过链接就可以跳转到该app。
在 `app.json` 文件下进行配置:
```json
{
"expo": {
"scheme": "oneao"
}
}
```
然后就可以通过这个配置 从别的应用或者浏览器跳转到你的app:
```
oneao://courses/react-native
```
## 定义 src 路径别名 @
> 参考:https://docs.expo.dev/guides/typescript/
修改 `tsconfig.json` 文件:
```json
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
"strict": true
}
}
```
安装 `module-resolver` :
```
pnpm add -D babel-plugin-module-resolver
```
修改 `babel.config.js` :
```js
module.exports = function (api) {
api.cache(true)
return {
presets: [
['babel-preset-expo', { jsxImportSource: 'nativewind' }],
'nativewind/babel',
],
plugins: [
[
'module-resolver',
{
root: ['./src'],
alias: {
'@': './src',
},
},
],
],
}
}
```
@@ -0,0 +1,359 @@
## 云打包
1. 安装 EAS CLI
```bash
npm install -g eas-cli
```
2. 注册并登录 Expo 账户
- 访问 https://expo.dev/ 注册账户,然后命令行登录:
```bash
expo login
```
3. 配置项目构建
- 输入以下命令,选择 Android 平台即可。
```bash
eas build:configure
```
4. 构建 Android 包
- 默认构建 AAB 包(上传 Google Play):
```bash
eas build --platform android
```
- 构建 APK(可直接安装):
```bash
eas build -p android --profile preview
```
## 本地打包(EAS方式)
## 本地打包(原生方式)
### 1. 安装 [Android Studio]( https://developer.android.com/?hl=zh-cn)
1. 下载安装
- 按照官网提示依次安装 SDK 工具和必要组件。
- 安装完成后,记住 SDK 的安装路径(例如:`D:\data\sdk`,默认位置是:`C:\Users\<你的用户名>\AppData\Local\Android\Sdk`),后续需要用到。
2. 配置环境变量
- 打开 **系统属性 → 高级 → 环境变量**。
- 在 **系统变量** 中新增:
```
变量名:ANDROID_HOME
变量值:D:\data\sdk
```
- 在 **Path** 中新增:
```bash
%ANDROID_HOME%\platform-tools
%ANDROID_HOME%\tools
%ANDROID_HOME%\tools\bin
```
- 保存设置。
3. 验证安装
- 打开命令行,执行:
```
echo %ANDROID_HOME%
```
- 如果输出 SDK 路径,则说明配置成功。
### 2. 安装 [jdk17](https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any)
1. 下载安装
- 下载对应版本解压即可。
- 安装成功后,记住 jdk 的安装路径,后续需要用到。
2. 配置环境变量
- 打开 **系统属性 → 高级 → 环境变量**。
- 在 **系统变量** 中新增:
```bash
变量名:JAVA_HOME
变量值:D:\devtool\jdk\jdk-17.0.16+8
```
- 在 **Path** 中新增:
```bash
%JAVA_HOME%\bin
```
- 保存设置。
3. 验证安装
- 打开命令行,执行:
```bash
java --version
```
- 如果输出 jdk 的信息,则说明配置成功。
### 3. Expo 项目启用 [Prebuild](https://docs.expo.dev/workflow/prebuild/)
1. 生成原生项目
```bash
npx expo prebuild
```
然后执行完毕后,会生成 `android` 目录。
2. 清除并重新生成原生项目
```bash
npx expo prebuild --clean
```
会删除已有的 `android` 和 `ios` 目录,然后重新生成。
### 4. 配置 Keystore
#### 4.1 生成密钥
```bash
keytool -genkey -v -keystore android-release.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
```
说明:
- `my-release-key.keystore`:生成的密钥文件名,可自定义路径
- `my-key-alias`:密钥别名
- `RSA`:加密算法
- `2048`:密钥长度
- `10000`:有效期(天)
#### 4.2 手动配置
修改 `android/app/build.gradle` 文件
1. 修改 `signingConfigs`
```bash
signingConfigs {
release {
storeFile file('android-release.keystore') // keystore 文件路径
storePassword '你的Keystore密码' // keystore 密码
keyAlias '你的KeyAlias' // 密钥别名
keyPassword '你的Key密码' // key 密码
}
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
```
2. 在 `buildTypes` 中设置 release 使用 release 签名
```bash
buildTypes {
release {
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.debug
}
}
```
#### 4.3 脚本配置(推荐)
1. 在 expo 项目根目录下新增 `plugins\withAndroidSignature.js` 文件,内容如下:
```js
// plugins/withAndroidSignature.js
const { withAppBuildGradle } = require("@expo/config-plugins");
const fs = require("fs");
const path = require("path");
module.exports = function withAndroidSignature(config) {
return withAppBuildGradle(config, config => {
if (config.modResults.language === "groovy") {
config.modResults.contents = setAndroidSignature(config.modResults.contents);
} else {
throw new Error("如果不是 groovy,则无法在 app/build.gradle 中设置 signingConfigs");
}
return config;
});
};
function setAndroidSignature(appBuildGradle) {
if (!fs.existsSync(path.resolve(__dirname, "../credentials.json"))) {
console.warn("警告:没有设置正式版本的 Android Keystore 文件,因为 credentials.json 不存在。");
return appBuildGradle;
}
const info = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../credentials/credentials.json"), { encoding: "utf8" }));
// 使用正则表达式插入签名信息
let output = appBuildGradle.replace(
/(signingConfigs\s*\{)/,
`$1
release {
storeFile file(${JSON.stringify(path.resolve(__dirname, "../credentials/android-release.keystore"))})
storePassword ${JSON.stringify(info.android.keystore.keystorePassword)}
keyAlias ${JSON.stringify(info.android.keystore.keyAlias)}
keyPassword ${JSON.stringify(info.android.keystore.keyPassword)}
}`,
);
// 使用正则表达式替换 signingConfig
output = output.replace(
/(release\s*\{)[^}]*?signingConfig\s+signingConfigs\.debug/s,
`$1
signingConfig signingConfigs.release
`,
);
return output;
}
```
2. 在 expo 项目根目录下新增 `/credentials/credentials.json` 文件(该文件主要是 Keystore 的信息):
```json
{
"android": {
"keystore": {
"keystorePath": "credentials/android-release.keystore", // Android keystore 文件路径
"keystorePassword": "123456", // keystore 密码
"keyAlias": "my-key-alias", // Key 别名
"keyPassword": "123456" // Key 密码
}
},
"ios": {
"provisioningProfilePath": "ios/certs/profile.mobileprovision", // iOS 描述文件路径
"distributionCertificate": {
"path": "ios/certs/dist-cert.p12", // iOS 分发证书路径
"password": "password" // 证书密码
}
}
}
```
3. 在 `app.json` 中指定这个项目级插件:
```json
{
"expo": {
"plugins": [
"./plugins/withAndroidSignature"
]
}
}
```
### 5. 打包
- 编译成 Google Play 商店用的 .aab 文件
```bash
./gradlew bundleRelease
```
- 直接安装的 .apk 文件
```bash
./gradlew assembleRelease
```
**注意**:这个时候可能会下载 `gradle` 、`apk` 等资源,网络速度可能过慢。
**解决方法**:在 `android/gradle.properties` 添加网络代理:
```bash
systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=7890
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=7890
```
打包结果在 `android/app/build/outputs/apt/release` 包下。
## 打包体积优化
#### 方法1(简单)
找到 `android/gradle.properties` 文件,找到 `reactNativeArchitectures` ,根据需要删除即可
```properties
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
```
#### 方法2(原生方法 选择更多)
在 `android/app/build.gradle` 文件中添加或修改以下配置:
```
android {
// 其他配置...
splits {
abi {
enable true // 启用按 CPU 架构拆分
reset() // 重置默认架构列表
include 'arm64-v8a', 'armeabi-v7a'
universalApk false // 是否生成包含所有架构的通用 APK(false 表示只生成分架构的独立包)
// 还有一个 exclude 配置是排除指定架构的
}
}
// 其他配置...
}
```
**说明:**
- `enable true`:启用架构拆分功能。
- `reset()`:清空默认的架构配置,避免重复。
- `include`:指定要生成的架构包,比如只打 `arm64-v8a` 和 `armeabi-v7a`。
- `universalApk false`:不生成通用包(即包含所有架构的 APK)。
**举例:**
执行打包命令后,将生成多个包,例如:
```
app-arm64-v8a-release.apk
app-armeabi-v7a-release.apk
```
每个 APK 只包含对应架构的二进制文件,体积更小。
如果把 `universalApk` 设置为 `true`,则只会生成一个:
```
app-universal-release.apk
```
这个包能在 `arm64-v8a` 和 `armeabi-v7a` 架构的设备上运行,但体积最大。
@@ -0,0 +1,7 @@
{
"label": "expo",
"position": 1,
"link": {
"type": "generated-index"
}
}
@@ -0,0 +1,6 @@
有很多地方下载依赖使用的命令是:
```bash
npx expo add xxx
```
使用这种的方式只是为了兼容 expo 项目,如果没用 expo 的话,将命令修改为现在使用的 `pnpm add xxx`,`npm i xxx` 等都可以
@@ -0,0 +1,109 @@
NativeWind 原子化 CSS 库
> 官网:https://www.nativewind.dev/docs/getting-started/installation
1. 安装依赖
```bash
npx expo add nativewind react-native-reanimated react-native-safe-area-context
npx expo add tailwindcss@^3.4.17 -- --save-dev
```
2. 运行 `npx tailwindcss init` 生成 `tailwind.config.js` 文件,添加配置:
```js
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all files that contain Nativewind classes.
content: ['./App.tsx', './components/**/*.{js,jsx,ts,tsx}'],
presets: [require('nativewind/preset')],
theme: {
extend: {},
},
plugins: [],
}
```
3. 创建 `global.css` 文件:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
注意在全局引入
4. 修改 `babel.config.js` 文件:
> 如果没有该文件,执行 `npx expo customize babel.config.js` 命令创建。
```js
module.exports = function (api) {
api.cache(true)
return {
presets: [
['babel-preset-expo', { jsxImportSource: 'nativewind' }],
'nativewind/babel',
],
}
}
```
5. 修改 `metro.config.js` 文件:
> 如果没有该文件,执行 `npx expo customize metro.config.js` 命令创建。
```js
const { getDefaultConfig } = require('expo/metro-config')
const { withNativeWind } = require('nativewind/metro')
const config = getDefaultConfig(__dirname)
module.exports = withNativeWind(config, { input: './global.css' })
```
6. 新建 `src/types/nativewind-env.d.ts` 文件:
```ts
/// <reference types="nativewind/types" />
```
7. 安装 ` react-native-css-interop` :
```bash
npx expo install react-native-css-interop
```
8. 检验是否生效
```tsx
import { Text, View } from 'react-native'
import './global.css'
export default function App() {
return (
<View className="flex-1 items-center justify-center bg-white">
<Text className="text-xl font-bold text-blue-500">
Welcome to Nativewind!
</Text>
</View>
)
}
```
如果不生效,记得修改 `tailwind.config.js` 的目标路径:
```js
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all files that contain Nativewind classes.
content: ['./src/app/_layout.tsx', './src/components/**/*.{js,jsx,ts,tsx}'],
presets: [require('nativewind/preset')],
theme: {
extend: {},
},
plugins: [],
}
```
@@ -0,0 +1,290 @@
Gluestack UI UI 组件库
> 官网:https://gluestack.io/ui/docs/home/getting-started/installation
## 方式一:CLI
```bash
npx gluestack-ui init
```
## 方式二:Manual(推荐)
**前置条件:** 需要安装 `nativewind`
1. 安装依赖:
```bash
npx expo add @gluestack-ui/core @gluestack-ui/utils react-native-svg @gluestack/ui-next-adapter
```
2. 从 [github](https://github.com/gluestack/gluestack-ui/tree/main/src/components/ui/gluestack-ui-provider) 复制必须的组件到 `@/components/ui/gluestack-ui-provider`。
3. 修改 `tailwind.config.js` 文件:
```bash
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: process.env.DARK_MODE ? process.env.DARK_MODE : 'class',
content: [
'./app/**/*.{html,js,jsx,ts,tsx,mdx}',
'./components/**/*.{html,js,jsx,ts,tsx,mdx}',
'./utils/**/*.{html,js,jsx,ts,tsx,mdx}',
'./*.{html,js,jsx,ts,tsx,mdx}',
'./src/**/*.{html,js,jsx,ts,tsx,mdx}',
],
presets: [require('nativewind/preset')],
important: 'html',
safelist: [
{
pattern:
// eslint-disable-next-line regexp/no-dupe-disjunctions
/(bg|border|text|stroke|fill)-(primary|secondary|tertiary|error|success|warning|info|typography|outline|background|indicator)-(0|50|100|200|300|400|500|600|700|800|900|950|white|gray|black|error|warning|muted|success|info|light|dark|primary)/,
},
],
theme: {
extend: {
colors: {
primary: {
0: 'rgb(var(--color-primary-0)/<alpha-value>)',
50: 'rgb(var(--color-primary-50)/<alpha-value>)',
100: 'rgb(var(--color-primary-100)/<alpha-value>)',
200: 'rgb(var(--color-primary-200)/<alpha-value>)',
300: 'rgb(var(--color-primary-300)/<alpha-value>)',
400: 'rgb(var(--color-primary-400)/<alpha-value>)',
500: 'rgb(var(--color-primary-500)/<alpha-value>)',
600: 'rgb(var(--color-primary-600)/<alpha-value>)',
700: 'rgb(var(--color-primary-700)/<alpha-value>)',
800: 'rgb(var(--color-primary-800)/<alpha-value>)',
900: 'rgb(var(--color-primary-900)/<alpha-value>)',
950: 'rgb(var(--color-primary-950)/<alpha-value>)',
},
secondary: {
0: 'rgb(var(--color-secondary-0)/<alpha-value>)',
50: 'rgb(var(--color-secondary-50)/<alpha-value>)',
100: 'rgb(var(--color-secondary-100)/<alpha-value>)',
200: 'rgb(var(--color-secondary-200)/<alpha-value>)',
300: 'rgb(var(--color-secondary-300)/<alpha-value>)',
400: 'rgb(var(--color-secondary-400)/<alpha-value>)',
500: 'rgb(var(--color-secondary-500)/<alpha-value>)',
600: 'rgb(var(--color-secondary-600)/<alpha-value>)',
700: 'rgb(var(--color-secondary-700)/<alpha-value>)',
800: 'rgb(var(--color-secondary-800)/<alpha-value>)',
900: 'rgb(var(--color-secondary-900)/<alpha-value>)',
950: 'rgb(var(--color-secondary-950)/<alpha-value>)',
},
tertiary: {
50: 'rgb(var(--color-tertiary-50)/<alpha-value>)',
100: 'rgb(var(--color-tertiary-100)/<alpha-value>)',
200: 'rgb(var(--color-tertiary-200)/<alpha-value>)',
300: 'rgb(var(--color-tertiary-300)/<alpha-value>)',
400: 'rgb(var(--color-tertiary-400)/<alpha-value>)',
500: 'rgb(var(--color-tertiary-500)/<alpha-value>)',
600: 'rgb(var(--color-tertiary-600)/<alpha-value>)',
700: 'rgb(var(--color-tertiary-700)/<alpha-value>)',
800: 'rgb(var(--color-tertiary-800)/<alpha-value>)',
900: 'rgb(var(--color-tertiary-900)/<alpha-value>)',
950: 'rgb(var(--color-tertiary-950)/<alpha-value>)',
},
error: {
0: 'rgb(var(--color-error-0)/<alpha-value>)',
50: 'rgb(var(--color-error-50)/<alpha-value>)',
100: 'rgb(var(--color-error-100)/<alpha-value>)',
200: 'rgb(var(--color-error-200)/<alpha-value>)',
300: 'rgb(var(--color-error-300)/<alpha-value>)',
400: 'rgb(var(--color-error-400)/<alpha-value>)',
500: 'rgb(var(--color-error-500)/<alpha-value>)',
600: 'rgb(var(--color-error-600)/<alpha-value>)',
700: 'rgb(var(--color-error-700)/<alpha-value>)',
800: 'rgb(var(--color-error-800)/<alpha-value>)',
900: 'rgb(var(--color-error-900)/<alpha-value>)',
950: 'rgb(var(--color-error-950)/<alpha-value>)',
},
success: {
0: 'rgb(var(--color-success-0)/<alpha-value>)',
50: 'rgb(var(--color-success-50)/<alpha-value>)',
100: 'rgb(var(--color-success-100)/<alpha-value>)',
200: 'rgb(var(--color-success-200)/<alpha-value>)',
300: 'rgb(var(--color-success-300)/<alpha-value>)',
400: 'rgb(var(--color-success-400)/<alpha-value>)',
500: 'rgb(var(--color-success-500)/<alpha-value>)',
600: 'rgb(var(--color-success-600)/<alpha-value>)',
700: 'rgb(var(--color-success-700)/<alpha-value>)',
800: 'rgb(var(--color-success-800)/<alpha-value>)',
900: 'rgb(var(--color-success-900)/<alpha-value>)',
950: 'rgb(var(--color-success-950)/<alpha-value>)',
},
warning: {
0: 'rgb(var(--color-warning-0)/<alpha-value>)',
50: 'rgb(var(--color-warning-50)/<alpha-value>)',
100: 'rgb(var(--color-warning-100)/<alpha-value>)',
200: 'rgb(var(--color-warning-200)/<alpha-value>)',
300: 'rgb(var(--color-warning-300)/<alpha-value>)',
400: 'rgb(var(--color-warning-400)/<alpha-value>)',
500: 'rgb(var(--color-warning-500)/<alpha-value>)',
600: 'rgb(var(--color-warning-600)/<alpha-value>)',
700: 'rgb(var(--color-warning-700)/<alpha-value>)',
800: 'rgb(var(--color-warning-800)/<alpha-value>)',
900: 'rgb(var(--color-warning-900)/<alpha-value>)',
950: 'rgb(var(--color-warning-950)/<alpha-value>)',
},
info: {
0: 'rgb(var(--color-info-0)/<alpha-value>)',
50: 'rgb(var(--color-info-50)/<alpha-value>)',
100: 'rgb(var(--color-info-100)/<alpha-value>)',
200: 'rgb(var(--color-info-200)/<alpha-value>)',
300: 'rgb(var(--color-info-300)/<alpha-value>)',
400: 'rgb(var(--color-info-400)/<alpha-value>)',
500: 'rgb(var(--color-info-500)/<alpha-value>)',
600: 'rgb(var(--color-info-600)/<alpha-value>)',
700: 'rgb(var(--color-info-700)/<alpha-value>)',
800: 'rgb(var(--color-info-800)/<alpha-value>)',
900: 'rgb(var(--color-info-900)/<alpha-value>)',
950: 'rgb(var(--color-info-950)/<alpha-value>)',
},
typography: {
0: 'rgb(var(--color-typography-0)/<alpha-value>)',
50: 'rgb(var(--color-typography-50)/<alpha-value>)',
100: 'rgb(var(--color-typography-100)/<alpha-value>)',
200: 'rgb(var(--color-typography-200)/<alpha-value>)',
300: 'rgb(var(--color-typography-300)/<alpha-value>)',
400: 'rgb(var(--color-typography-400)/<alpha-value>)',
500: 'rgb(var(--color-typography-500)/<alpha-value>)',
600: 'rgb(var(--color-typography-600)/<alpha-value>)',
700: 'rgb(var(--color-typography-700)/<alpha-value>)',
800: 'rgb(var(--color-typography-800)/<alpha-value>)',
900: 'rgb(var(--color-typography-900)/<alpha-value>)',
950: 'rgb(var(--color-typography-950)/<alpha-value>)',
white: '#FFFFFF',
gray: '#D4D4D4',
black: '#181718',
},
outline: {
0: 'rgb(var(--color-outline-0)/<alpha-value>)',
50: 'rgb(var(--color-outline-50)/<alpha-value>)',
100: 'rgb(var(--color-outline-100)/<alpha-value>)',
200: 'rgb(var(--color-outline-200)/<alpha-value>)',
300: 'rgb(var(--color-outline-300)/<alpha-value>)',
400: 'rgb(var(--color-outline-400)/<alpha-value>)',
500: 'rgb(var(--color-outline-500)/<alpha-value>)',
600: 'rgb(var(--color-outline-600)/<alpha-value>)',
700: 'rgb(var(--color-outline-700)/<alpha-value>)',
800: 'rgb(var(--color-outline-800)/<alpha-value>)',
900: 'rgb(var(--color-outline-900)/<alpha-value>)',
950: 'rgb(var(--color-outline-950)/<alpha-value>)',
},
background: {
0: 'rgb(var(--color-background-0)/<alpha-value>)',
50: 'rgb(var(--color-background-50)/<alpha-value>)',
100: 'rgb(var(--color-background-100)/<alpha-value>)',
200: 'rgb(var(--color-background-200)/<alpha-value>)',
300: 'rgb(var(--color-background-300)/<alpha-value>)',
400: 'rgb(var(--color-background-400)/<alpha-value>)',
500: 'rgb(var(--color-background-500)/<alpha-value>)',
600: 'rgb(var(--color-background-600)/<alpha-value>)',
700: 'rgb(var(--color-background-700)/<alpha-value>)',
800: 'rgb(var(--color-background-800)/<alpha-value>)',
900: 'rgb(var(--color-background-900)/<alpha-value>)',
950: 'rgb(var(--color-background-950)/<alpha-value>)',
error: 'rgb(var(--color-background-error)/<alpha-value>)',
warning: 'rgb(var(--color-background-warning)/<alpha-value>)',
muted: 'rgb(var(--color-background-muted)/<alpha-value>)',
success: 'rgb(var(--color-background-success)/<alpha-value>)',
info: 'rgb(var(--color-background-info)/<alpha-value>)',
light: '#FBFBFB',
dark: '#181719',
},
indicator: {
primary: 'rgb(var(--color-indicator-primary)/<alpha-value>)',
info: 'rgb(var(--color-indicator-info)/<alpha-value>)',
error: 'rgb(var(--color-indicator-error)/<alpha-value>)',
},
},
fontFamily: {
'heading': undefined,
'body': undefined,
'mono': undefined,
'jakarta': ['var(--font-plus-jakarta-sans)'],
'roboto': ['var(--font-roboto)'],
'code': ['var(--font-source-code-pro)'],
'inter': ['var(--font-inter)'],
'space-mono': ['var(--font-space-mono)'],
},
fontWeight: {
extrablack: '950',
},
fontSize: {
'2xs': '10px',
},
boxShadow: {
'hard-1': '-2px 2px 8px 0px rgba(38, 38, 38, 0.20)',
'hard-2': '0px 3px 10px 0px rgba(38, 38, 38, 0.20)',
'hard-3': '2px 2px 8px 0px rgba(38, 38, 38, 0.20)',
'hard-4': '0px -3px 10px 0px rgba(38, 38, 38, 0.20)',
'hard-5': '0px 2px 10px 0px rgba(38, 38, 38, 0.10)',
'soft-1': '0px 0px 10px rgba(38, 38, 38, 0.1)',
'soft-2': '0px 0px 20px rgba(38, 38, 38, 0.2)',
'soft-3': '0px 0px 30px rgba(38, 38, 38, 0.1)',
'soft-4': '0px 0px 40px rgba(38, 38, 38, 0.1)',
},
},
},
}
```
4. 使用 `GluestackUIProvider` 包括着整个组件:
```tsx
// App.tsx
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'
import '@/global.css' // Make sure this path is correct
export default function App() {
return (
<GluestackUIProvider>{/* Add your app code here */}</GluestackUIProvider>
)
}
```
## 测试
下载对应组件:
```bash
npx gluestack-ui add button
```
引入使用:
```tsx
import { StyleSheet, Text, View } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { Button, ButtonText } from '@/components/ui/button'
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'
import '@/styles/global.css'
export default function Layout() {
return (
<GluestackUIProvider>
<SafeAreaView style={styles.container}>
<View className="flex-1 items-center justify-center bg-white">
<Text className="text-xl font-bold text-blue-500">
Welcome to Nativewind!
</Text>
<Button>
<ButtonText>你好</ButtonText>
</Button>
</View>
</SafeAreaView>
</GluestackUIProvider>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
paddingHorizontal: 16,
}
})
```
@@ -0,0 +1,6 @@
Lucide 是一个轻量级、开源的图标库
> 官网:https://lucide.dev/icons/
```bash
npx expo add lucide-react-native
```
@@ -0,0 +1,7 @@
{
"label": "第三方库",
"position": 2,
"link": {
"type": "generated-index"
}
}
@@ -0,0 +1,34 @@
## 设置页面背景色
在 `pages.json` 中设置 `backgroundColor` 并未生效。
设置全局背景色在 `App.vue` 中进行设置
```css
<!--此标签需要新建,不要和样式搞在一起-->
<style>
page {
background-color: #f5f7fa;
}
</style>
```
设置单个页面背景色就在对应的页面中设置
```css
<!--此标签需要新建,不要和样式搞在一起-->
<style scoped>
page {
background-color: red;
}
</style>
```
``` css
<style>
page {
background-color: #f5f7fa;
}
</style>
```
@@ -0,0 +1,100 @@
## 白屏问题
环境:
- 浏览器:Chrome56
- Unibest:快速开发框架,官网:https://unibest.tech/
出现白屏参考上面的方案。
使用的是 Vscode 模板的话,直接参考
使用的是 Hbuilderx 模板的话,在根目录下添加`vite.config.js`文件
```js
import Uni from '@dcloudio/vite-plugin-uni'
import legacy from '@vitejs/plugin-legacy'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
uni(),
legacyPlugin({
// 配置参考上面的 md 文件
})
]
})
```
## 原生Tabbar遮挡
如果Uniapp原生的Tabbar会遮挡一部分内容,这是因为部分低版本浏览器可能不支持 `env` 计算函数,所以导致整个样式设置失效。
**解决方案:**
新建 `/hooks/useSafeAreaBottom` 文件夹
在该目录下新建 `index.ts` 和 `index.css` 文件,添加一下内容
`index.css`:
```css
.safe-area-bottom {
padding-bottom: 50px;
padding-bottom: calc(50px + constant(safe-area-inset-bottom));
padding-bottom: calc(50px + env(safe-area-inset-bottom));
}
// 设置为50px是因为Uniapp的tabber的高度固定为50px。
```
`index.ts`:
```ts
import './index.css'
export function useSafeAreaBottom(): {
safeAreaInsets: UniApp.GetSystemInfoResult['safeAreaInsets']
needSafeAreaBottom: boolean
} {
const systemInfo = uni.getSystemInfoSync()
const safeAreaInsets: UniApp.GetSystemInfoResult['safeAreaInsets']
= systemInfo.safeAreaInsets ?? {
top: 0,
bottom: 0,
left: 0,
right: 0,
}
// ✅ 仅检测是否支持 env(safe-area-inset-bottom)
const supportsEnv
= typeof window !== 'undefined'
&& 'CSS' in window
&& typeof CSS.supports === 'function'
&& CSS.supports('padding-bottom', 'env(safe-area-inset-bottom)')
const needSafeAreaBottom = !supportsEnv
return {
safeAreaInsets,
needSafeAreaBottom,
}
}
```
使用:
```html
<template>
<view
:class="{ 'safe-area-bottom': needSafeAreaBottom }"
:style="{ marginTop: safeAreaInsets.top + 'px' }"
>
</view>
</template>
<script lang="ts" setup>
import { useSafeAreaBottom } from '@/hooks/useSafeAreaBottom/index'
const { safeAreaInsets, needSafeAreaBottom } = useSafeAreaBottom()
</script>
```
@@ -0,0 +1,381 @@
> 背景:现在使用 HBuilderX 打自定义基座的话,一个账号会有限制次数。并且时间过慢。
## 1. 安装 Android Studio
使用该工具进行自定义基座。
下载地址:https://developer.android.com/studio?hl=zh-cn
按照顺序安装即可,注意SDK的位置不要安装到C盘
## 2. 下载 HBuilderX 离线SDK
下载地址:https://nativesupport.dcloud.net.cn/AppDocs/download/android.html
**注意:下载的 SDK 的版本需要与 HBuilderX 的版本保持一致。**
历史版本:https://pan.baidu.com/share/init?surl=KtOCtMZJSgfAayHNjTpdTg&pwd=4hvi
## 3. 导入 HBuilder-Integrate-AS 项目到 Android Studio
解压从 HBuilderX 下载后的 Android-SDK,使用 Android Studio 打开解压后的 HBuilder-Integrate-AS 项目。
![alt text](assets/1767860095770.png)
导入成功后,会发现目录只有部分内容。
![alt text](assets/1767860105639.png)
这时候需要将 Android 更新为 Project 既可查看到项目全部内容
![alt text](assets/1767860116406.png)
修改后的效果
![alt text](assets/1767860127749.png)
## 4. 配置 Andriod Studio
配置 JDK ,配置路径:Settings - Build - Build Tools - Gradle
将 Gradle JDK 的路径修改为本地的路径,修改后点击 `Apply` 即可。注意:JDK 的版本需要和 Gradle 的版本进行适配,如果不适配那么运行的时候也会有详细的报错信息。
![alt text](assets/1767860213983.png)
## 5. Uniapp开发者中心 申请相关信息
### 5.1 创建应用
首先根据应用名称检查是否已经存在当前的项目。
![alt text](assets/1767860225084.png)
有过没有的话则点击右上角的 `创建应用` 按钮进行创建:
![alt text](assets/1767860300109.png)
创建成功后会添加到 **我的应用** 列表中
![alt text](assets/1767860311950.png)
点击对应的 **应用名称** 即可进入对应的应用
### 5.2 申请云端证书
点击创建证书
![alt text](assets/1767860326407.png)
因为需要时间,过段时间刷新即可
![alt text](assets/1767860336247.png)
创建成功后,点击 **证书详情 ** 这里面有需要的一些信息。
需要的有 别名、MD5、SHA1、SHA256
![alt text](assets/1767860347571.png)
同时还需要证书密码,点击 **查看证书密码 ** 即可获取到。
![alt text](assets/1767860358483.png)
现在记录的信息有: 别名、MD5、SHA1、SHA256、证书密码
注意下载申请过的证书,后面需要用到
![alt text](assets/1767860370727.png)
### 5.3 新增平台信息
进入 **各平台信息** ,点击 **新增** 按钮
![alt text](assets/1767860380849.png)
填写以下信息,注意填写包名(任意),该包名后面使用到。这个时候 SHA1、MD5、SHA256 就是在 [5.2 申请云端证书](#52-申请云端证书) 章节申请的信息。
![alt text](assets/1767860391828.png)
创建成功后就会显示
![alt text](assets/1767860402803.png)
创建离线Key,点击刚刚创建的平台信息的 创建离线Key 按钮
![alt text](assets/1767860413675.png)
点击进行创建,创建成功后,会显示 **查看离线Key**
![alt text](assets/1767860423452.png)
点击查看对应的离线Key,主要保留该值,后面会用到
## 6. 配置导入过的 HBuilder-Integrate-AS 项目
配置 `HBuilder-Integrate-AS\simpleDemo\build.gradle` ,这些修改的信息 已经都在 [5. Uniapp开发者中心 申请相关信息](#5-Uniapp开发者中心 申请相关信息) 申请过了,我已标注。注意下载云端证书,并放到 simpleDemo 目录下。
![alt text](assets/1767860437778.png)
替换 离线Key(该值就在 [5.3 新增平台信息](#53-新增平台信息) 申请过了),配置 `HBuilder-Integrate-AS\simpleDemo\src\main\AndroidManifest.xml` 文件。
![alt text](assets/1767860447485.png)
配置 `HBuilder-Integrate-AS\simpleDemo\src\main\assets\data\dcloud_control.xml` ,替换自己项目的appid。
![alt text](assets/1767860459644.png)
## 7. Hbuilder X 导出本地打包资源
注意 APPID 需要和创建应用的 appid 保持一致。如果不一致,可以去源码视图进行修改
![alt text](assets/1767860475275.png)
导出成功后,路径参考:
![alt text](assets/1767860484887.png)
复制 **resources** 文件夹下面文件夹,然后替换 **HBuilder-Integrate-AS** 项目中的 `HBuilder-Integrate-AS\simpleDemo\src\main\assets\apps\__UNI__A` 目录,将 `__UNI__A` 文件夹替换为导出的 `__UNI__9063282` 文件夹,替换后如下:
![alt text](assets/1767860494289.png)
确保 应用版本名称 和 应用版本号保持一致
![alt text](assets/1767860503374.png)
![alt text](assets/1767860510261.png)
## 8. 运行项目
先进行加载配置好的项目
![alt text](assets/1767860524973.png)
加载成功后即可出现蓝色运行按钮,点击运行即可
![alt text](assets/1767860536194.png)
## 9. 导入原生插件
> 如果不需要该步可以忽略,不影响自定义基座。
参考网站:https://zh.uniapp.dcloud.io/plugin/native-plugin.html#%E6%9C%AC%E5%9C%B0%E6%8F%92%E4%BB%B6-%E9%9D%9E%E5%86%85%E7%BD%AE%E5%8E%9F%E7%94%9F%E6%8F%92%E4%BB%B6
### 9.1 下载插件
这里用 **DCloud-RichAlert** 举例,插件下载地址:https://ext.dcloud.net.cn/plugin?id=36
下载完毕后,新建 **nativeplugins** 文件夹,将解压后的插件放到该文件夹下面
![alt text](assets/1767860546989.png)
9.2 配置本地插件
![alt text](assets/1767860556154.png)
选择插件
![alt text](assets/1767860566602.png)
配置成功页面
![alt text](assets/1767860575227.png)
然后就可以使用啦,在页面中添加测试代码
```html
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
}
},
onLoad() {
const dcRichAlert = uni.requireNativePlugin('DCloud-RichAlert')
dcRichAlert.show(
{
position: 'bottom',
title: '提示信息',
titleColor: '#FF0000',
content:
"<a href='https://uniapp.dcloud.io/' value='Hello uni-app'>uni-app</a> 是一个使用 Vue.js 开发跨平台应用的前端框架!\n免费的\n免费的\n免费的\n重要的事情说三遍",
contentAlign: 'left',
checkBox: {
title: '不再提示',
isSelected: true,
},
buttons: [
{
title: '取消',
},
{
title: '否',
},
{
title: '确认',
titleColor: '#3F51B5',
},
],
},
(result) => {
switch (result.type) {
case 'button':
console.log('callback---button--' + result.index)
break
case 'checkBox':
console.log('callback---checkBox--' + result.isSelected)
break
case 'a':
console.log('callback---a--' + JSON.stringify(result))
break
case 'backCancel':
console.log('callback---backCancel--')
break
}
},
)
},
methods: {},
}
</script>
```
当然,现在还没有结束,如果需要在本地看到效果,需要重复 [7. Hbuilder X 导出本地打包资源](#7-Hbuilder X 导出本地打包资源) 步骤,将新的打包资源将旧的替换掉。
### 9.3 配置项目
**重要的下一步**,将 `nativeplugins\DCloud-RichAlert\android\uniplugin_richalert.aar` 复制到 `HBuilder-Integrate-AS\simpleDemo\libs` 文件夹下。
![alt text](assets/1767860605362.png)
然后呢,还没有结束哦。
在assets目录下创建 **dcloud_uniplugins.json** 文件,添加以下内容
```json
{
"nativePlugins": [
{
"plugins": [
{
"type": "module",
"name": "DCloud-RichAlert",
"class": "uni.dcloud.io.uniplugin_richalert.RichAlertWXModule"
}
]
}
]
}
```
![alt text](assets/1767860623138.png)
### 9.4 配置gradle文件
添加制定依赖。
```
dependencies {
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.core:core:1.1.0'
implementation "androidx.fragment:fragment:1.1.0"
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.facebook.fresco:fresco:2.5.0'
implementation "com.facebook.fresco:animated-gif:2.5.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.alibaba:fastjson:1.2.83'
implementation 'androidx.webkit:webkit:1.5.0'
// 基座需要,必须添加。主要是这个是
implementation 'com.github.bumptech.glide:glide:4.9.0'
}
```
![alt text](assets/1767860638268.png)
### 9.5 运行项目
然后就是可以重新运行项目啦。运行成功的结果如下:
![alt text](assets/1767860648404.png)
## 10. 自定义基座
### 10.1 Debug 配置
修改 `HBuilder-Integrate-AS\simpleDemo\src\main\assets\data\dcloud_control.xml` 文件,设置 Debug 模式:
```xml
<hbuilder debug="true" syncDebug="true">
<apps>
<app appid="__UNI__ID" appver=""/>
</apps>
</hbuilder>
```
![alt text](assets/1767860660364.png)
修改 `HBuilder-Integrate-AS\simpleDemo\build.gradle` 在该文件中添加 **okhttp3** 依赖
```
dependencies {
implementation "com.alibaba:fastjson:1.2.83"
implementation "com.squareup.okhttp3:okhttp:3.12.12"
}
```
![alt text](assets/1767860678022.png)
### 10.2 导入 Debug SDK
需要导入的 SDK 位于 `Android-SDK@4.66.82418_20250520\SDK\libs` 中
![alt text](assets/1767860687556.png)
将 **debug-server-release.aar** 复制到 **libs** 下面
![alt text](assets/1767860696316.png)
### 10.3 生成APK文件
![alt text](assets/1767860704777.png)
生成后会生成在 debug 目录下
![alt text](assets/1767860712216.png)
### 10.4 复制APK文件到HBuilderX中
1. 在HBuilderX项目中创建创建 unpackage 目录,在 unpackage 目录中创建 debug 目录,将上述生成的APK文件拷贝到debug目录中。
2. **重命名**文件为 **android_debug.apk**,目录结构参考下图
![alt text](assets/1767860732712.png)
### 10.5 运行自定义基座
![alt text](assets/1767860747593.png)
选择自定义基座
![alt text](assets/1767860756953.png)
点击运行,运行结果如下:
![alt text](assets/1767860772664.png)
同时能支持 **热更新** 。修改下,查看效果吧。
![alt text](assets/1767860784873.png)
## 11. 模块及三方 SDK 配置
参考官网:https://nativesupport.dcloud.net.cn/AppDocs/usemodule/androidModuleConfig/others.html
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,65 @@
环境:
- 浏览器:Chrome56
- Vue:^3.5.15
- Vite:6.3.5
解决方案:
`@vitejs/plugin-legacy` ,该包是Vite提供的一个插件,为打包后的文件提供传统浏览器兼容性支持。官网:https://github.com/vitejs/vite/tree/main/packages/plugin-legacy
`terser`,主要用于压缩代码,还有代码混淆、源码映射等功能。
```bash
pnpm i @vitejs/plugin-legacy terser -D
```
安装上述依赖后,在 `vite.config.ts/js` 中添加以下内容:
```ts
import legacy from '@vitejs/plugin-legacy'
// 在插件处添加一下功能
plugins: [
legacy({
// 目标浏览器环境,'defaults' 是浏览器列表默认设置,支持 Chrome 56 及以上
targets: ['defaults', 'Chrome >= 56'],
// 额外引入的兼容性 polyfill,这里加入了对 generator 函数的支持
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
// 是否生成兼容旧浏览器的代码块(chunk)
renderLegacyChunks: true,
// 需要引入的具体 polyfill 列表,确保目标环境缺失的 API 得到支持
polyfills: [
'es.symbol', // Symbol 支持
'es.array.filter', // Array.prototype.filter 支持
'es.promise', // Promise 支持
'es.promise.finally', // Promise.prototype.finally 支持
'es.object.assign', // Object.assign 支持
'es.map', // Map 支持
'es.set', // Set 支持
'es.array.for-each', // Array.prototype.forEach 支持
'es.object.define-properties', // Object.defineProperties 支持
'es.object.define-property', // Object.defineProperty 支持
'es.object.get-own-property-descriptor', // Object.getOwnPropertyDescriptor 支持
'es.object.get-own-property-descriptors', // Object.getOwnPropertyDescriptors 支持
'es.object.keys', // Object.keys 支持
'es.object.to-string', // Object.prototype.toString 支持
'web.dom-collections.for-each', // DOM 集合的 forEach 支持
'esnext.global-this', // 全局变量 globalThis 支持
'esnext.string.match-all', // String.prototype.matchAll 支持
'es.array.iterator', // 数组迭代器支持
'es.string.includes', // String.prototype.includes 支持
'es.string.starts-with', // String.prototype.startsWith 支持
'es.object.values', // Object.values 支持
],
}),
]
```
`targets` 可以参考:[Browserslist官网](https://github.com/browserslist/browserslist) 查询
**注意该方案只在打包后生效。**
@@ -0,0 +1,3 @@
PostgreSQL(常简称“Postgres”)是一款强调可扩展性和标准兼容性的对象关系型数据库管理系统(ORDBMS)。作为数据库服务器,其核心功能是安全存储数据并支持最佳实践,同时支持本地或网络(含互联网)中的应用程序按需检索数据。它可处理从小型单机应用到高并发互联网应用的各类负载,最新版本还支持数据库复制以提升安全性和可扩展性。
PostgreSQL 实现了 SQL:2011 标准的大部分功能,支持 ACID 事务(含多数 DDL 语句),通过多版本并发控制(MVCC)避免锁竞争,提供防脏读和完全可序列化能力。它支持复杂 SQL 查询、多种索引类型、可更新视图、物化视图、触发器、外键,以及函数和存储过程,并拥有丰富的第三方扩展。此外,PostgreSQL 支持从其他数据库迁移,通过标准 SQL 兼容和迁移工具,甚至可通过内置或第三方扩展模拟专有数据库的特性(如 Oracle)。
@@ -0,0 +1,15 @@
## Docker安装
dockerhub网站:https://hub.docker.com/_/postgres
1. 拉取
```bash
docker pull postgres@18
```
2. 运行
```bash
docker run --name postgres18 -e POSTGRES_PASSWORD=xxx -p 5432:5432 -d postgres:18
```
> 初始化数据库:postgres 默认用户名:postgres
Whitespace-only changes.
@@ -0,0 +1,38 @@
## Docker 安装
拉取镜像
```bash
docker pull redis:8.4-alpine
```
快速启动
```bash
docker run -d --name redis -p 6370:6379 redis:8.4-alpine --requirepass "xxx"
```
在容器启动后配置密码
```bash
# 拉取redis镜像
docker pull redis
# 启动容器
docker run -d -p 6366:6379 --name myredis2 redis
# 通过容器id,进入redis
docker exec -it myredis2 /bin/bash
# 运行redis客户端
redis-cli
# 查看redis的密码
config get requirepass
# 设置redis的密码
config set requirepass yourPassword
# 认证
auth yourPassword
```
@@ -0,0 +1,11 @@
SQL Server 是微软推出的一款关系型数据库管理系统(RDBMS),主要用于存储、管理和处理结构化数据。
简单来说可以这样理解:
稳定可靠:常用于企业级应用,适合处理大量数据和高并发场景
功能全面:支持事务、索引、视图、存储过程、触发器等常见数据库功能
和微软生态集成好:和 Windows、.NET、Azure 等配合非常顺畅
易上手:自带管理工具(SSMS),对新手和运维都比较友好
@@ -0,0 +1,200 @@
## Windows系统
### 安装
**1**、登陆微软中国官网:[Microsoft - Official Home Page](https://link.zhihu.com/?target=https%3A//www.microsoft.com/zh-cn/);在搜索中输入 SQL Server 2008 并搜索。
![img](./assets/v2-7b64ed995472d681b150272e831bd06f_1440w.jpg)
下载链接:
[Download Microsoft® SQL Server® 2008 R2 SP2 - Express Edition from Official Microsoft Download Center](https://link.zhihu.com/?target=https%3A//www.microsoft.com/zh-CN/download/details.aspx%3Fid%3D30438)
**2**、下载
下载 64 位程序,如果系统是 32 位,就选 32 位的
![image-20250610210005234](./assets/image-20250610210005234.png)
这里只下载 **SQLEXPR_x64_CHS.exe** ,可视化工具选用 **Navicat**
**3**、安装
先安装SQL,再安装 SQL Management Studio
双击SQLEXPR_x64.CHS
![img](./assets/v2-a3b4eaa43750e31661f95cc1e25d7c55_1440w.jpg)
等待加载完毕
(这时会有一定的几率提醒你的电脑缺少[Microsoft .NET Framework 2.0](https://zhida.zhihu.com/search?content_id=102713512&content_type=Article&match_order=1&q=Microsoft+.NET+Framework+2.0&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDk3MzMwMzQsInEiOiJNaWNyb3NvZnQgLk5FVCBGcmFtZXdvcmsgMi4wIiwiemhpZGFfc291cmNlIjoiZW50aXR5IiwiY29udGVudF9pZCI6MTAyNzEzNTEyLCJjb250ZW50X3R5cGUiOiJBcnRpY2xlIiwibWF0Y2hfb3JkZXIiOjEsInpkX3Rva2VuIjpudWxsfQ.riy6QZKx3etA1Hd2g0oaCLoNl0G_pzuoq8tZqWZXfFo&zhida_source=entity) 或更高版本
根据他的提示进行安装就行)
![img](./assets/v2-21688a13be329ecf9efbdbc4040596a3_1440w.jpg)
如果没有,请忽略这一步。
当他顺利加载完毕之后,我们就可以看到下图所示的界面,**点击全新安装**
![img](./assets/v2-1688783d592ae41aa9fcf397867a2588_1440w.jpg)
![img](./assets/v2-4c7d6f2d930368d96ed646c8ef1e12c8_1440w.jpg)
接受并下一步
![img](./assets/v2-f3f22c97d8dfe77a9adb6811aa60dffe_1440w.jpg)
点击安装
一直下一步,保持默认设置到”实例配置“这一节,并选择”默认实例“,并点击下一步
![img](./assets/v2-34283637dc32b1e6623305be7194b3c6_1440w.jpg)
再一路下一步到”数据库引擎配置这一节“
![img](./assets/v2-9c9150dd6b42728ba18d001e08870058_1440w.jpg)
如果没有用户的话就点击”添加当前用户”
![img](./assets/v2-994ee12358e16a3c839030de71bb5fb0_1440w.jpg)
错误报告可选可不选
一直下一步直到安装完成
![img](./assets/v2-3c4a8588b5a2faca27dec12af7c99c4b_1440w.jpg)
到此为止,我们的安装过程已经进行完成了。 SQL Management Studio 可按照需求安装
### 配置
#### 服务
Windows 系统:`win` + `r` 输入 `services.msc` ,打开后找到 SqlServer 相关的,并将服务修改为自动,并且需要 首次 手动启动
![image-20250610210638276](./assets/image-20250610210638276.png)
![image-20250610210703831](./assets/image-20250610210703831.png)
#### 协议
`win` 键启动搜索,搜索 SQL Server 配置管理器
![image-20250610210833638](./assets/image-20250610210833638.png)
点击 SQL Server 配置管理器,确保该三个协议已启动,未启动则启动![image-20250610210952597](./assets/image-20250610210952597.png)
#### 端口
右键 TCP/IP
![image-20250610211035375](./assets/image-20250610211035375.png)
点击属性,修改 TCP 端口 为 1433
![image-20250610211139630](./assets/image-20250610211139630.png)
点击 应用 和 确认后,**重启电脑才能生效**
### 校验
**校验是否安装正确**
打开 **命令提示符**(Win + R,输入 `cmd`,回车)
Windows 上默认安装 SQL Server 的时候,通常会带有 `sqlcmd` 工具(如果没有,可能需要单独安装“命令行工具”)。
1. 打开 **命令提示符**(Win + R,输入 `cmd`,回车)
2. 输入以下命令连接本机默认实例:
```bash
sqlcmd -S localhost -E
```
参数说明:
- `-S localhost` :连接本机默认实例
- `-E` :使用 Windows 身份验证
3. 如果成功连接,你会看到类似如下提示:
```shell
1>
```
4. 在提示符后输入测试命令:
```sql
SELECT @@VERSION;
GO
```
然后按回车,输出当前 SQL Server 版本信息,证明连接成功。
5. 输入
```
QUIT
```
退出命令行界面。
### 启用混合模式认证(SQL Server 和 Windows 认证)
默认情况下,SQL Server 只开启 Windows 认证(Windows Authentication Mode),你需要手动开启“混合模式”(Mixed Mode Authentication),才能使用 SQL Server 账号(如 `sa`)登录。
1. 打开命令提示符,连接到 SQL Server:
```bash
sqlcmd -S localhost -E
```
2. 执行以下命令开启混合模式:
```sql
EXEC xp_instance_regwrite
N'HKEY_LOCAL_MACHINE',
N'Software\Microsoft\MSSQLServer\MSSQLServer',
N'LoginMode',
REG_DWORD,
2
GO
```
> 说明:`LoginMode` 设置为 `2` 表示混合模式,`1` 表示只 Windows 认证。
3. 重启 SQL Server 服务,使设置生效:
- 打开服务管理器,找到 `SQL Server (实例名)` 服务,点击“重启”或先停止再启动。
4. 启用 `sa` 账号并设置密码(默认可能禁用)
继续用 `sqlcmd` 执行:
```
ALTER LOGIN sa ENABLE;
GO
ALTER LOGIN sa WITH PASSWORD = '你的强密码';
GO
```
- **密码建议**:至少 8 位,包含大小写字母、数字和特殊符号。
5. 测试账号密码登录
- 使用 `sqlcmd`:
```bash
sqlcmd -S localhost -U sa -P 你的密码
```
- 连接成功即开启账号密码登录。
6. 额外说明
- 修改注册表和重启服务后才生效。
- 也可以用 PowerShell 或其他管理工具执行上述 SQL 命令。
- 强烈建议启用强密码,防止安全风险。
- 生产环境尽量避免启用 `sa`,建议创建新的 SQL 登录账号。
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Loaded 100 of 184 files, more files were not shown because too many files have changed in this diff. Show more