u
No files matched your search
@@ -0,0 +1,2 @@
|
||||
ALGOLIA_APP_ID=OQQO4TVA7K
|
||||
ALGOLIA_API_KEY=941fbfc44df709cad3220294b747ed91
|
||||
@@ -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*
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"recommendations": [
|
||||
]
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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**
|
||||
|
||||

|
||||
|
||||
**设置 GoPath**
|
||||
|
||||

|
||||
|
||||
#### 错误处理
|
||||
|
||||
- 运行报错: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`
|
||||
|
||||
|
After Width: | Height: | Size: 58 KiB |
|
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 文本检测训练模型
|
||||
|
||||

|
||||
|
||||
### 3.2 文本识别训练模型
|
||||
|
||||

|
||||
|
||||
|
||||
## 错误情况
|
||||
### 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. 打开服务器面板,选择 **添加角色和功能**
|
||||

|
||||
2. 在功能处开启 **桌面体验**
|
||||

|
||||
|
||||
如果开启 桌面体验 报错:**尚未开启 WinRM 服务**, 这个时候需要开启 `Windows Remote Management (WS-Management) `
|
||||

|
||||
|
||||
如果在开启过程中报错:**错误1068:依存服务或组无法启动**
|
||||
|
||||
点击属性,找到 **依存关系**,确保依赖的服务已开启
|
||||
|
||||

|
||||
|
||||
检查 `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
|
||||
```
|
||||
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 219 KiB |
|
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 项目。
|
||||
|
||||

|
||||
|
||||
导入成功后,会发现目录只有部分内容。
|
||||
|
||||

|
||||
|
||||
这时候需要将 Android 更新为 Project 既可查看到项目全部内容
|
||||
|
||||

|
||||
|
||||
修改后的效果
|
||||
|
||||

|
||||
|
||||
## 4. 配置 Andriod Studio
|
||||
|
||||
配置 JDK ,配置路径:Settings - Build - Build Tools - Gradle
|
||||
|
||||
将 Gradle JDK 的路径修改为本地的路径,修改后点击 `Apply` 即可。注意:JDK 的版本需要和 Gradle 的版本进行适配,如果不适配那么运行的时候也会有详细的报错信息。
|
||||
|
||||

|
||||
|
||||
## 5. Uniapp开发者中心 申请相关信息
|
||||
|
||||
### 5.1 创建应用
|
||||
|
||||
首先根据应用名称检查是否已经存在当前的项目。
|
||||
|
||||

|
||||
|
||||
有过没有的话则点击右上角的 `创建应用` 按钮进行创建:
|
||||
|
||||

|
||||
|
||||
创建成功后会添加到 **我的应用** 列表中
|
||||
|
||||

|
||||
|
||||
点击对应的 **应用名称** 即可进入对应的应用
|
||||
|
||||
### 5.2 申请云端证书
|
||||
|
||||
点击创建证书
|
||||
|
||||

|
||||
|
||||
因为需要时间,过段时间刷新即可
|
||||
|
||||

|
||||
|
||||
创建成功后,点击 **证书详情 ** 这里面有需要的一些信息。
|
||||
|
||||
需要的有 别名、MD5、SHA1、SHA256
|
||||
|
||||

|
||||
|
||||
同时还需要证书密码,点击 **查看证书密码 ** 即可获取到。
|
||||
|
||||

|
||||
|
||||
现在记录的信息有: 别名、MD5、SHA1、SHA256、证书密码
|
||||
|
||||
注意下载申请过的证书,后面需要用到
|
||||
|
||||

|
||||
|
||||
### 5.3 新增平台信息
|
||||
|
||||
进入 **各平台信息** ,点击 **新增** 按钮
|
||||
|
||||

|
||||
|
||||
填写以下信息,注意填写包名(任意),该包名后面使用到。这个时候 SHA1、MD5、SHA256 就是在 [5.2 申请云端证书](#52-申请云端证书) 章节申请的信息。
|
||||
|
||||

|
||||
|
||||
创建成功后就会显示
|
||||
|
||||

|
||||
|
||||
创建离线Key,点击刚刚创建的平台信息的 创建离线Key 按钮
|
||||
|
||||

|
||||
|
||||
点击进行创建,创建成功后,会显示 **查看离线Key**
|
||||
|
||||

|
||||
|
||||
点击查看对应的离线Key,主要保留该值,后面会用到
|
||||
|
||||
## 6. 配置导入过的 HBuilder-Integrate-AS 项目
|
||||
|
||||
配置 `HBuilder-Integrate-AS\simpleDemo\build.gradle` ,这些修改的信息 已经都在 [5. Uniapp开发者中心 申请相关信息](#5-Uniapp开发者中心 申请相关信息) 申请过了,我已标注。注意下载云端证书,并放到 simpleDemo 目录下。
|
||||
|
||||

|
||||
|
||||
替换 离线Key(该值就在 [5.3 新增平台信息](#53-新增平台信息) 申请过了),配置 `HBuilder-Integrate-AS\simpleDemo\src\main\AndroidManifest.xml` 文件。
|
||||
|
||||

|
||||
|
||||
配置 `HBuilder-Integrate-AS\simpleDemo\src\main\assets\data\dcloud_control.xml` ,替换自己项目的appid。
|
||||
|
||||

|
||||
|
||||
## 7. Hbuilder X 导出本地打包资源
|
||||
|
||||
注意 APPID 需要和创建应用的 appid 保持一致。如果不一致,可以去源码视图进行修改
|
||||
|
||||

|
||||
|
||||
导出成功后,路径参考:
|
||||
|
||||

|
||||
|
||||
复制 **resources** 文件夹下面文件夹,然后替换 **HBuilder-Integrate-AS** 项目中的 `HBuilder-Integrate-AS\simpleDemo\src\main\assets\apps\__UNI__A` 目录,将 `__UNI__A` 文件夹替换为导出的 `__UNI__9063282` 文件夹,替换后如下:
|
||||
|
||||

|
||||
|
||||
确保 应用版本名称 和 应用版本号保持一致
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 8. 运行项目
|
||||
|
||||
先进行加载配置好的项目
|
||||
|
||||

|
||||
|
||||
加载成功后即可出现蓝色运行按钮,点击运行即可
|
||||
|
||||

|
||||
|
||||
## 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** 文件夹,将解压后的插件放到该文件夹下面
|
||||
|
||||

|
||||
|
||||
9.2 配置本地插件
|
||||
|
||||

|
||||
|
||||
选择插件
|
||||
|
||||

|
||||
|
||||
配置成功页面
|
||||
|
||||

|
||||
|
||||
然后就可以使用啦,在页面中添加测试代码
|
||||
|
||||
```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` 文件夹下。
|
||||
|
||||

|
||||
|
||||
然后呢,还没有结束哦。
|
||||
|
||||
在assets目录下创建 **dcloud_uniplugins.json** 文件,添加以下内容
|
||||
|
||||
```json
|
||||
{
|
||||
"nativePlugins": [
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"type": "module",
|
||||
"name": "DCloud-RichAlert",
|
||||
"class": "uni.dcloud.io.uniplugin_richalert.RichAlertWXModule"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
### 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'
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 9.5 运行项目
|
||||
|
||||
然后就是可以重新运行项目啦。运行成功的结果如下:
|
||||
|
||||

|
||||
|
||||
## 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>
|
||||
```
|
||||
|
||||

|
||||
|
||||
修改 `HBuilder-Integrate-AS\simpleDemo\build.gradle` 在该文件中添加 **okhttp3** 依赖
|
||||
|
||||
```
|
||||
dependencies {
|
||||
implementation "com.alibaba:fastjson:1.2.83"
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.12"
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 10.2 导入 Debug SDK
|
||||
|
||||
需要导入的 SDK 位于 `Android-SDK@4.66.82418_20250520\SDK\libs` 中
|
||||
|
||||

|
||||
|
||||
将 **debug-server-release.aar** 复制到 **libs** 下面
|
||||
|
||||

|
||||
|
||||
### 10.3 生成APK文件
|
||||
|
||||

|
||||
|
||||
生成后会生成在 debug 目录下
|
||||
|
||||

|
||||
|
||||
### 10.4 复制APK文件到HBuilderX中
|
||||
|
||||
1. 在HBuilderX项目中创建创建 unpackage 目录,在 unpackage 目录中创建 debug 目录,将上述生成的APK文件拷贝到debug目录中。
|
||||
2. **重命名**文件为 **android_debug.apk**,目录结构参考下图
|
||||

|
||||
|
||||
### 10.5 运行自定义基座
|
||||
|
||||

|
||||
|
||||
选择自定义基座
|
||||
|
||||

|
||||
|
||||
点击运行,运行结果如下:
|
||||
|
||||

|
||||
|
||||
同时能支持 **热更新** 。修改下,查看效果吧。
|
||||
|
||||

|
||||
|
||||
## 11. 模块及三方 SDK 配置
|
||||
|
||||
参考官网:https://nativesupport.dcloud.net.cn/AppDocs/usemodule/androidModuleConfig/others.html
|
||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
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
|
||||
@@ -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 并搜索。
|
||||
|
||||

|
||||
|
||||
下载链接:
|
||||
|
||||
[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 位的
|
||||
|
||||

|
||||
|
||||
这里只下载 **SQLEXPR_x64_CHS.exe** ,可视化工具选用 **Navicat**
|
||||
|
||||
**3**、安装
|
||||
|
||||
先安装SQL,再安装 SQL Management Studio
|
||||
|
||||
双击SQLEXPR_x64.CHS
|
||||
|
||||

|
||||
|
||||
等待加载完毕
|
||||
|
||||
(这时会有一定的几率提醒你的电脑缺少[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) 或更高版本
|
||||
|
||||
根据他的提示进行安装就行)
|
||||
|
||||

|
||||
|
||||
如果没有,请忽略这一步。
|
||||
|
||||
当他顺利加载完毕之后,我们就可以看到下图所示的界面,**点击全新安装**
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
接受并下一步
|
||||
|
||||

|
||||
|
||||
点击安装
|
||||
|
||||
一直下一步,保持默认设置到”实例配置“这一节,并选择”默认实例“,并点击下一步
|
||||
|
||||

|
||||
|
||||
再一路下一步到”数据库引擎配置这一节“
|
||||
|
||||

|
||||
|
||||
如果没有用户的话就点击”添加当前用户”
|
||||
|
||||

|
||||
|
||||
错误报告可选可不选
|
||||
|
||||
一直下一步直到安装完成
|
||||
|
||||

|
||||
|
||||
到此为止,我们的安装过程已经进行完成了。 SQL Management Studio 可按照需求安装
|
||||
|
||||
### 配置
|
||||
|
||||
#### 服务
|
||||
|
||||
Windows 系统:`win` + `r` 输入 `services.msc` ,打开后找到 SqlServer 相关的,并将服务修改为自动,并且需要 首次 手动启动
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 协议
|
||||
|
||||
`win` 键启动搜索,搜索 SQL Server 配置管理器
|
||||
|
||||

|
||||
|
||||
点击 SQL Server 配置管理器,确保该三个协议已启动,未启动则启动
|
||||
|
||||
#### 端口
|
||||
|
||||
右键 TCP/IP
|
||||
|
||||

|
||||
|
||||
点击属性,修改 TCP 端口 为 1433
|
||||
|
||||

|
||||
|
||||
点击 应用 和 确认后,**重启电脑才能生效**
|
||||
|
||||
### 校验
|
||||
|
||||
**校验是否安装正确**
|
||||
|
||||
打开 **命令提示符**(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 登录账号。
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 125 KiB |