i18n(ko): init korean translation (#3528)

Co-authored-by: deepthought <deepthough@postech.ac.kr>
Co-authored-by: FabianLars <github@fabianlars.de>
This commit is contained in:
Taeyoon Kim
2025-09-30 20:36:40 +09:00
committed by GitHub
parent 7eb4f40695
commit 35015b6f11
85 changed files with 13073 additions and 199 deletions

View File

@@ -86,3 +86,22 @@ Here are some guidelines to help with the translation.
Remember, the main goal of the translation is to make the content as accessible and clear to the new audience as it was to the original audience. Always prioritize clarity and accuracy. Remember, the main goal of the translation is to make the content as accessible and clear to the new audience as it was to the original audience. Always prioritize clarity and accuracy.
Thank you for your interest in contributing; we're excited to have you! Reach out on the [`#docs` channel on Discord](https://discord.com/invite/tauri) if you have any questions along the way. Thank you for your interest in contributing; we're excited to have you! Reach out on the [`#docs` channel on Discord](https://discord.com/invite/tauri) if you have any questions along the way.
## Language-specific Guidelines
This section was written by the translators themselves, feel free to add your own tips here.
### Basic Procedure of JP Translation邦訳基本手順
1. Use On-line Translation for the inital translation. <br />オンライン翻訳にて初期翻訳。
1. Checks on the auto-translation result. Inappropriate translations shall be corrected (such as "Tauri" - which is often translated as the name of the zodiac sign "the Bull"). <br />自動翻訳の内容確認。f不適切な訳語は修正例えば「牡牛座」と訳された "Tauri" など)。
1. Products names, trade names and proper names such as Tauri, Windows, macOS etc. are shown as they are. <br />商品名、会社名、固有名詞などは、
そのまま英語表記とする(必要に応じて括弧書きで「読み」を表示)。
1. The technical terms shall be checked on the on-line terminology sites (Microsoft Terminology Search, etc.) <br />技術専門用語類は、オンライン用語検索サイト(マイクロソフト社等)に記載されている一般的なものを採用するが、カタカナ語に関しては適宜和語に置き換える倍もある。
### Basic Procedure of KO Translation(번역 기본 절차)
1. Use On-line Translation for the inital translation. <br />온라인 번역으로 초기 번역.
1. Checks on the auto-translation result. Inappropriate translations shall be corrected (such as "Tauri" - which is often translated as the name of the zodiac sign "the Bull"). <br />자동 번역 내용 확인. 부적절한 번역어는 수정(예: "황소자리"로 번역된 "Tauri" 등).
1. Products names, trade names and proper names such as Tauri, Windows, macOS etc. are shown as they are. <br />상품명, 회사명, 고유명사 등은 그대로 영어 표기로 함(필요에 따라 괄호 안에 "읽기" 표시).
1. The technical terms shall be checked on the on-line terminology sites (Microsoft Terminology Search, etc.) <br />기술 전문 용어류는 온라인 용어 검색 사이트(마이크로소프트사 등)에 기재된 일반적인 것을 채택하지만, 가타카나어에 관해서는 적절히 한국어로 대체하는 경우도 있음.

3
.github/labeler.yml vendored
View File

@@ -6,6 +6,7 @@ i18n:
- src/content/docs/it/**/* - src/content/docs/it/**/*
- src/content/docs/zh-cn/**/* - src/content/docs/zh-cn/**/*
- src/content/docs/ja/**/* - src/content/docs/ja/**/*
- src/content/docs/ko/**/*
"i18n: es": "i18n: es":
- src/content/docs/es/**/* - src/content/docs/es/**/*
@@ -22,3 +23,5 @@ i18n:
"i18n: ja": "i18n: ja":
- src/content/docs/ja/**/* - src/content/docs/ja/**/*
"i18n: ko":
- src/content/docs/ko/**/*

View File

@@ -26,22 +26,20 @@ pnpm-lock.yaml
src/components/overrides/Header.astro src/components/overrides/Header.astro
# TODO: Prettier breaks these pages # TODO: Prettier breaks these pages
src/content/docs/learn/Security/capabilities-for-windows-and-platforms.mdx
src/content/docs/learn/Security/using-plugin-permissions.mdx
src/content/docs/learn/Security/writing-plugin-permissions.mdx
src/content/docs/zh-cn/learn/Security
src/content/docs/start/frontend/qwik.mdx src/content/docs/start/frontend/qwik.mdx
src/content/docs/ja/start/frontend/qwik.mdx src/content/docs/*/start/frontend/qwik.mdx
src/content/docs/es/start/frontend/qwik.mdx
src/content/docs/zh-cn/start/frontend/qwik.mdx
src/content/docs/learn/splashscreen.mdx
src/content/docs/zh-cn/learn/splashscreen.mdx
src/content/docs/ja/learn/Security/capabilities-for-windows-and-platforms.mdx
src/content/docs/ja/learn/Security/using-plugin-permissions.mdx
src/content/docs/ja/learn/Security/writing-plugin-permissions.mdx
src/content/docs/security/http-headers.mdx src/content/docs/security/http-headers.mdx
src/content/docs/*/security/http-headers.mdx
src/content/docs/learn/splashscreen.mdx
src/content/docs/*/learn/splashscreen.mdx
src/content/docs/learn/Security/capabilities-for-windows-and-platforms.mdx
src/content/docs/*/learn/Security/capabilities-for-windows-and-platforms.mdx
src/content/docs/learn/Security/using-plugin-permissions.mdx
src/content/docs/*/learn/Security/using-plugin-permissions.mdx
src/content/docs/learn/Security/writing-plugin-permissions.mdx
src/content/docs/*/learn/Security/writing-plugin-permissions.mdx

View File

@@ -18,5 +18,9 @@
"ja": { "ja": {
"label": "日本語", "label": "日本語",
"lang": "ja" "lang": "ja"
},
"ko": {
"label": "한국어",
"lang": "ko"
} }
} }

View File

@@ -42,6 +42,10 @@
{ {
"label": "日本語", "label": "日本語",
"lang": "ja" "lang": "ja"
},
{
"label": "한국어",
"lang": "ko"
} }
], ],
"dashboard": { "dashboard": {

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 85 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 90 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -1,181 +0,0 @@
---
title: Tauri Doc 日本語版 改訂記録メモ | Memorundom on Doc-JP Rev Control
topic: guides # this sidebar is active when viewing this page
---
- Rev Status Control of Japanese Translation Documents <br /> 日本語訳文書の改訂履歴メモ
## Basic Procedure of JP Translation邦訳基本手順
1. Use On-line Translation for the inital translation. <br />オンライン翻訳にて初期翻訳。
1. Checks on the auto-translation result. Inappropriate translations shall be corrected (such as "Tauri" - which is often translated as the name of the zodiac sign "the Bull"). <br />自動翻訳の内容確認。f不適切な訳語は修正例えば「牡牛座」と訳された "Tauri" など)。
1. Products names, trade names and proper names such as Tauri, Windows, macOS etc. are shown as they are. <br />商品名、会社名、固有名詞などは、
そのまま英語表記とする(必要に応じて括弧書きで「読み」を表示)。
1. The technical terms shall be checked on the on-line terminology sites (Microsoft Terminology Search, etc.) <br />技術専門用語類は、オンライン用語検索サイト(マイクロソフト社等)に記載されている一般的なものを採用するが、カタカナ語に関しては適宜和語に置き換える倍もある。
## Rev Numbering System Configuration: x.xx.xx
Example Numbering番号体系例 2.00.01
- First Didit最初の一桁= Tauri Version: "2" --> Tauri 2.0Tauri のバージョン)
- Middle Digits中央の二桁= English Doc Status: "00" --> EN Doc Status #00(英語版文書番号)
- Last Digits最後の二桁 = JP Doc Status: "01" --> JP Doc Status #01(日本語文書番号)
For the details of EN/JP doc status, see the listing below: <br /> 文書番号の詳細は以下のリストを参照して下さい。
**NOTE** This Rv Control number is for JP translation purpose only and does not necessarily represent the actual revision history of each document.<br />
**《注意》** この変更履歴番号は、日本語翻訳管理用であり、各文書の実際の変更履歴を反映しているものではありません。
## EN/JP Doc Status listEN/JP 文書簡易比較表)
### Home/Quick Start
#### index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/01/01 | **00** | 2025/01/06 |
#### 404.md
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/01/01 | **00** | 2025/01/06 |
#### rss.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/01/01 | **00** | 2025/01/06 |
### Quick Start
#### start/index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/01 | **00** | 2025/01/06 |
#### start/prerequisites.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/17 | **00** | 2025/01/07 |
#### start/create-project.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/12/31 | **00** | 2025/01/07 |
#### frontend/index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/01 | **00** | 2025/01/07 |
#### frontend/leptos.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/01 | **00** | 2025/01/07 |
#### frontend/nextjs.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/01 | **00** | 2025/01/07 |
#### frontend/nuxt.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/01 | **00** | 2025/01/07 |
#### frontend/qwik.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/01 | **00** | 2025/01/07 |
#### frontend/sveltekit.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/01 | **00** | 2025/01/07 |
#### frontend/trunk.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/01 | **00** | 2025/01/07 |
#### frontend/vite.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/01 | **00** | 2025/01/07 |
#### migrate/index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/01 | **00** | 2025/01/08 |
#### migrate/from-tauri-1.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/11/13 | **00** | 2025/01/08 |
#### migrate/from-tauri-2-beta.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2024/10/06 | **00** | 2025/01/08 |
### Core Concepts
### concept/index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/07 |
### concept/architecture.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/06 |
### concept/process-model.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/06 |
### concept/size.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/07 |
### concept/I-P-C/index.mdx
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/07 |
### concept/I-P-C/brownfield.md
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/07 |
### concept/I-P-C/isolation.md
| EN Doc # | EN Doc Date | JP Doc # | JP Doc Date |
| :------: | :---------- | :------: | :---------- |
| **00** | 2025/02/22 | **00** | 2025/03/09 |
Cont.

View File

@@ -0,0 +1,22 @@
---
title: '404'
topic: guides # 이 페이지를 볼 때 이 사이드바가 활성화됩니다
template: doc
editUrl: false
tableOfContents: false
lastUpdated: false
pagefind: false
next: false
prev: false
hero:
title: '404'
tagline: 찾고 있는 페이지를 찾을 수 없습니다. URL을 확인하거나 검색창에서 다시 검색해 주세요.
---
<p>
검색에 문제가 있는 경우 <a href="https://github.com/tauri-apps/tauri-docs/issues/new/choose">GitHub에 보고서를 제출</a>하거나 <a href="https://discord.com/invite/tauri">Discord에 문제를 보고</a>해 주세요.
</p>
<div style="text-align: right;">
Doc-KO 2.00.00
</div>

View File

@@ -0,0 +1,36 @@
---
title: The Tauri Book
i18nReady: true
---
:::note[진행 업데이트]
저희는 『The Tauri Book』 집필에 적극적으로 임하고 있습니다. 하지만 Tauri의 급격한 성장으로 인해 지연이 발생하여 최근 이 프로젝트의 우선순위를 변경했습니다. 완료 일정은 아직 미정이지만, 이 페이지를 주시하여 최신 정보를 확인해 주십시오.
당초 공지했던 공개일보다 늦어진 점 사과드립니다. GitHub Sponsors 또는 Open Collective를 통해 기부하셨고 환불을 원하시는 경우, Open Collective를 통해 진행할 수 있습니다: [Open Collective에서 Tauri에 문의하기](https://opencollective.com/tauri/contact).
:::
### Tauri Book 개요
『The Tauri Book』에서는 Tauri의 역사와 저희가 내린 설계상의 결정 사항에 대해 설명합니다. 또한, 왜 프라이버시, 보안, 지속 가능성이 중요한지, 그리고 현대의 어떤 소프트웨어 프로젝트에도 적용할 수 있는 기본적인 고찰에 대해서도 자세히 설명합니다.
포함되는 내용은 다음과 같습니다:
- Tauri 설계 이면의 방법과 그 이유
- Tauri로 프로그램을 빌드할 때 할 수 있는 일
- "신속한 출시"와 "지속 가능하고 신뢰할 수 있는 것" 중 하나를 선택할 필요가 없다는 것
- Tauri의 바인딩/애플리케이션 계층으로 Rust 언어를 선택한 이유
- 바이너리 리뷰가 중요한 이유
### Tauri의 역사
2020년, 네이티브 앱(특정 플랫폼용 앱) 제작은 그 어느 때보다 쉽고 접근하기 쉬워졌습니다. 그럼에도 불구하고, 보안과 프라이버시의 양상이 급변하는 가운데 초보자도 숙련된 개발자도 똑같이 어려운 선택에 직면해 있습니다. 이는 신뢰성이 낮은 사용자 디바이스 환경에서 특히 그렇습니다.
Tauri에서는 추측할 필요가 없습니다. 왜냐하면 Rust의 언어 기능을 활용하여 자신이 좋아하는 프론트엔드 프레임워크를 사용하여 앱을 구축할 수 있게 되는 "개발의 안전성과 유연한 창의성"이라는 새로운 패러다임을 도입하기 위해 처음부터 설계되었기 때문입니다.
Rust 프로그래밍 언어에 대한 지식이 없어도, 완전히 동일한 코드베이스에서 기록적인 속도로 주요 데스크톱 및 모바일 플랫폼을 위한 작고 빠르며 견고하고 안전한 네이티브 애플리케이션을 어떻게 설계, 구축, 감사, 배포할 수 있는지 알아보십시오.
저자이자 Tauri의 공동 설립자인 Daniel과 Lucas가 여러분을 이론에서 실행까지의 여정으로 안내합니다. 그 과정에서 Tauri가 만들어진 이유와 그 내부에서 어떻게 작동하는지 배우게 됩니다.
또한, 이 책에서는 오픈 소스, DevOps(개발과 운영), 보안, 엔터프라이즈 아키텍처를 전문으로 하는 해당 분야 분들의 통찰과 함께, 대화 형식의 철학적 논의와 오픈 소스 지속 가능성의 관점도 소개합니다. 거기서부터, 여러분이 만드는 차세대 앱은 편의를 받고, 여러분의 사용자도 그 혜택을 누리게 될 것입니다.
> > > 《번역 주》 **DevOps** 소프트웨어 개발에서 "개발(Development)"과 "운영(Operations)"을 연계하여 수행하는 방법. 자세한 내용은 Wikipedia의 "[DevOps](https://ko.wikipedia.org/wiki/데브옵스)" 항목을 참조하십시오.

View File

@@ -0,0 +1,54 @@
---
title: Tauri의 거버넌스
i18nReady: true
---
Tauri 조직 구조의 주요 목표 중 하나는 기여자의 건강과 행복을 존중하면서 오픈 소스의 가치에 충실하고 지속적인 실행을 보장하는 것입니다. [커먼즈 컨서번시/타우리 프로그램](https://dracc.commonsconservancy.org/0035/)은 Tauri와 그 부수적인 산출물의 향후 개발을 통해 이러한 가치에 전념하고, 개방적이고 투명하며 효율적인 조직의 거버넌스 프로세스(관리 통치)를 촉진하기 위해 설립되었습니다.
> > > 《번역 주》 **커먼즈 컨서번시** The Commons Conservancy. "Commons(공유 재산)"를 "Conservancy(보호 관리하는 단체)"라는 의미. 오픈 소스 프로젝트의 실제 개발 작업이 아닌, 프로젝트 운영의 법인 조직을 설립할 목적으로 설치되었습니다.
## Tauri Working Group(작업 그룹)
"Tauri 워킹 그룹"은 이 거버넌스 프로세스를 실현하기 위해 만들어진 집합적인 조직으로, 다음 구성원으로 이루어져 있습니다:
- 워킹 그룹 멤버
- Tauri 이사회 및 이사
- Tauri 각 도메인 담당 책임자
- Tauri 각 도메인 팀
![Tauri governance diagram](@assets/about/governance/diagram.svg)
### 워킹 그룹 멤버
"Tauri 워킹 그룹"을 구성하는 모든 개인을 말합니다.
### Tauri 이사회 및 이사
"Tauri 이사회"는 "Tauri 개발 활동 프로그램"의 중심적인 의사 결정 기관이며, 그 전체적인 건전성과 안정성에 책임을 집니다. 이사회는 "Tauri 개발 활동 프로그램"의 주요 결정 사항이나 워킹 그룹에 의해 제기된 문제에 대해 표결을 합니다.
> > > 《번역 주》 **Tauri 개발 활동 프로그램** 원문은 "The Tauri Programme". 그대로 "Tauri 프로그램"이라고 표기하면 개별 앱 프로그램과 구별하기 어려우므로, 개발 활동을 주관하는 "개발 주체" 또는 "개발 조직"을 "개발 활동 프로그램"으로 표현했습니다.
개별 이사란 기술적인 기여자이거나, Tauri의 장래 이해 관계자이거나, 업계 경험을 공유하거나, 오픈 소스 내의 규제나 법적 측면에 열정을 가진 사람들 같은 분들입니다.
### 각 도메인 담당 책임자(Domains & Domain Leads)
"도메인(Domains)"이란 Tauri 내의 특정 관심 영역을 대표하는 조직 단위입니다.
"도메인 리드(Domain Leads)"(담당 책임자)란 자신이 이끄는 도메인에 관한 전문 지식을 가진, Tauri 커뮤니티 내의 신뢰받는 기여자입니다. 그 도메인 내의 활동 방향을 정하고, 감독하며, 지원할 책임을 집니다.
현재 각 "도메인"과 그 "도메인 리드"에 대해서는 GitHub의 [Governance and Guidance Repository](https://github.com/tauri-apps/governance-and-guidance)에 개요가 기재되어 있습니다.
### 도메인 팀
"팀(Teams)"이란 "Tauri 개발 활동 프로그램"의 특정 영역(도메인)을 지원 또는 유지하는 소수의 기여자 그룹입니다. 이러한 팀은, 특히 그때그때의 단기적인 기여로는 같은 결과를 달성할 수 없는 경우 등에, Tauri가 사용하는 장기적인 과제와 목표를 달성하기 위한 수단입니다.
## Tauri에 참여하기
만약 당신이 "Tauri 이사" 또는 "도메인 리드"가 되고 싶다면, 이러한 직책의 선거는 연중 내내 실시됩니다. "도메인 리드" 선거는 봄과 가을에, "이사" 선거는 여름에 실시됩니다. 지원 방법 설명은 각 선거 전에 [Tauri 블로그](https://tauri.app/blog/) (영문판)에 게재됩니다.
## 추가 정보
- [Governance and Guidance Repository](https://github.com/tauri-apps/governance-and-guidance)(영문판): Tauri의 거버넌스와 현재 도메인 및 도메인 리드에 관한 상세 정보
- [사회 계약](https://github.com/tauri-apps/governance-and-guidance/blob/main/SOCIAL_CONTRACT.md)(영문판): "사회 계약"(도덕 윤리 규범)은 Tauri 의사 결정과 조직의 존재 방식을 보여줍니다
- [행동 강령](https://github.com/tauri-apps/governance-and-guidance/blob/main/CODE_OF_CONDUCT.md)(영문판)
- ["Tauri 개발 활동 프로그램" 규약](https://dracc.commonsconservancy.org/0035/)(영문판)

View File

@@ -0,0 +1,30 @@
---
title: Tauri에 대하여
i18nReady: true
---
:::tip[팁]
빠르게 읽을 수 있는 기술 개요를 원하거나 앱 제작을 시작하고 싶다면 [Tauri란?](/ko/start/) 페이지를 참조하십시오. Tauri 프로젝트의 이념에 대해 더 자세히 알고 싶다면 계속 읽어주십시오.
:::
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
<CardGrid>
<LinkCard
title="Tauri의 이념"
href="/ko/about/philosophy/"
description="Tauri의 접근 방식에 대해 자세히 알아보기"
/>
<LinkCard
title="Tauri의 거버넌스"
href="/ko/about/governance/"
description="Tauri의 거버넌스 이해하기"
/>
<LinkCard
title="상표 가이드라인"
href="/ko/about/trademark/"
description="Tauri 상표 사용에 관한 가이드라인"
/>
</CardGrid>

View File

@@ -0,0 +1,53 @@
---
title: Tauri의 이념
i18nReady: true
---
Tauri는 기존의 거의 모든 프론트엔드 프레임워크를 사용하여 개발자가 주요 데스크톱 플랫폼용 애플리케이션을 만드는 데 도움이 되는 툴킷입니다. "코어" 부분은 Rust로 작성되었고 CLI 부분은 Node.js를 활용하므로 Tauri는 뛰어난 앱을 만들고 유지 관리하기 위한 진정한 다국어 접근 방식입니다.
<iframe
style="width: 100%; aspect-ratio: 16/9;"
src="https://www.youtube-nocookie.com/embed/UxTJeEbZX-0?si=mwQUzXb6mmCg7aom"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
## 보안 우선
오늘날의 세계에서 모든 "정직한 위협 모델"은 사용자의 장치가 이미 보안 침해를 당했다고 가정합니다. 이로 인해 앱 개발자는 어려운 상황에 처하게 됩니다. 장치가 이미 위험에 처한 경우 소프트웨어를 어떻게 신뢰할 수 있습니까?
> > > 《번역 주》 **정직한 위협 모델** 원문은 "**honest** threat model". honest 부분의 정해진 번역이 불분명하여 "정직한, 꾸밈없는"의 의미로 해석했습니다. 아래의 "[진정한 오픈 소스](#진정한-오픈-소스)"의 원문도 "**honest** open source"이지만, 이 honest는 "진정한, 순수한"의 의미로 사용되었습니다.
"심층 방어(Defence in depth)"가 Tauri가 취한 접근 방식입니다. 공격자에게 노출되는 표면을 최소화하기 위해 모든 예방 조치를 취할 수 있도록 하고 싶었습니다. Tauri를 사용하면 배포할 API 엔드포인트를 선택하고, 앱에 로컬 호스트 서버를 포함할지 여부를 선택하고, 런타임 기능 핸들을 무작위화할 수 있습니다. 이러한 기술과 기타 기술은 귀하와 귀하의 앱 사용자의 방어력을 강화하는 안전한 기준선을 형성합니다.
"정적 공격(Static attacks)"을 매우 어렵게 만들고 시스템을 서로 분리하여 공격자의 침입을 지연시키는 것이 가장 중요합니다. 다른 프레임워크인 Electron 생태계에서 마이그레이션한 경우에도 안심하십시오. 기본적으로 Tauri는 바이너리만 게시하고 ASAR 파일은 게시하지 않습니다.
> > > 《번역 주》 **ASAR** Atom Shell Archive Format의 약자. [Electron](https://www.electronjs.org/ko/docs/latest/tutorial/asar-archives)에서 사용되는 여러 파일을 하나로 묶기 위한 간단한 아카이브 형식입니다. 애플리케이션 배포 형식을 만든 후 앱의 소스 코드가 ASAR 아카이브에 번들로 제공됩니다.
보안이라는 판단 기준에서 Tauri로 빌드하기로 선택함으로써 미래를 내다보는 보안 중심의 자세를 취할 수 있는 다양한 기회가 생길 것입니다.
## 다국어 지원(사일로가 아닌)
현대의 대부분의 프레임워크는 단일 언어 체계를 사용하므로 좁은 지식과 관용구의 거품 속에 갇혀 있습니다. 이는 특정 틈새 애플리케이션에서는 잘 작동하지만 일종의 부족주의(사일로화)를 조장하기도 합니다.
이 상황은 React, Angular, Vue의 각 개발 커뮤니티가 각자의 문제에 몰두하여 결국 이종 교배가 거의 일어나지 않는다는 점에서도 알 수 있습니다.
같은 상황은 Rust 대 Node 대 C++의 전쟁터에서도 볼 수 있습니다. 거기서는 강경파가 독자적인 입장을 취하고 커뮤니티 간의 협력을 거부합니다.
현재 Tauri는 백엔드에 Rust를 사용하지만, 머지않아 Go, Nim, Python, C#과 같은 다른 백엔드도 가능해질 것입니다. 왜냐하면 Tauri는 [webview](https://github.com/webview) 기관에 대한 공식 Rust 바인딩을 유지 관리하고 있지만, 여러분의 필요에 따라 백엔드를 전환할 수 있도록 할 예정이기 때문입니다. Tauri의 API는 "C 상호 운용성"을 갖춘 모든 언어로 구현할 수 있으므로 완전한 다국어화를 실현하려면 "PR(풀 리퀘스트)"을 하나 제출하기만 하면 됩니다.
## 진정한 오픈 소스
커뮤니티가 없으면 오픈 소스의 어떤 것도 의미가 없습니다. 오늘날의 소프트웨어 커뮤니티는 놀라운 곳입니다. 거기서는 사람들이 서로 돕고 멋진 것을 만듭니다. 오픈 소스는 그러한 움직임의 매우 큰 부분을 차지합니다.
오픈 소스의 의미는 사람마다 다르지만, 대부분의 사람들은 오픈 소스가 자유를 증진하는 데 도움이 된다는 데 동의할 것입니다. 소프트웨어가 귀하의 권리를 존중하지 않는 경우, 윤리에 반하는 동작으로 인해 불공평하게 느껴지고 잠재적으로 귀하의 자유를 침해할 수 있습니다.
이 때문에 FLOSS 지지자들이 "진정한" 오픈 소스인 Tauri를 사용하여 애플리케이션을 만들고 FSF(자유 소프트웨어 재단)가 승인한 GNU/Linux 배포판에 포함될 수 있다는 것을 자랑스럽게 생각합니다.
> > > 《번역 주》 **FLOSS**(free/libre open-source software) 오픈 소스 자유 소프트웨어.
## Tauri의 미래
Tauri의 미래는 여러분의 참여와 기여에 달려 있습니다. 실제로 Tauri를 사용해 보거나, 문제를 보고하거나, 워킹 그룹(각 작업 그룹)에 참여하거나, 기부해 보십시오. 어떤 기여도 필수적입니다. 어쨌든, 꼭 연락 주시기 바랍니다.

View File

@@ -0,0 +1,130 @@
---
title: 상표 가이드라인
i18nReady: true
---
:::[warning【주의】]
《번역 주》 이 한국어 번역은 "참고 번역"이며 정확한 법령 해석이 아닙니다. 상표에 관한 취급은 "영문판"의 기재에 따라 주십시오.
:::
이 방침 문서 "상표 가이드라인"은 "The Tauri Programme within the Commons Conservancy"가 소유한 "TAURI 상표", "서비스 마크" 및 "로고"의 사용 방법을 이해하는 데 도움을 드리기 위해 작성되었습니다.
> 《번역 주》 **The Tauri Programme within the Commons Conservancy** Tauri 개발팀의 공식 명칭. "커먼즈 컨서번시 내의 Tauri 프로그램"(공유 재산 보호 관리 단체 사이트 내에 등록된 Tauri 프로그램이라는 의미). 법령 관련 내용을 나타내는 본고에서는 원문 표기를 사용합니다. "커먼즈 컨서번시"에 대해서는 [Tauri의 거버넌스](/ko/about/governance/)를 참조하십시오.
Tauri의 소프트웨어는 자유/무료 오픈 소스 소프트웨어 라이선스에 따라 제공되지만, 그 저작권 라이선스에는 Tauri의 상표를 사용할 라이선스가 포함되어 있지 않습니다. 이 방침 문서는 "배경법" 및 "커뮤니티의 기대"에 따라 Tauri의 상표를 사용하는 방법을 설명하는 것을 목적으로 합니다.
**이 "방침 문서"가 다루는 범위는:**
- Tauri의 "문자 상표"와 "서비스/마크": TAURI, TAO, WRY
- Tauri의 "로고": The TAURI, TAO, WRY 각 로고(및 모든 시각적 파생물)
> 《번역 주》 **문자 상표** 원문은 "word trademarks". 기업명이나 제품명의 문자만으로 만들어진 상표. "워드 마크 word mark".
이 방침 문서는 등록 여부에 관계없이 모든 "상표"와 "서비스 마크"에 적용됩니다.
## 일반적인 가이드라인
Tauri의 상표 중 하나를 사용하는 경우, 수신자가 "누구로부터 무엇을" 받고 있는지에 대해 항상 누구에게도 오해를 주지 않는 형태로 이루어져야 합니다. 예를 들어, TAURI 소프트웨어의 수정판(포크라고도 함)을 배포하는 경우, "TAURI 소프트웨어를 배포하고 있다"고 말할 수 없습니다. 수신자가 수정판과 Tauri 공식판의 차이를 이해하지 못할 수 있기 때문입니다.
또한, 귀하의 웹사이트가 Tauri의 공식 웹사이트인 것처럼, 또는 Tauri가 귀하의 웹사이트를 공인하고 있는 것처럼 오해를 주는 형태로 귀하의 웹사이트에 Tauri의 로고를 사용할 수 없습니다.
단, TAURI 소프트웨어를 좋아한다거나, TAURI 커뮤니티에 참여하고 있다거나, TAURI 소프트웨어의 수정되지 않은 그대로의 버전을 제공하고 있다는 등의 말은 할 수 있습니다.
Tauri의 상표 또는 그 변형을 귀하 자신의 상표, 서비스 마크, 도메인 이름, 회사명, 상호, 제품명 또는 서비스명의 일부로 사용하거나 등록할 수 없습니다.
상표법에서는 Tauri의 상표와 매우 유사한 명칭이나 상표의 사용을 인정하지 않습니다. 따라서 Tauri의 상표류나 발음 표기의 명백한 "변형", "외국어 동의어", "모사", 또는 유사하거나 호환되는 제품이나 서비스의 "약어"를 사용할 수 없습니다. Tauri에서는 다음과 같은 사례를 Tauri의 상표류에 매우 유사하다고 간주합니다:
- TAURIMAGE
- Tauri Wallet App
## 허용되는 사용 예
### 애플리케이션
TAURI는 컴퓨터 기기용 애플리케이션을 만들기 위한 프레임워크입니다. 귀하의 애플리케이션이 TAURI를 사용하고 있음을 표방할 수는 있지만, 그 애플리케이션이 "the Tauri Programme within the Commons Conservancy"에 의해 인증되었거나 공식 애플리케이션이라는 인상을 주지 않도록 주의해야 합니다. 또한, 그 애플리케이션에 Tauri의 아이콘을 붙여 _공개하지 않도록_ 주의하십시오.
### 플러그인과 템플릿
적절한 명명 규칙을 사용하여 플러그인이나 템플릿 코드를 공개할 수는 있지만, 그러한 저작물은 "공식적으로 승인된 것이 아님"을 명기해야 합니다. GitHub 조직 내의 `tauri-apps`에 의해 관리되는 코드베이스만이 공식판으로 간주됩니다.
## Tauri Core의 수정판(포크)
Tauri 소프트웨어(TAURI CORE)의 수정판을 배포하는 경우, Tauri의 로고와 이름을 모두 삭제해야 합니다. 그러나 원본 라이선스를 SPDX 형식으로 남겨야 합니다. 귀하가 제공하려는 소프트웨어의 출처를 성실하게 기술하기 위해 Tauri의 "워드 마크"는 사용할 수 있지만, Tauri의 "로고"는 사용할 수 없습니다. 예를 들어, 배포하는 코드가 Tauri 소프트웨어의 수정판인 경우, "이 소프트웨어는 TAURI 소프트웨어의 소스 코드에서 파생되었습니다"라고 기재할 수 있습니다.
> 《번역 주》 **SPDX 형식** [Software Package Data Exchange](https://ko.wikipedia.org/wiki/Software_Package_Data_Exchange) "소프트웨어 패키지 데이터 교환"의 약자.
### Tauri와의 호환성에 관한 고지에 대하여
귀하의 소프트웨어와 Tauri 소프트웨어의 관계를 성실하게 표현하기 위해 "워드 마크"는 사용할 수 있지만, "로고"는 사용할 수 없습니다. 그 외의 사용 방법은 Tauri가 귀하의 소프트웨어를 인증 또는 승인했다고 받아들여질 수 있습니다. 만약 Tauri의 로고를 사용하고 싶다면, 라이선스 조건에 대해 상담해 주십시오.
### 호환되는 제품의 명명에 대하여
TAURI 소프트웨어와 관련하여 귀하의 제품을 설명하고 싶다면, 그 조건은 다음과 같습니다. 다음 조건을 충족하는 경우에만 귀하의 소프트웨어를 "TAURI의 XYZ"(XYZ는 귀하의 제품명)라고 부를 수 있습니다:
- 귀하의 제품과 함께 공개되는 TAURI 소프트웨어의 모든 버전은 Tauri가 제공하는 바이너리 자체이거나, Tauri가 제공하는 코어 소프트웨어와 도구로 만들어진 것이어야 합니다.
- 귀하의 제품이 TAURI 소프트웨어의 API와 완벽하게 호환되어야 합니다.
- 마케팅 자료나 제품 설명에 다음 문장을 기재해야 합니다: "TAURI is a trademark of The Tauri Programme within the Commons Conservancy. https://tauri.app/ "(TAURI는 the Tauri Programme within the Commons Conservancy의 상표입니다. https://tauri.app/).
### 사용자 그룹에서의 상표 이용에 대하여
다음 조건을 충족하는 경우, "사용자 그룹명"의 일부로 "워드 마크"를 사용할 수 있습니다:
- 해당 그룹의 활동 중심이 "Tauri 소프트웨어"일 것.
- 해당 그룹이 영리 활동을 하지 않을 것.
- 참가 비용이 장소비, 음식비에 한정될 것.
Tauri의 상표를 사용하여 회의를 개최하는 것은 허용되지 않습니다.
### 도메인 이름에서의 상표 사용 금지
Tauri의 "워드 마크" 또는 그 변형이나 조합을 포함하는 도메인 이름을 등록할 수 없습니다.
### 기타 TAURI 상표의 영리 목적 사용에 대하여
비디오, 튜토리얼 시리즈, 서적, 기타 교육 자료를 제작하고 구독, 판매, 광고 등을 통해 보상을 받는 경우, "the Tauri Programme within the Commons Conservancy"로부터 명시적인 라이선스 허가를 받아야 합니다.
## Tauri 상표의 표시 방법
Tauri의 상표류를 사용할 권리가 있는 경우, 다음 방법으로 표시하십시오.
### 상표 마크와 설명문에 대하여
웹 페이지, 문서 또는 자료의 처음 또는 가장 눈에 띄는 곳에 상표 마크가 표시되는 경우, 그 상표가 "등록 상표("®")"인지 "미등록 상표("™")"인지를 나타내는 기호를 부기해야 합니다. 어느 쪽에 해당하는지 불분명한 경우, Tauri에 문의하십시오. ("TAURI" 자체는 등록 상표입니다.)
상표 마크를 사용한 페이지 하단에 다음 주의 사항을 기재하십시오. "TAURI is trademark of [The Tauri Programme within the Commons Conservancy]"(TAURI는 "커먼즈 컨서번시의 Tauri 개발 활동 프로그램"의 상표입니다라는 의미).
### 문중 상표의 사용에 대하여
상표는 항상 "그대로의 형태", "정확한 철자"로 사용하고, 생략하거나, 하이픈으로 연결하거나, 다른 단어와 조합해서는 안 됩니다.
- 부적절한 예: TAUREE 《※ 철자가 다릅니다.》
- 적절한 예: TAURI
상표를 "복수형으로 만들지 마십시오".
- 부적절한 예: I have seventeen **TAURIs** running on my computer. (컴퓨터에서 17개의 TAURI를 실행하고 있습니다.) 《※ 복수형 표기》
- 적절한 예: I am running seventeen **TAURI** applications on my computer and have ram to spare. (컴퓨터에서 17개의 TAURI 애플리케이션을 실행하고 있으며 RAM에 여유가 있습니다.)
상표는 항상 명사를 수식하는 "형용사로서" 사용하십시오.
- Unacceptable: This is a TAURI.
- Acceptable: This is a TAURI software application.
- 부적절한 예: This is a **TAURI**. (이것은 TAURI입니다.) 《※ 명사로 사용》
- 적절한 예: This is a **TAURI** software application. (이것은 TAURI의 소프트웨어 애플리케이션입니다.)
### 로고의 사용에 대하여
로고는 확대/축소 표시를 제외하고 어떠한 변경도 해서는 안 됩니다. 즉, 장식적인 요소의 추가 색상이나 비율의 변경 변형 다른 요소의 추가, 로고와의 조합 등을 할 수 없습니다.
Tauri에서는 로고의 "고대비" 버전도 준비되어 있으며, 다음 "자산" 섹션에서 다운로드할 수 있습니다.
## 자산
- [브랜드 가이드라인](/assets/brand_guidelines.pdf): 이 링크(영문판)에서는 상표에 관한 모든 자료를 다운로드할 수 있습니다 - (PDF, 74.3 MB)
- [로고 팩](/assets/logopack.zip): 이 링크에서는 "로고"와 "워드 마크"의 SVG 형식과 PNG 형식의 데이터를 다운로드할 수 있습니다 - (ZIP, 203 KB)
---
"The Tauri Programme within the Commons Conservancy" Conservancy 내의 Tauri 프로그램은 이러한 상표 가이드라인을 언제든지 변경할 권리를 보유합니다. 질문이나 문의 사항이 있는 경우 `trademark@tauri.app`으로 메일을 보내주십시오.
위의 가이드라인은 http://www.modeltrademarkguidelines.org에서 구할 수 있는 "모델 상표 가이드라인"을 기반으로 하며, "크리에이티브 커먼즈 저작자표시 3.0 비이식 라이선스 1.0판 2022/08/20자" (https://creativecommons.org/licenses/by/3.0/deed.en_EU)에 따라 사용되었습니다.

View File

@@ -0,0 +1,31 @@
---
title: 브라운필드 패턴(Brownfield Pattern)
i18nReady: true
---
_**기본 IPC 패턴입니다**_
이 패턴은 Tauri를 사용하는 데 있어 가장 명확하고 이해하기 쉬운 것입니다. 기존 프론트엔드 프로젝트와 최대한 호환되도록 하려고 하기 때문입니다. 간단히 말해, 기존 웹 프론트엔드가 브라우저 내에서 사용하는 것 외에는 다른 것이 필요하지 않도록 되어 있다는 것입니다.
단, 이것은 기존 브라우저 애플리케이션에서 작동하는 **_모든 것_**이 그대로 작동한다는 의미는 아닙니다.
일반적인 "브라운필드"형 소프트웨어 개발에 익숙하지 않은 경우, Wikipedia의 [Brownfield Wikipedia article](<https://en.wikipedia.org/wiki/Brownfield_(software_development)>)(한국어판 없음)에 알기 쉬운 개설이 있습니다.
Tauri의 경우, (브라운필드형 개발의 대상이 되는) 기존 소프트웨어란 레거시 시스템이 아니라 현재 브라우저의 지원과 동작입니다.
## 설정
브라운필드형 개발은 기본 패턴이므로 설정 옵션을 지정할 필요가 없습니다.
명시적으로 설정하려면 `tauri.conf.json` 구성 파일 내의 `tauri > pattern` 객체를 사용합니다.
```json
{
"tauri": {
"pattern": {
"use": "brownfield"
}
}
}
```
_**브라운필드형에서는 추가 설정 옵션이 없습니다.**_
[brownfield wikipedia article]: https://en.wikipedia.org/wiki/Brownfield_(software_development)

View File

@@ -0,0 +1,94 @@
---
title: 프로세스 간 통신
sidebar:
label: Overview
order: 1
i18nReady: true
---
import { CardGrid, LinkCard } from '@astrojs/starlight/components';
"프로세스 간 통신(Inter-Process Communication)"(IPC)은 단일 프로세스가 안전하게 통신할 수 있도록 하여 더 복잡한 애플리케이션을 구축하는 데 핵심적인 역할을 합니다.
구체적인 "프로세스 간 통신(IPC)" 유형(패턴)에 대해서는 다음 설명을 참조하십시오.
<CardGrid>
<LinkCard
title="Brownfield<br>브라운필드형"
href="/ko/concept/inter-process-communication/brownfield/"
/>
<LinkCard
title="Isolation<br>아이솔레이션형"
href="/ko/concept/inter-process-communication/isolation/"
/>
</CardGrid>
Tauri는 [Asynchronous Message Passing](https://ko.wikipedia.org/wiki/메시지_전달)이라는 특별한 스타일의 프로세스 간 통신을 사용합니다. 이 방법에서는 프로세스들이 간단한 데이터 표현을 사용하여 직렬화된 "_요청_"과 "_응답_"을 주고받습니다. 메시지 전달은 인터넷상의 클라이언트-서버 통신에 사용되는 메커니즘이므로 웹 개발 경험이 있는 사람이라면 누구나 익숙할 것입니다.
또한 메시지 전달은 수신자가 필요에 따라 "요청"을 거부하거나 폐기할 수 있으므로 "공유 메모리 방식"이나 "직접 함수 접근 방식"보다 안전한 방법입니다. 예를 들어, Tauri 코어 프로세스가 "요청"을 악의적인 것으로 판단하면 해당 요청은 폐기되고 해당 함수 처리는 실행되지 않습니다.
아래에서는 Tauri의 두 가지 "IPC 프리미티브(동기 기본 명령)", 즉 "이벤트 `Events`"와 "명령 `Commands`"에 대해 자세히 설명합니다.
## 이벤트
"이벤트"는 자동 추적형 단방향 "IPC 메시지"로, 라이프사이클 중 각 이벤트와 상태 변화를 전달하는 데 최적입니다.
"[명령](#명령)"과 달리 "이벤트"는 프론트엔드와 Tauri Core(코어부) 양쪽에서 발행할 수 있습니다.
<figure>
```d2 sketch pad=50
shape: sequence_diagram
Frontend: {
shape: rectangle
label: "Webview\nFrontend"
}
Core: {
shape: rectangle
label: "Core\nBackend"
}
Frontend -> Core: "이벤트"{style.animated: true}
Core -> Frontend: "이벤트"{style.animated: true}
```
<figcaption>코어부와 Webview 간에 주고받는 이벤트</figcaption>
</figure>
## 명령
Tauri는 또한 "IPC 메시지" 외에도 [foreign function interface](https://ko.wikipedia.org/wiki/외부_함수_인터페이스)와 같은 추상화도 제공합니다[^1]. 기본 주요 API인 `invoke`는 브라우저의 `fetch` API와 유사하며, 프론트엔드가 Rust 함수를 호출하고 인수를 전달하며 데이터를 수신할 수 있도록 합니다.
이 메커니즘은 내부적으로 [JSON-RPC]와 같은 프로토콜을 사용하여 요청과 응답을 직렬화하므로 모든 인수와 반환 값 데이터는 JSON 표준에 따라 직렬화 가능해야 합니다.
<figure>
```d2 sketch pad=50
shape: sequence_diagram
Frontend: {
label: "Webview\nFrontend"
}
Core: {
label: "Core\nBackend"
}
InvokeHandler: {
label: "Invoke\nHandler"
}
Frontend -> Core: "IPC 요청"{style.animated: true}
Core -> InvokeHandler: "명령 호출"{style.animated: true}
InvokeHandler -> Core: "반환 값 직렬화"{style.animated: true}
Core -> Frontend: "응답"{style.animated: true}
```
<figcaption>명령 호출에 관련된 IPC 메시지</figcaption>
</figure>
[^1]: 명령은 내부적으로 메시지 전달을 사용하므로 실제 "외부 함수 인터페이스(FFI)"와 같은 보안상의 함정은 없습니다.
[Asynchronous Message Passing]: https://en.wikipedia.org/wiki/Message_passing#Asynchronous_message_passing
[json-rpc]: https://www.jsonrpc.org
[foreign function interface]: https://en.wikipedia.org/wiki/Foreign_function_interface

View File

@@ -0,0 +1,116 @@
---
title: 아이솔레이션 패턴(Isolation Pattern)
i18nReady: true
---
아이솔레이션(분리, 격리) 패턴은 프론트엔드에서 전송된 Tauri API 메시지가 Tauri 코어부에 도달하기 전에 JavaScript를 사용하여 가로채고 변경하는 방법입니다. 아이솔레이션 패턴으로 삽입되는 안전한 JavaScript 코드는 아이솔레이션 애플리케이션이라고 합니다.
## 아이솔레이션 패턴의 필요성
아이솔레이션 패턴의 목적은 Tauri 코어부에 대한 원치 않거나 악의적인 프론트엔드 호출로부터 애플리케이션을 보호하기 위한 메커니즘을 개발자에게 제공하는 것입니다. 아이솔레이션 패턴이 필요하게 된 것은 프론트엔드에서 실행되는 신뢰할 수 없는 콘텐츠로 인해 발생하는 위협에 대응하기 위해 만들어졌습니다. 이러한 위협은 많은 종속성을 가진 애플리케이션에서 흔히 볼 수 있는 사례입니다. 애플리케이션이 마주칠 수 있는 많은 위협 원인의 목록은 [보안: 위협 모델]을 참조하십시오.
위의 가장 큰 위협 모델은 "개발 시 위협"이었지만, 이러한 위협은 아이솔레이션 패턴을 설계할 때 염두에 두었던 것입니다. 많은 프론트엔드 빌드 도구가 종종 깊이 중첩된 수십(또는 수백) 개의 종속성으로 이루어져 있을 뿐만 아니라, 복잡한 애플리케이션 측에도 수많은 (이 또한 종종 깊이 중첩된) 종속성이 있을 수 있으므로 최종 출력 버전에 번들로 제공됩니다.
## 아이솔레이션 패턴을 사용하는 경우
Tauri는 아이솔레이션 패턴을 사용할 수 있는 경우 항상 사용하는 것을 강력히 권장합니다. 아이솔레이션 애플리케이션에서는 프론트엔드의 _**모든**_ 메시지를 "캡처"(인터셉트)하므로 아이솔레이션 패턴이 _항상_ 사용됩니다.
또한 Tauri는 외부 Tauri API를 사용할 때 항상 애플리케이션을 "잠금"(록다운)할 것을 강력히 권장합니다. 앱 개발자는 안전한 아이솔레이션 애플리케이션을 이용하여 IPC 입력을 검증하고, 그 입력 내용이 확실히 예상되는 매개변수 범위 내에 있는지 확인합니다. 사례로는 파일 읽기 또는 쓰기 호출이 해당 애플리케이션의 예상치 못한 위치의 경로에 액세스하려고 하지 않는지 확인하거나, Tauri API의 "HTTP 페치 콜"이 "Origin 헤더"에 해당 애플리케이션이 예상하는 것만 설정하고 있는지 확인하는 것입니다.
하지만 프론트엔드의 _**모든**_ 메시지를 캡처하기 때문에, 상시 동작 API, 예를 들어 [Events] 등에서도 작동합니다. 일부 이벤트에서는 앱 고유의 Rust 코드로 작업을 실행시킬 가능성이 있으므로, 그에도 유사한 검증 방법으로 대응할 수 있습니다.
## 아이솔레이션 패턴의 적용
아이솔레이션 패턴에서 중요한 것은 프론트엔드와 Tauri Core(타우리 코어부) 사이에 안전한 애플리케이션을 삽입하여 IPC 수신 메시지를 캡처하고 수정하는 것입니다. 이는 `<iframe>`의 샌드박스 기능(격리 기능)을 사용하여 메인 프론트엔드 애플리케이션과 병행하여 JavaScript를 안전하게 실행함으로써 실현됩니다. Tauri는 페이지 로드 중에 아이솔레이션 패턴을 발동하여 Tauri Core에 대한 모든 IPC 호출을 직접이 아닌 샌드박스화(격리화)된 아이솔레이션 애플리케이션을 통해 강제로 라우팅을 전환합니다. Tauri Core에 전달될 메시지가 준비되면, 메시지는 브라우저 구현의 [SubtleCrypto]를 사용하여 암호화되어 메인 프론트엔드 애플리케이션으로 반환됩니다.
프론트엔드로 돌아오자마자 메시지는 직접 Tauri Core로 전달되어 거기서 평소와 같이 복호화되어 읽힙니다.
누군가가 애플리케이션의 특정 버전의 키를 수동으로 읽고 암호화 후 해당 키를 사용하여 메시지를 변경할 수 없도록 하기 위해, 애플리케이션이 실행될 때마다 새로운 키가 생성됩니다.
### IPC 메시지의 대략적인 절차
동작 흐름을 알기 쉽게 하기 위해, 아이솔레이션 패턴의 IPC 메시지가 Tauri Core로 전송될 때 실행되는 대략적인 절차를 순서 있는 목록으로 아래에 나타냅니다:
1. Tauri의 IPC 핸들러가 메시지를 받습니다
2. IPC 핸들러 → 아이솔레이션 애플리케이션
3. `[sandbox]` 아이솔레이션 애플리케이션의 후크가 실행되어 메시지를 변경할 수 있습니다.
4. `[sandbox]` 메시지는 "실행 시 생성되는 키"를 사용하여 AES-GCM으로 암호화됩니다
5. `[encrypted]` 아이솔레이션 애플리케이션 → IPC 핸들러
6. `[encrypted]` IPC 핸들러 → Tauri Core
_참고: 화살표(→)는 메시지 전달(패싱)을 나타냅니다._
### 성능에 미치는 영향
안전한 아이솔레이션 애플리케이션은 메시지 암호화가 이루어지기 때문에, 아무것도 하지 않는 경우에도 [브라운필드 패턴]과 비교하여 추가적인 오버헤드 비용이 발생합니다. (적절한 성능을 유지하기 위해 신중하게 유지 관리되고 종속성도 적을) 성능 중심의 애플리케이션을 제외하면, 대부분의 애플리케이션은 비교적 작고 AES-GCM 암호화 방식도 비교적 빠르기 때문에 IPC 메시지의 암호화/복호화 실행 시 비용을 의식할 필요는 없습니다. 만약 AES-GCM에 익숙하지 않더라도, 여기서 관련된 것은 그것이 [SubtleCrypto]에 포함된 유일한 인증 모드 알고리즘이며, 아마도 "[TLS][transport_layer_security] 암호화 프로토콜" 내부에서 이미 매일 사용하고 있다는 것뿐입니다.
Tauri 애플리케이션이 시작될 때마다 한 번, 암호화된 안전한 키도 생성되지만, 시스템이 이미 충분한 엔트로피(랜덤성)를 갖추고 있어 즉시 충분한 난수를 반환한다면 이 처리에는 보통 눈치채지 못합니다. 이는 "데스크톱 환경"에서는 매우 일반적입니다. "헤드리스 환경"에서 [WebDriver와의 통합 테스트] 등을 실행하는 경우, 운영 체제에 엔트로피 생성 서비스<번역 주: "난수 생성" 기능>가 포함되어 있지 않은 경우에는 `haveged`와 같은 어떤 엔트로피 생성 서비스를 설치하는 것을 권장합니다. <sup>Linux 5.6 (2020년 3월) 버전부터 추측 실행에 의한 엔트로피 생성이 포함되었습니다.</sup>
### 제한 사항
아이솔레이션 패턴에는 플랫폼과의 불일치로 인해 발생하는 몇 가지 제한 사항이 있습니다. 가장 중대한 제한은 Windows의 샌드박스화된 `<iframes>` 내에 외부 파일이 올바르게 로드되지 않는 것입니다. 이 때문에 아이솔레이션 애플리케이션과 관련된 스크립트의 내용을 가져와 인라인으로 삽입하는, 빌드 시 간단한 스크립트 인라인화 절차를 구현했습니다. 즉, 이는 `<script src="index.js"></script>`와 같은 파일의 일반적인 번들, 또는 단순한 삽입은 여전히 정상적으로 작동하지만, ES Modules(ECMAScript Modules)와 같은 새로운 메커니즘은 잘 로드되지 **않는다**는 것을 의미합니다.
## 권장 사항
아이솔레이션 애플리케이션의 목적은 개발 시 위협으로부터 보호하는 것이므로, 아이솔레이션 애플리케이션은 가능한 한 단순하게 유지하는 것을 강력히 권장합니다. 종속성을 최소한으로 유지하도록 노력할 뿐만 아니라, 필요한 빌드 절차를 최소한으로 줄이는 것을 검토해야 합니다. 이를 통해 프론트엔드 애플리케이션을 덮고 있는 아이솔레이션 애플리케이션에 대한 공급망 공격에 대해 걱정할 필요가 없어집니다.
## 아이솔레이션 애플리케이션 만들기
다음 예에서는 작은 "hello-world"와 같은 아이솔레이션 애플리케이션을 만들고, 그것을 가상으로 기존 Tauri 애플리케이션에 연결하는 것을 가정합니다. 이 앱에서는 통과하는 메시지의 검증은 수행되지 않고, WebView 콘솔에 내용이 출력될 뿐입니다.
이 사례의 목적을 위해, `tauri.conf.json`과 같은 디렉토리에 있다고 가정합니다. 기존 Tauri 애플리케이션의 `distDir``../dist`로 설정되어 있습니다.
`../dist-isolation/index.html`:
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
```
`../dist-isolation/index.js`:
```javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// 아무것도 검증하거나 수정하지 않고, 그냥 hook에서 내용을 인쇄하기만 합니다.
console.log('hook', payload);
return payload;
};
```
이제 아이솔레이션 패턴을 사용하도록 `tauri.conf.json`의 [설정](#설정)을 변경하고, 부트 처리 경로를 [브라운필드 패턴]에서 아이솔레이션 패턴으로 전환하기만 하면 됩니다.
## 설정
메인 프론트엔드 `distDir``../dist`로 설정되어 있다고 가정합니다. 또한, 아이솔레이션 애플리케이션을 `../dist-isolation`에 출력합니다.
```json
{
"build": {
"distDir": "../dist"
},
"app": {
"security": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../dist-isolation"
}
}
}
}
}
```
[transport_layer_security]: https://ko.wikipedia.org/wiki/전송_계층_보안
[보안: 위협 모델]: /ko/security/lifecycle/
[events]: /ko/reference/javascript/api/namespaceevent/
[subtlecrypto]: https://developer.mozilla.org/ko/docs/Web/API/SubtleCrypto
[브라운필드 패턴]: /ko/concept/inter-process-communication/brownfield/
[WebDriver와의 통합 테스트]: /ko/develop/tests/webdriver/

View File

@@ -0,0 +1,187 @@
---
title: Tauri 아키텍처
sidebar:
order: 0
i18nReady: true
---
## 소개
Tauri는 매우 구축하기 쉽고 엔지니어가 다양한 애플리케이션을 만들 수 있는 다국어 범용 툴킷입니다. Rust 도구와 Webview로 렌더링되는 HTML의 조합을 사용하여 데스크톱 컴퓨터용 애플리케이션을 구축하는 데 사용됩니다. Tauri로 구축된 앱에는 JavaScript API/Rust API를 얼마든지 동봉할 수 있으므로 Webview는 메시지 전달 기능을 통해 시스템을 제어할 수 있습니다. 개발자는 기본 API를 고유한 기능으로 확장하고 Webview와 Rust 기반 백엔드를 쉽게 연결할 수 있습니다.
Tauri 앱은 [트레이 인터페이스](/ko/learn/system-tray/)(시스템 트레이/작업 트레이)를 사용할 수 있습니다. 또한 앱은 [앱 자동 업데이트](/ko/plugin/updater/)를 사용하여 예상대로 사용 중인 운영 체제에서 관리되도록 할 수 있습니다. OS의 WebView를 사용하기 때문에 앱 크기는 매우 작고 최종 바이너리(앱 실행 파일)가 Rust에서 컴파일되므로 런타임(실행 파일)은 제공되지 않습니다. 이 때문에 [Tauri 앱의 역분석은 쉽지 않습니다](/ko/security/).
### Tauri는 ~가 아닙니다
Tauri는 경량 커널 래퍼가 아닙니다. 대신 OS에 대한 시스템 호출을 실행할 때 WebView 렌더링 라이브러리인 [WRY](#wry라이)와 창 생성 라이브러리인 [TAO](#tao타오)를 직접 사용하여 무겁고 번거로운 처리를 실행합니다.
Tauri는 가상 머신(VM)이나 가상 환경도 아닙니다. 대신 WebView OS 애플리케이션을 만들 수 있는 애플리케이션 툴킷입니다.
## 코어 에코시스템
<figure>
```d2 sketch pad=50
direction: up
Core: {
shape: rectangle
"tauri": {
"tauri-runtime"
"tauri-macros"
"tauri-utils"
}
"tauri-build"
"tauri-codegen"
"tauri-runtime-wry"
}
Upstream: {
shape: rectangle
direction: right
WRY
TAO
}
Core."tauri"."tauri-runtime" -> Core."tauri-runtime-wry"{style.animated: true}
Upstream.WRY -> Upstream.TAO{style.animated: true}
Core."tauri-runtime-wry" -> Upstream.Wry {style.animated: true}
```
<figcaption>Tauri 아키텍처 구성 약도</figcaption>
</figure>
### tauri(타우리)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri)
"tauri 부"가 모든 것을 종합하는 주요 크레이트입니다. 여기서 런타임, 매크로, 유틸리티, API를 하나의 최종 제품으로 통합합니다. 컴파일 시 [`tauri.conf.json`](/reference/config/) 파일을 읽어 기능 도입과 앱의 실제 구성 설정(심지어 프로젝트 폴더 내의 `Cargo.toml` 파일 설정까지)을 수행합니다. 실행 시에는 스크립트 삽입을 처리하고(폴리필 코드나 프로토타입 개정용), 시스템 조작용 API를 호스트(실행 가능하게)하고, 업데이트 프로세스도 관리합니다.
### tauri-runtime(타우리 런타임)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime)
"tauri-runtime"은 Tauri 본체와 하위 수준의 Webview 라이브러리를 연결하는 레이어입니다.
### tauri-macros(타우리 매크로)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-macros)
"tauri-macros"는 [`tauri-codegen`](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-codegen) 크레이트를 활용하여 컨텍스트, 핸들러 및 명령 매크로를 만듭니다.
### tauri-utils(타우리 유틸리티)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-utils)
"tauri-utils"는 설정 파일 분석, 동작 환경(3대 플랫폼) 감지, CSP(클라우드 서비스 제공업체) 삽입, 자산 관리 등 여러 곳에서 재사용되며 편리한 유틸리티를 제공하는 공통 코드입니다.
### tauri-build(타우리 빌드)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-build)
"tauri-build"는 빌드 시 매크로를 적용하여 `cargo`에 필요한 몇 가지 특별한 기능을 갖추게 합니다.
### tauri-codegen(타우리 코드젠)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-codegen)
"tauri-codegen"은 앱 아이콘이나 시스템 트레이 등을 포함한 자산(디지털 자산)을 내장, 해시화, 압축합니다. 컴파일 시 [`tauri.conf.json`](/ko/reference/config/)을 분석하여 Config 구조체를 생성하는 코드 생성 도구입니다.
### tauri-runtime-wry(타우리 런타임 라이)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime-wry)
"tauri-runtime-wry". 이 크레이트는 인쇄, 모니터 감지, 기타 창 관련 작업 등 특히 WRY용 직접적인 시스템 수준의 "대화형 조작"(상호 작용)을 시작합니다.
## Tauri Tooling(타우리 도구)
### API (JavaScript / TypeScript)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/packages/api)
Typescript 라이브러리로, `cjs`(CommonJS 모듈) 및 `esm`(ECMAScript 모듈)이라는 JavaScript 표준 입출력 엔드포인트를 만들어 프론트엔드(사용자 인터페이스) 프레임워크로 가져옵니다. 이를 통해 Webview가 백엔드(프로그램 내부 처리)에서의 활동을 호출하고 응답 대기(수신)할 수 있게 됩니다. 또한 일부 프레임워크에서는 더 최적의 형태인 순수한 Typescript만으로도 제공됩니다. 이 라이브러리는 Webview에서 각 호스트(연결 대상)로의 메시지 전달 기능(처리 요청)을 사용합니다.
### Bundler (Rust / Shell)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-bundler)
Bundler(번들러)는 감지되거나 통지된 플랫폼(os)용 Tauri 앱을 구축하는 라이브러리입니다. 현재는 macOS, Windows, Linux를 지원하지만 가까운 장래에 모바일 플랫폼도 지원될 예정입니다. Tauri 프로젝트 이외에도 사용할 수 있을 가능성이 있습니다.
### cli.rs (Rust)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-cli)
이 Rust 실행 파일은 CLI(명령줄 인터페이스)에 필요한 모든 활동에 대한 완전한 인터페이스를 제공합니다. 이 프로그램은 macOS, Windows, Linux 중 하나에서 작동합니다.
### cli.js (JavaScript)
[GitHub에서 보기](https://github.com/tauri-apps/tauri/tree/dev/packages/cli)
cli.js는 [`napi-rs`](https://github.com/napi-rs/napi-rs)를 사용하여 [`cli.rs`](https://github.com/tauri-apps/tauri/blob/dev/crates/tauri-cli)를 모든 플랫폼(os)에서 사용할 수 있도록 한 래퍼로, npm 패키지(Node.js Package Manager)를 생성합니다.
### create-tauri-app (JavaScript)
[GitHub에서 보기](https://github.com/tauri-apps/create-tauri-app)
이 툴킷은 선택한 프론트엔드 프레임워크를 사용하여 기술팀이 새로운 `tauri-apps` 프로젝트를 신속하게 구축할 수 있도록 하기 위한 것입니다(설정이 되어 있는 경우).
## 상위 크레이트
Tauri-Apps의 구조에는 Tauri의 "상위"에 두 개의 크레이트, 즉 애플리케이션 창 생성 및 관리를 수행하는 "TAO(타오)"와 창 내의 Webview와 연동하는 "wry(라이)"를 관리하고 있습니다.
### TAO(타오)
[GitHub에서 보기](https://github.com/tauri-apps/tao)
"Tao(타오)"는 Rust의 크로스 플랫폼 애플리케이션 창 생성 라이브러리로, Windows, macOS, Linux, iOS, Android 등 모든 주요 플랫폼을 지원합니다. Rust로 작성되었으며, 메뉴 바나 시스템 트레이 등 Tauri 고유의 요구에 맞게 확장된 [winit](https://github.com/rust-windowing/winit)의 포크입니다.
### WRY(라이)
[GitHub에서 보기](https://github.com/tauri-apps/wry)
"WRY(라이)"는 Rust의 크로스 플랫폼 WebView 렌더링 라이브러리로, Windows, macOS, Linux 등 주요 데스크톱 플랫폼을 모두 지원합니다.
Tauri는 WRY를 추상 레이어로 사용하여 어떤 Webview가 사용될지(그리고 어떻게 상호 작용/상호 통신이 이루어질지)를 결정하는 역할을 합니다.
## 기타 도구
### tauri-action(타우리 액션)
[GitHub에서 보기](https://github.com/tauri-apps/tauri-action)
tauri-action은 모든 플랫폼용 Tauri 바이너리를 빌드하는 GitHub 워크플로(자동화 프로세스)입니다. Tauri가 설정되어 있지 않은 경우에도 (매우 간단한) Tauri 앱을 만들 수 있습니다.
### tauri-vscode
[GitHub에서 보기](https://github.com/tauri-apps/tauri-vscode)
이 도구는 몇 가지 "있으면 편리한 기능"으로 Visual Studio Code의 인터페이스를 강화합니다.
### vue-cli-plugin-tauri
[GitHub에서 보기](https://github.com/tauri-apps/vue-cli-plugin-tauri)
이 도구를 사용하면 vue-cli 프로젝트에 빠르게 Tauri를 설치할 수 있습니다.
## 플러그인
[Tauri 플러그인 가이드](/develop/plugins/)
일반적으로 플러그인은 타사에서 만듭니다(공식적으로 지원되는 플러그인이 있을 수도 있습니다). 플러그인은 일반적으로 다음 세 가지 작업을 수행합니다.
1. Rust 코드를 "무언가를 하기 위해" 실행 가능하게 만듭니다.
2. 앱에 쉽게 통합할 수 있는 인터페이스의 글루(glue) 기능을 제공합니다.
3. Rust 코드와 인터페이스하기 위한 JavaScript API를 제공합니다.
다음은 Tauri의 플러그인 예입니다.
- [tauri-plugin-fs](https://github.com/tauri-apps/tauri-plugin-fs)
- [tauri-plugin-sql](https://github.com/tauri-apps/tauri-plugin-sql)
- [tauri-plugin-stronghold](https://github.com/tauri-apps/tauri-plugin-stronghold)
## 라이선스
Tauri 자체는 MIT 또는 Apache-2.0 라이선스에 따라 배포됩니다. 귀하가 Tauri를 재패키징하고 소스 코드를 변경하는 경우, 모든 상위 라이선스를 준수하는지 확인하는 책임은 귀하에게 있습니다. Tauri는 있는 그대로 보증 없이 제공되며, 어떤 목적에 대해서도 그 적합성을 명시적으로表明하지 않습니다.
여기서 [소프트웨어 상태 관리표](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri)의 자세한 내용을 확인할 수 있습니다.

View File

@@ -0,0 +1,39 @@
---
title: 기본 설계 사상
sidebar:
order: 0
label: 개요
i18nReady: true
---
import { CardGrid, LinkCard } from '@astrojs/starlight/components';
Tauri에는 핵심적인 설계 사상이 몇 가지 있습니다. 이러한 항목은 애플리케이션을 개발할 때 개발자가 알아야 할 사항입니다. 다음은 Tauri 프레임워크를 최대한 활용하기 위해 더 자세히 이해해야 할 개념입니다.
<CardGrid>
<LinkCard
title="Tauri 아키텍처"
href="/ko/concept/architecture/"
description="기본 설계와 생태계"
/>
<LinkCard
title="프로세스 간 통신(IPC)"
href="/ko/concept/inter-process-communication/"
description="프로세스 간 통신의 내부 구조"
/>
<LinkCard
title="안전성"
href="/ko/security/"
description="Tauri의 안전성 강화 시책"
/>
<LinkCard
title="프로세스 모델"
href="/ko/concept/process-model/"
description="Tauri가 관리하는 프로세스와 그 이유"
/>
<LinkCard
title="앱 크기"
href="/ko/concept/size/"
description="앱 크기를 최소화하는 방법"
/>
</CardGrid>

View File

@@ -0,0 +1,83 @@
---
title: 프로세스 모델
sidebar:
order: 0
i18nReady: true
---
Tauri는 Electron이나 많은 최신 웹 브라우저와 같은 멀티 프로세스 아키텍처를 채택하고 있습니다. 이 가이드에서는 이러한 설계 방침의 선택 이유와 그것이 안전한 애플리케이션을 만드는 데 왜 중요한지에 대해 설명합니다.
## 멀티 프로세스인 이유
GUI(그래픽 사용자 인터페이스) 애플리케이션의 초기에는 계산, 인터페이스 그리기, 사용자 입력에 대한 반응을 하나의 프로세스에서 실행하는 것이 일반적이었습니다. 상상할 수 있듯이, 이 프로세스는 시간이 많이 걸리는 고부하 계산 처리로 인해 사용자 인터페이스가 응답하지 않게 되거나, 더 나쁜 경우에는 하나의 앱 구성 요소의 장애가 앱 전체의 충돌을 일으키는 것을 의미했습니다.
이 결과, 더 강력한 아키텍처가 필요하다는 것이 분명해졌고, 애플리케이션은 다른 구성 요소를 다른 프로세스에서 실행하게 되었습니다. 이를 통해 최신 멀티 코어 CPU를 더 효과적으로 활용하고 훨씬 안전한 애플리케이션을 만들 수 있습니다. 각 구성 요소는 다른 프로세스에 분산되어 실행되므로 하나의 구성 요소에서 충돌이 발생해도 시스템 전체에 영향을 미치지 않습니다. 프로세스가 비활성 상태가 된 경우 간단히 해당 프로세스를 다시 시작할 수 있습니다.
또한 각 프로세스에 해당 작업을 완료하는 데 필요한 최소한의 권한만 부여함으로써 잠재적인 약점의 영향 범위를 제한할 수도 있습니다. 이 방법은 [최소 권한의 원칙]으로 알려져 있으며 현실 세계에서 흔히 볼 수 있습니다. 울타리 손질을 위해 정원사가 왔을 때, 정원 열쇠는 주지만 집 열쇠는 **주지 않을** 것입니다(집 안 출입은 정원사에게 필요 없겠죠?). 같은 생각이 컴퓨터 프로그램에도 적용됩니다. 접근 권한이 적을수록 침입당했을 때의 피해가 줄어듭니다.
## 코어 프로세스
각 Tauri 애플리케이션에는 "코어 프로세스"가 있으며, 이것이 애플리케이션의 "진입점"으로 기능합니다. 코어 프로세스는 운영 체제에 대한 전체 액세스 권한을 가진 유일한 구성 요소입니다.
이 "코어부"의 첫 번째 역할은 해당 액세스 권한을 사용하여 "애플리케이션 창", "시스템 트레이 메뉴" 및 "알림"을 만들고 조정하는 것입니다. Tauri는 이러한 처리를 쉽게 하기 위해 필요한 크로스 플랫폼 추상화를 구현합니다. 또한 모든 [프로세스 간 통신](IPC)을 "코어 프로세스"를 통해 전송하고, IPC 메시지를 이 중앙 부분 한 곳에서 가로채고, 필터링하고, 조작할 수 있도록 합니다.
"코어 프로세스"는 설정이나 데이터베이스 연결과 같은 "전역 상태"의 관리도 담당해야 합니다. 이를 통해 창 간의 상태를 쉽게 동기화하고, 프론트엔드에서 엿보려는 외부의 의심스러운 눈으로부터 비즈니스 기밀 데이터를 보호할 수 있습니다.
우리가 Tauri의 구현에 Rust를 선택한 것은 [소유권] 개념 덕분에
우수한 성능을 유지하면서 메모리 안전성이 보장되기 때문입니다.
<figure>
```d2 sketch pad=50
direction: right
Core: {
shape: diamond
}
"Events & Commands 1": {
WebView1: WebView
}
"Events & Commands 2": {
WebView2: WebView
}
"Events & Commands 3": {
WebView3: WebView
}
Core -> "Events & Commands 1"{style.animated: true}
Core -> "Events & Commands 2"{style.animated: true}
Core -> "Events & Commands 3"{style.animated: true}
"Events & Commands 1" -> WebView1{style.animated: true}
"Events & Commands 2" -> WebView2{style.animated: true}
"Events & Commands 3" -> WebView3{style.animated: true}
```
<figcaption>Tauri 프로세스 모델의 약도. 하나의 "코어 프로세스"가 하나 이상의 WebView 프로세스를 제어합니다.</figcaption>
</figure>
## WebView 프로세스
"코어 프로세스"가 실제 사용자 인터페이스(UI)를 렌더링하는 것은 아닙니다. 운영 체제에서 제공하는 WebView 라이브러리를 이용하여 WebView 프로세스를 시작하는 것입니다. WebView는 브라우저와 같은 환경으로, 여러분이 만든 HTML, CSS, JavaScript를 실행하는 것입니다.
이는 즉, 기존 웹 개발에서 사용되는 대부분의 기법과 도구를 Tauri 애플리케이션 제작에 사용할 수 있다는 것을 의미합니다. 예를 들어, Tauri의 참고 사례 대부분이 [Svelte] 프론트엔드 프레임워크와 [Vite] 번들러를 사용하여 만들어졌습니다.
보안 면에서도 최선의 방법이 취해지고 있습니다. 예를 들어, 사용자 입력을 항상 살균(무해화)하고, 프론트엔드에서는 결코 민감한 정보를 처리하지 않도록 하며, 이상적으로는 공격 대상 영역을 작게 유지하기 위해 가능한 한 많은 비즈니스 로직(업무 처리 절차)을 "코어 프로세스"에 위임해야 합니다.
다른 유사한 방법과 달리, WebView 라이브러리는 최종 실행 파일에 **포함되지 않고** 실행 시 동적으로 링크됩니다[^1]. 이를 통해 애플리케이션은 _상당히_ 작아지지만, 기존 웹 개발과 마찬가지로 플랫폼의 차이에 유의해야 한다는 것도 의미합니다.
[^1]:
현재 Tauri는 Windows에서는 [Microsoft Edge WebView2]를, macOS에서는 [WKWebView]를,
Linux에서는 [webkitgtk]를 사용합니다.
[최소 권한의 원칙]: https://ko.wikipedia.org/wiki/최소_권한의_원칙
[프로세스 간 통신]: /ko/concept/inter-process-communication/
[소유권]: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
[microsoft edge webview2]: https://docs.microsoft.com/ko-kr/microsoft-edge/webview2/
[wkwebview]: https://developer.apple.com/documentation/webkit/wkwebview
[webkitgtk]: https://webkitgtk.org
[svelte]: https://svelte.dev/
[vite]: https://vitejs.dev/

View File

@@ -0,0 +1,71 @@
---
title: 앱 크기
sidebar:
order: 0
i18nReady: true
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
Tauri는 기본적으로 매우 작은 바이너리 크기를 가지지만, 그 한계를 조금 더 넓혀도 문제는 없습니다. 여기서는 최적의 결과를 얻기 위한 몇 가지 팁과 요령을 소개합니다.
## Cargo 설정
작업 중인 프로젝트에 대해 프론트엔드에 의존하지 않고 수행할 수 있는 가장 간단한 크기 개선 중 하나는 "Cargo 프로필"을 추가하는 것입니다.
Stable 버전(안정판)의 Rust 툴체인을 사용하는지, Nightly 버전(나이틀리판/최신 개발판)의 Rust 툴체인을 사용하는지에 따라 사용할 수 있는 옵션이 약간 다릅니다. 고급 사용자가 아닌 경우 안정판 툴체인을 사용하는 것이 좋습니다.
<Tabs>
<TabItem label="Stable">
```toml
# src-tauri/Cargo.toml
[profile.dev]
incremental = true # 바이너리를 더 작은 단계로 컴파일합니다.
[profile.release]
codegen-units = 1 # LLVM이 더 나은 최적화를 수행할 수 있도록 합니다.
lto = true # 링크 타임 최적화를 활성화합니다.
opt-level = "s" # 작은 바이너리 크기를 우선시합니다. 속도를 선호하는 경우 `3`을 사용하십시오.
panic = "abort" # 패닉 핸들러를 비활성화하여 성능을 향상시킵니다.
strip = true # 디버그 심볼이 제거되도록 합니다.
````
</TabItem>
<TabItem label="Nightly">
```toml
# src-tauri/Cargo.toml
[profile.dev]
incremental = true # 바이너리를 더 작은 단계로 컴파일합니다.
rustflags = ["-Zthreads=8"] # 더 나은 컴파일 성능.
[profile.release]
codegen-units = 1 # LLVM이 더 나은 최적화를 수행할 수 있도록 합니다.
lto = true # 링크 타임 최적화를 활성화합니다.
opt-level = "s" # 작은 바이너리 크기를 우선시합니다. 속도를 선호하는 경우 `3`을 사용하십시오.
panic = "abort" # 패닉 핸들러를 비활성화하여 성능을 향상시킵니다.
strip = true # 디버그 심볼이 제거되도록 합니다.
trim-paths = "all" # 바이너리에서 잠재적으로 권한 있는 정보를 제거합니다.
rustflags = ["-Cdebuginfo=0", "-Zthreads=8"] # 더 나은 컴파일 성능.
````
</TabItem>
</Tabs>
### 참고 정보
:::note
아래 목록은 사용 가능한 모든 옵션을 나열한 전체 버전이 아니라, 특히 주목해야 할 옵션을 기재한 것입니다.
:::
- [incremental:](https://doc.rust-lang.org/cargo/reference/profiles.html#incremental) 바이너리를 더 세분화된 단위로 컴파일합니다.
- [codegen-units:](https://doc.rust-lang.org/cargo/reference/profiles.html#codegen-units) 컴파일 시간 최적화를 희생하여 컴파일 시간을 단축합니다.
- [lto:](https://doc.rust-lang.org/cargo/reference/profiles.html#lto) 링크 시 최적화를 활성화합니다.
- [opt-level:](https://doc.rust-lang.org/cargo/reference/profiles.html#opt-level) 컴파일러의 초점 내용을 결정합니다. "성능" 최적화에는 `3`을, "크기" 최적화에는 `z`를, 그 "중간"에는 `s`를 지정합니다.
- [panic:](https://doc.rust-lang.org/cargo/reference/profiles.html#panic) 오류 처리 시 "패닉 언와인드"(이상, 되감기 정보)를 삭제하여 크기를 줄입니다.
- [strip:](https://doc.rust-lang.org/cargo/reference/profiles.html#strip) 바이너리에서 심볼 또는 디버그 정보를 제거합니다.
- [rpath:](https://doc.rust-lang.org/cargo/reference/profiles.html#rpath) 바이너리 내에 필요 정보를 기록(하드 코딩)하여 바이너리에 필요한 동적 라이브러리를 찾는 데 도움을 줍니다.
- [trim-paths:](https://rust-lang.github.io/rfcs/3127-trim-paths.html) 바이너리에서 기밀일 수 있는 정보를 제거합니다.
- [rustflags:](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option) 프로필별로 Rust 컴파일러 플래그를 설정합니다.
- `-Cdebuginfo=0`: 빌드에 "debuginfo 심볼"을 포함할지 여부를 지정합니다.
- `-Zthreads=8`: 컴파일 시 사용되는 스레드 수를 늘립니다.

View File

@@ -0,0 +1,58 @@
---
title: CrabNebula DevTools
sidebar:
badge:
text: New
variant: tip
i18nReady: true
---
import { Image } from 'astro:assets';
import devToolsPrint from '@assets/develop/Debug/crabnebula-devtools.png';
[CrabNebula](https://crabnebula.dev/) 사는 Tauri 프로젝트와의 파트너십의 일환으로, Tauri용 무료 [DevTools](https://crabnebula.dev/devtools/) 애플리케이션을 제공합니다. 이 애플리케이션을 사용하면 내장된 애셋, Tauri 구성 파일, 로그, 스팬을 가져와 웹 프론트엔드를 제공함으로써 데이터를 실시간으로 원활하게 시각화할 수 있도록 Tauri 앱을 보강할 수 있습니다.
> > > 《번역 주》 **크랩네뷸라** Tauri의 공식 파트너 기업명. Crab(“게”) + Nebula(성운)의 의미. Rust(게)・Tauri(황소자리)・CrabNebula(게성운)이라는 흐름.
CrabNebula DevTools에서는 페이로드(전송 데이터 본체)나 응답, 내부 로그, 실행 기간 등을 포함하는 Tauri의 이벤트나 커맨드용 특별한 인터페이스를 이용하여, 앱의 로그 이벤트(의존 관계로부터의 로그를 포함합니다)를 검사하고, 커맨드 호출의 퍼포먼스와 Tauri API의 전체적인 사용 상황을 추적할 수 있습니다.
CrabNebula DevTools를 활성화하려면, devtools 크레이트를 설치합니다:
```sh frame=none
cargo add tauri-plugin-devtools@2.0.0
```
그리고, 메인 함수에서 가능한 한 빨리 플러그인을 초기화합니다:
```rust
fn main() {
// 이것은 앱 실행의 가능한 한 빠른 단계에서 호출해야 합니다
#[cfg(debug_assertions)] // 개발 빌드에의 도입만을 유효하게 합니다
let devtools = tauri_plugin_devtools::init();
let mut builder = tauri::Builder::default();
#[cfg(debug_assertions)]
{
builder = builder.plugin(devtools);
}
builder
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
그 후, 통상대로 앱을 실행합니다. 모든 것이 올바르게 설정되어 있으면, devtools는 다음의 메시지를 출력합니다:
<Image src={devToolsPrint} alt="DevTools message on terminal" />
:::note
이 건에서는, 디버그 애플리케이션용의 devtools 플러그인만을 초기화하고 있습니다. 이 방법이 권장됩니다.
:::
자세한 내용은 [CrabNebula DevTools](https://docs.crabnebula.dev/devtools/get-started/)의 도큐먼트를 참조해 주세요.
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,162 @@
---
title: 디버깅
sidebar:
label: 개요
order: 10
i18nReady: true
---
import CommandTabs from '@components/CommandTabs.astro';
Tauri에는 많은 동작 부분이 있으므로 디버깅이 필요한 문제에 직면할 수 있습니다. 오류 세부 정보가 출력되는 곳은 여러 곳이 있으며, Tauri에는 디버깅 프로세스를 더 쉽게 만들어주는 몇 가지 도구도 있습니다.
## 개발 전용 코드
디버깅용 툴킷 중에서 가장 유용한 도구 중 하나는 코드에 디버그 문을 추가하는 기능입니다. 그러나 이러한 기능이 프로덕션 환경에까지 들어가는 것은 일반적으로 바람직하지 않습니다. 여기서 "개발 모드에서 실행 중인지 여부"를 확인하는 기능이 유용합니다.
### Rust에서
```rs frame=none
fn main() {
// 현재 인스턴스가 `tauri dev`로 시작되었는지 여부.
#[cfg(dev)]
{
// `tauri dev` 전용 코드 기재
}
if cfg!(dev) {
// `tauri dev` 전용 코드 기재
} else {
// `tauri build` 전용 코드 기재
}
let is_dev: bool = tauri::is_dev();
// 디버그 어설션이 활성화되어 있는지 여부. 이는 `tauri dev`와 `tauri build --debug`에서 "true"가 됩니다.
#[cfg(debug_assertions)]
{
// 디버그 전용 코드 기재
}
if cfg!(debug_assertions) {
// 디버그 전용 코드 기재
} else {
// 프로덕션 전용 코드 기재
}
}
```
> > > 《번역 주》 **디버그 어설션** debug assertions. 프로그램 중에 충족되어야 할 조건(어설션)을 기술하여 실행 시에 체크하는 구조.
{/* TODO: js version */}
## Rust 콘솔
오류를 확인하는 첫 번째 장소는 "Rust 콘솔"입니다. 이것은 (`tauri dev` 등을 실행하는) 터미널 내에 있습니다. 다음 코드를 사용하면 Rust 파일 내에서 콘솔에 정보를 출력할 수 있습니다.
```rust frame=none
println!("Message from Rust: {}", msg);
```
때로는 작성한 Rust 코드에 오류가 발생할 수 있지만, Rust 컴파일러가 많은 정보를 제공해 줍니다. 예를 들어, `tauri dev`가 충돌했을 때 다음과 같이 다시 실행할 수 있습니다. Linux 및 macOS에서는:
```shell frame=none
RUST_BACKTRACE=1 tauri dev
```
Windows(PowerShell)에서는 다음과 같습니다:
```powershell frame=none
$env:RUST_BACKTRACE=1
tauri dev
```
이 명령은 상세한 스택 트레이스를 제공합니다.
종합적으로 보면, Rust 컴파일러는 문제에 대한 상세한 정보를 제공하여 문제 해결에 도움을 줍니다. 예를 들어:
```bash frame=none
error[E0425]: cannot find value `sun` in this scope
--> src/main.rs:11:5
|
11 | sun += i.to_string().parse::<u64>().unwrap();
| ^^^ help: a local variable with a similar name exists: `sum`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.
```
> > > 《번역 주》 **스택 트레이스** stack trace. 프로그램 오류 발생 시, 해당 오류에 이르기까지의 함수 호출 이력이나 메서드 등을 기록한 것. 자세한 내용은 [Wikipedia](https://ko.wikipedia.org/wiki/스택_추적)를 참조하십시오.
## WebView 콘솔
WebView를 마우스 오른쪽 버튼으로 클릭하고 `Inspect Element`(요소 검사)를 선택합니다. 그러면 익숙한 Chrome이나 Firefox 개발자 도구와 유사한 "웹 인스펙터"가 열립니다.
Linux와 Windows에서는 단축키 `Ctrl + Shift + i`를, macOS에서는 `Command + Option + i`를 사용하여 이 "인스펙터"를 열 수도 있습니다.
"인스펙터"는 플랫폼에 따라 다르며, Linux에서는 "webkit2gtk WebInspector", macOS에서는 "Safari 인스펙터", Windows에서는 "Microsoft Edge DevTools"를 렌더링합니다.
### 프로그램에서 Devtools 열기
인스펙터 창의 가시성을 조정하려면 [`WebviewWindow::open_devtools`] 및 [`WebviewWindow::close_devtools`] 함수를 사용합니다.
```rust
tauri::Builder::default()
.setup(|app| {
#[cfg(debug_assertions)] // 이 코드는 디버그 빌드에만 기재하십시오.
{
let window = app.get_webview_window("main").unwrap();
window.open_devtools();
window.close_devtools();
}
Ok(())
});
```
### 프로덕션 환경에서 인스펙터 사용
인스펙터는 기본적으로 개발 및 디버그 빌드에서만 활성화되어 있으므로 프로덕션 환경에서 사용하려면 Cargo 기능을 사용하여 활성화해야 합니다.
#### 디버그 빌드 만들기
디버그 빌드를 만들려면 `tauri build --debug` 명령을 실행합니다.
<CommandTabs
npm="npm run tauri build -- --debug"
yarn="yarn tauri build --debug"
pnpm="pnpm tauri build --debug"
deno="deno task tauri build --debug"
bun="bun tauri build --debug"
cargo="cargo tauri build --debug"
/>
일반적인 빌드나 개발 프로세스와 마찬가지로, 이 명령을 처음 실행할 때는 빌드에 다소 시간이 걸리지만, 그 이후의 실행에서는 훨씬 빨라집니다. 최종적으로 번들된 앱에서는 개발 콘솔이 활성화되어 있으며, `src-tauri/target/debug/bundle`에 배치됩니다.
또한 터미널에서 빌드된 앱을 실행하여 Rust 컴파일러의 메모(오류의 경우)나 `println` 메시지를 표시할 수도 있습니다. `src-tauri/target/(release|debug)/[앱 이름]` 파일을 참조하여 콘솔에서 직접 실행하거나, 파일 시스템 내의 실행 파일 자체를 더블 클릭합니다(원주: 이 방법에서는 오류가 발생하면 콘솔이 닫힙니다).
##### Devtools 기능 활성화
:::danger
devtools API는 macOS에서 "프라이빗"입니다. macOS에서 프라이빗 API를 사용하면 해당 애플리케이션은 App Store에 수리되지 않습니다.
> > > 《번역 주》 **프라이빗** private. 변수나 상수, 함수, 메서드 등이 그것이 정의된 범위 안에서만 호출·참조할 수 있는 것(외부에서는 호출할 수 없는 것). 닫힌 공간 안("집 안"과 같은)에서만 유효한 상태.
:::
**프로덕션 빌드**(제품판 빌드)에서 devtools를 활성화하려면, `src-tauri/Cargo.toml` 파일의 Cargo 기능 "`devtools`"를 활성화해야 합니다.
```toml
[dependencies]
tauri = { version = "...", features = ["...", "devtools"] }
```
## Core 프로세스 디버깅
Core 프로세스는 Rust로 작동하므로 GDB 또는 LLDB를 사용하여 디버깅할 수 있습니다. "LLDB VS Code 확장 기능"을 사용하여 Tauri 애플리케이션의 Core 프로세스를 디버깅하는 방법에 대해서는 [VS Code에서의 디버깅] 가이드를 참조하십시오.
> > > 《번역 주》 **GDB** The GNU Project Debugger의 약자. [GNU 디버거](https://ko.wikipedia.org/wiki/GNU_디버거) > > > **LLDB** The LLDB Debugger. 차세대 고성능 디버거.
[VS Code에서의 디버깅]: /ko/develop/debug/vscode/
[`WebviewWindow::open_devtools`]: https://docs.rs/tauri/2.0.0/tauri/webview/struct.WebviewWindow.html#method.open_devtools
[`WebviewWindow::close_devtools`]: https://docs.rs/tauri/2.0.0/tauri/webview/struct.WebviewWindow.html#method.close_devtools
<div style="text-align: right">
【※ 이 한국어판은 "Mar 29, 2025 영문판"을 기준으로 합니다】
</div>

View File

@@ -0,0 +1,135 @@
---
title: Neovim 에디터에서의 디버깅
i18nReady: true
---
Neovim 에디터에서 Rust 코드를 디버깅하는 데 사용할 수 있는 플러그인은 여러 가지가 있습니다. 이 장에서는 `nvim-dap`과 몇 가지 추가 플러그인을 설정하여 Tauri 애플리케이션을 디버깅하는 방법을 설명합니다.
> > > 《번역 주》 **dap** [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)의 약자. 개발 도구(IDE나 에디터 등)와 디버거 간에 사용되는 추상 프로토콜.
### 사전 준비
`nvim-dap`의 확장 기능에는 `codelldb` 바이너리가 필요합니다. [Github 사이트](https://github.com/vadimcn/codelldb/releases)에서 자신의 시스템에 맞는 버전을 다운로드하여 압축을 해제하십시오. 다음 항목 "`nvim-dap` 설정"에 필요합니다.
> > > 《번역 주》 **codelldb** LLDB 디버거를 VSCode에서 사용하기 위한 확장 기능.
### nvim-dap 설정
[`nvim-dap`](https://github.com/mfussenegger/nvim-dap) 및 [`nvim-dap-ui`](https://github.com/rcarriga/nvim-dap-ui) 두 플러그인을 모두 설치합니다. github 페이지에 기재된 지침을 따르거나, 즐겨 사용하는 플러그인 관리자를 사용하여 실시하십시오.
또한, `nvim-dap-ui`에는 `nvim-nio` 플러그인이 필요하다는 점에 유의하십시오.
다음으로, "Neovim 설정"에서 플러그인을 설정합니다:
```lua title="init.lua"
local dap = require("dap")
dap.adapters.codelldb = {
type = 'server',
port = "${port}",
executable = {
-- 이 경로는 자신의 시스템에 맞게 변경하십시오!
command = '/opt/codelldb/adapter/codelldb',
args = {"--port", "${port}"},
}
}
dap.configurations.rust= {
{
name = "Launch file",
type = "codelldb",
request = "launch",
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/target/debug/', 'file')
end,
cwd = '${workspaceFolder}',
stopOnEntry = false
},
}
```
이 "설정"에서는 디버거를 시작할 때마다 "디버깅할 Tauri App 바이너리를 지정"하도록 요청합니다.
옵션으로, "`nvim-dap-ui` 플러그인"을 설정하여 디버그 세션이 시작되고 중지될 때마다 "디버거 뷰를 자동으로 전환"하도록 지정할 수도 있습니다:
```lua title="init.lua"
local dapui = require("dapui")
dapui.setup()
dap.listeners.before.attach.dapui_config = function()
dapui.open()
end
dap.listeners.before.launch.dapui_config = function()
dapui.open()
end
dap.listeners.before.event_terminated.dapui_config = function()
dapui.close()
end
dap.listeners.before.event_exited.dapui_config = function()
dapui.close()
end
```
마지막으로, 에디터에서 중단점을 표시하는 기본 방법을 변경할 수 있습니다:
```lua title="init.lua"
vim.fn.sign_define('DapBreakpoint',{ text ='🟥', texthl ='', linehl ='', numhl =''})
vim.fn.sign_define('DapStopped',{ text ='▶️', texthl ='', linehl ='', numhl =''})
```
### 개발 서버 시작
앱 시작에 Tauri CLI를 사용하지 않으므로 개발 서버는 자동으로 시작되지 않습니다. Neovim에서 개발 서버의 상태를 제어하려면 [overseer 플러그인](https://github.com/stevearc/overseer.nvim/tree/master)을 사용할 수 있습니다.
백그라운드에서 실행 중인 작업을 제어하는 가장 좋은 방법은 [VS Code 스타일의 작업 설정](https://github.com/stevearc/overseer.nvim/blob/master/doc/guides.md#vs-code-tasks)을 사용하는 것입니다. 이를 수행하려면 프로젝트 디렉토리에 `.vscode/tasks.json` 파일을 만드십시오.
다음은 `trunk`를 사용한 프로젝트의 "작업 설정" 예입니다.
```json title=".vscode/tasks.json"
{
"version": "2.0.0",
"tasks": [
{
"type": "process",
"label": "dev server",
"command": "trunk",
"args": ["serve"],
"isBackground": true,
"presentation": {
"revealProblems": "onProblem"
},
"problemMatcher": {
"pattern": {
"regexp": "^error:.*",
"file": 1,
"line": 2
},
"background": {
"activeOnStart": false,
"beginsPattern": ".*Rebuilding.*",
"endsPattern": ".*server listening at:.*"
}
}
}
]
}
```
### 키에 명령 할당 예
다음은 디버그 세션을 시작하고 제어하기 위한 키 바인딩(키에 기능이나 기호, 명령 할당)의 예입니다.
```lua title="init.lua"
vim.keymap.set('n', '<F5>', function() dap.continue() end)
vim.keymap.set('n', '<F6>', function() dap.disconnect({ terminateDebuggee = true }) end)
vim.keymap.set('n', '<F10>', function() dap.step_over() end)
vim.keymap.set('n', '<F11>', function() dap.step_into() end)
vim.keymap.set('n', '<F12>', function() dap.step_out() end)
vim.keymap.set('n', '<Leader>b', function() dap.toggle_breakpoint() end)
vim.keymap.set('n', '<Leader>o', function() overseer.toggle() end)
vim.keymap.set('n', '<Leader>R', function() overseer.run_template() end)
```
<div style="text-align: right">
【※ 이 한국어판은, 「Dec 22, 2024 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,87 @@
---
title: JetBrains IDE에서의 디버깅
i18nReady: true
---
{/* TODO: Add support to light/dark mode images */}
이 장에서는 JetBrains RustRover를 사용하여 [Tauri 앱의 코어 프로세스](/ko/concept/process-model/#코어-프로세스)를 디버깅하는 방법을 설명합니다. 이 내용은 다른 JetBrains IDE인 IntelliJ와 CLion에도 거의 동일하게 적용됩니다.
## Cargo 프로젝트 설정
프로젝트에서 어떤 프론트엔드 스택을 사용하느냐에 따라 프로젝트 디렉토리가 "Cargo 프로젝트"가 될 수도 있고 아닐 수도 있습니다. 기본적으로 Tauri는 "Rust 프로젝트"를 `src-tauri`라는 하위 디렉토리에 배치합니다. Rust가 프론트엔드 개발에도 사용되는 경우에만 루트 디렉토리에 "Cargo 프로젝트"가 생성됩니다.
만약 프로젝트 디렉토리의 최상위에 `Cargo.toml` 파일이 없다면, Cargo 프로젝트를 수동으로 추가해야 합니다. Cargo 도구 창을 열고(메인 메뉴에서 **View | Tool Windows | Cargo** 선택), 도구 모음의 **+**(**Attach Cargo Project**)를 클릭하여 `src-tauri/Cargo.toml` 파일을 선택하십시오.
또는 다음 파일을 프로젝트의 루트 디렉토리에 추가하여 최상위 Cargo 워크스페이스를 수동으로 만들 수도 있습니다:
```toml title=Cargo.toml
[workspace]
members = ["src-tauri"]
```
다음으로 진행하기 전에 프로젝트가 완전히 로드되었는지 확인하십시오. "Cargo 도구 창"에 워크스페이스의 모듈과 대상이 모두 표시되면 준비가 된 것입니다.
## 실행 구성 설정
다음 두 가지 "실행/디버그" 설정을 각각 수행해야 합니다:
- 하나는 디버그 모드에서 Tauri 앱을 시작하기 위한 것
- 다른 하나는 선택한 프론트엔드 개발 서버를 실행하기 위한 것입니다.
### Tauri 앱
1. 메인 메뉴에서 "**Run | Edit Configurations**"(실행 | 설정 편집)으로 이동합니다.
2. "**Run/Debug Configurations**"(실행/디버그 설정) 대화 상자에서:
- 새로운 설정을 만들려면 도구 모음(왼쪽)의 **+**를 클릭하고 **Cargo**를 선택합니다.
![Add Run/Debug Configuration](@assets/develop/Debug/rustrover/add-cargo-config-light.png)
{/* ![Add Run/Debug Configuration](@assets/develop/Debug/rustrover/add-cargo-config-dark.png#gh-dark-mode-only) */}
설정 파일이 생성되면 RustRover의 설정을 수행하고 기본 기능 없이 앱을 빌드하도록 Cargo에 지시해야 합니다. 이렇게 하면 Tauri는 디스크에서 데이터(자산)를 읽는 대신 지정한 개발 서버를 사용하게 됩니다. 일반적으로 이 플래그는 Tauri CLI에 의해 전달되지만, 여기서는 Tauri CLI를 전혀 사용하지 않으므로 수동으로 플래그를 전달해야 합니다.
![Add `--no-default-features` flag](@assets/develop/Debug/rustrover/set-no-default-features-light.png)
{/* ![Add `--no-default-features` flag](@assets/develop/Debug/rustrover/set-no-default-features-dark.png#gh-dark-mode-only) */}
여기서 옵션으로 "실행/디버그 설정"의 이름을 더 기억하기 쉬운 것으로 변경할 수 있습니다. 이 예에서는 "Run Tauri App"이라는 이름을 붙였지만, 원하는 이름을 붙일 수 있습니다.
![Rename Configuration](@assets/develop/Debug/rustrover/rename-configuration-light.png)
{/* ![Rename Configuration](@assets/develop/Debug/rustrover/rename-configuration-dark.png#gh-dark-mode-only) */}
### 개발 서버
위의 설정에서는 Cargo를 직접 사용하여 Rust 애플리케이션을 빌드하고 디버거를 연결합니다. 이 설정에서는 Tauri CLI의 사용이 완전히 회피되므로 `beforeDevCommand`나 `beforeBuildCommand`와 같은 기능은 **실행되지 않습니다**. 개발 서버는 수동으로 실행해야 합니다.
이를 위한 "Run/Debug Configuration"(실행/디버그 설정)을 만들려면 실제로 사용 중인 개발 서버를 확인해야 합니다. `src-tauri/tauri.conf.json` 파일을 찾아 다음 줄을 찾으십시오:
```json
"beforeDevCommand": "pnpm dev"
```
패키지 관리자가 `npm`, `pnpm` 또는 `yarn`인 경우, **npm**의 "Run/Debug Configuration" 설정 창을 사용할 수 있습니다. 다음은 예입니다:
![NPM Configuration](@assets/develop/Debug/rustrover/npm-configuration-light.png)
{/* ![NPM Configuration](@assets/develop/Debug/rustrover/npm-configuration-dark.png#gh-dark-mode-only) */}
**Command**(명령), **Scripts**(스크립트) 및 **Package Manager**(패키지 관리자) 각 필드에 올바른 값이 입력되었는지 확인하십시오.
개발 서버가 Rust 기반 WebAssembly 프론트엔드 프레임워크용 `trunk`인 경우, 범용 **Shell Script**의 "Run/Debug Configuration"(셸 스크립트 실행/디버그 설정) 창을 사용할 수 있습니다.
![Trunk Serve Configuration](@assets/develop/Debug/rustrover/trunk-configuration-light.png)
{/* ![Trunk Serve Configuration](@assets/develop/Debug/rustrover/trunk-configuration-dark.png#gh-dark-mode-only) */}
## 디버그 세션 시작
디버그 세션을 시작하려면 먼저 개발 서버를 시작하고 "Run Configurations Switcher"(실행 설정 스위처) 옆에 있는 **디버그** 버튼을 클릭하여 Tauri 앱의 디버깅을 시작해야 합니다. RustRover는 프로젝트 내의 Rust 파일에 설정된 중단점을 자동으로 인식하고 첫 번째 중단점에 도달하면 중지합니다.
![Debug Session](@assets/develop/Debug/rustrover/debug-session-light.png)
{/* ![Debug Session](@assets/develop/Debug/rustrover/debug-session-dark.png#gh-dark-mode-only) */}
이 중단점에서 변수 값을 조사하고 코드를 더 자세히 살펴보고 실행 시에 무슨 일이 일어나고 있는지 자세히 확인할 수 있습니다.
[core process of your tauri app]: /ko/concept/process-model#코어-프로세스
<div style="text-align: right">
【※ 이 한국어판은, 「Jul 23, 2024 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,201 @@
---
title: 모델 애플리케이션의 기본 설정
sidebar:
order: 30
i18nReady: true
---
{/* TODO: REVISE COPY TO V2 */}
import { Image } from 'astro:assets';
import HelloTauriWebdriver from '@assets/develop/Tests/hello-tauri-webdriver.png';
import TranslationNote from '@components/i18n/TranslationNote.astro';
이 장의 "모델 애플리케이션" 사례에서는 기존 프로젝트에 WebDriver 테스트를 추가하는 데에만 초점을 맞춥니다.
이어지는 두 장에서 테스트할 프로젝트를 준비하기 위해, 해당 테스트에서 사용할 최소한의 Tauri 애플리케이션을 구성합니다.
여기서는 Tauri CLI나 프론트엔드 종속성, 빌드 절차는 사용하지 않으며, 나중에 애플리케이션을 번들링하지도 않습니다.
여기서의 작업은 기존 애플리케이션에 WebDriver 테스트를 추가하는 방법을 보여주고, 최소한의 구성 설정을 소개하기 위한 것입니다.
이 "모델 애플리케이션" 제작 가이드에서 소개된 내용에 기반한 완성된 프로젝트 사례만 보고 싶다면, https://github.com/chippers/hello_tauri 를 참조하십시오.
## Cargo 프로젝트 초기화
이 "모델 애플리케이션"을 저장하기 위한 새로운 바이너리 Cargo 프로젝트를 만듭니다.
이는 커맨드 라인에서 `cargo new hello-tauri-webdriver --bin`을 사용하면 간단하게 수행할 수 있으며, 이를 통해 최소한의 바이너리 Cargo 프로젝트가 준비됩니다.
이 디렉토리는 앞으로 이 제작 가이드의 작업 디렉토리로 기능하므로, 실행하는 명령이 이 새로운 `hello-tauri-webdriver/` 디렉토리 내에 있는지 확인하십시오.
## 최소 구성의 프론트엔드 만들기
"모델 애플리케이션"의 프론트엔드가 될 최소한의 HTML 파일을 만듭니다.
나중에 WebDriver 테스트 중에 이 프론트엔드의 몇 가지 항목을 사용하게 됩니다.
먼저, "모델 애플리케이션"의 Tauri 부분을 빌드할 때 필요한 Tauri `distDir`을 만듭시다.
명령 `mkdir dist`로 `dist/`라는 새 디렉토리를 만들고, 거기에 다음 `index.html` 파일을 배치합니다.
`dist/index.html`:
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello Tauri!</title>
<style>
body {
/* 보기 좋은 색상 구성표(colorscheme) 추가 */
background-color: #222831;
color: #ececec;
/* 본체를 창 크기에 맞춤 */
margin: 0;
height: 100vh;
width: 100vw;
/* body 태그의 자식 요소를 수직 및 수평으로 가운데 정렬 */
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<h1>Hello, Tauri!</h1>
</body>
</html>
```
## Tauri를 Cargo 프로젝트에 추가
다음으로, 위의 Cargo 프로젝트를 Tauri 프로젝트로 변환하는 데 필요한 항목을 추가합니다. 먼저, Cargo 매니페스트 파일(`Cargo.toml`)에 종속성을 추가하여 Cargo가 빌드 시에 종속성을 로드하도록 합니다.
<TranslationNote lang="ko">
**Cargo.toml** 아래의 Cargo.toml 파일은 일부 내용이 오래되었을 수 있습니다. 예를 들어 2025.02.20 현재 Rust 에디션은 "2024", 최신 버전은 "1.85"입니다. 버전 "1.56"은 2021.10.21 릴리스, tauri 1.0 릴리스가 2022.06.19이므로, 그 무렵에 작성된 사례로 보입니다. 적절히 읽어주세요.
</TranslationNote>
`Cargo.toml`:
```toml
[package]
name = "hello-tauri-webdriver"
version = "0.1.0"
edition = "2021"
rust-version = "1.56"
# 빌드 시 Tauri용으로 몇 가지 설정이 필요
[build-dependencies]
tauri-build = "1"
# 실제 Tauri 종속성과 페이지를 표시(serve)하기 위한 `custom-protocol`
[dependencies]
tauri = { version = "1", features = ["custom-protocol"] }
# --release로 작고(opt-level = "s") 빠르며(lto = true) 바이너리를 빌드합니다
# 이 설정은 완전히 선택 사항이지만, 일반적인 릴리스 설정에 최대한 가까운 상태에서 애플리케이션을 테스트할 수 있음을 보여줍니다
# 참고: 이로 인해 컴파일 속도가 저하됩니다
[profile.release]
incremental = false
codegen-units = 1
panic = "abort"
opt-level = "s"
lto = true
```
아마 눈치채셨겠지만, `[build-dependency]`(빌드 종속성)가 추가되었습니다. 이 `[build-dependency]`를 이용하려면, 이를 빌드 스크립트에서 사용해야 합니다.
그래서 `build.rs`에서 만듭니다.
`build.rs`:
```rust
fn main() {
// 재컴파일 시 `dist/` 디렉토리만 감시하여 다른 프로젝트의 하위 디렉토리 파일을 변경했을 때 불필요한 변경이 가해지는 것을 방지합니다
println!("cargo:rerun-if-changed=dist");
// Tauri build-time helpers를 실행합니다
tauri_build::build()
}
```
이제 Cargo 프로젝트는 Tauri의 종속성과 그 설정을 로드하여 빌드할 수 있게 되었습니다. 실제 프로젝트 코드에 Tauri를 설정하여 이 최소한의 Tauri 모델 애플리케이션을 완성합시다. 이 Tauri 기능을 추가하기 위해 `src/main.rs` 파일을 편집합니다.
`src/main.rs`:
```rust
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("unable to run Tauri application");
}
```
어때요? 아주 간단하죠?
## Tauri 설정
이 모델 애플리케이션을 성공적으로 빌드하려면 두 가지가 필요합니다. 첫 번째는 "아이콘 파일"입니다. 이 작업에는 어떤 PNG 데이터든 상관없습니다. 그것을 `icon.png`에 복사합니다.
일반적으로 이 데이터는 프로젝트 생성에 Tauri CLI를 사용하면 그 준비 처리의 일부로 제공됩니다.
기본 Tauri 아이콘을 얻으려면, 명령 `curl -L "https://github.com/chippers/hello_tauri/raw/main/icon.png" --output icon.png`를 사용하여 "Hello Tauri 샘플 리포지토리"에서 사용되는 아이콘을 다운로드합니다.
두 번째는 Tauri용 중요 설정 값을 설정하기 위한 "`tauri.conf.json`" 파일입니다.
이 파일도 일반적으로 스캐폴딩 명령인 `tauri init`으로 생성되지만, 여기서도 독자적인 최소한의 구성을 만듭니다.
<TranslationNote lang="ko">
**스캐폴딩 명령** scaffolding command: "scaffold"는 "공사 현장의 비계", "비계를 설치하다"라는 의미이지만, 본고에서는 주로 "준비"라는 번역어를 사용합니다. "스캐폴딩 명령"이란 애플리케이션 제작 시작 시 필요한 파일들을 자동으로 생성/준비해주는(작업용 비계를 설치해주는) 명령을 말합니다.
</TranslationNote>
`tauri.conf.json`:
```json
{
"build": {
"distDir": "dist"
},
"tauri": {
"bundle": {
"identifier": "studio.tauri.hello_tauri_webdriver",
"icon": ["icon.png"]
},
"allowlist": {
"all": false
},
"windows": [
{
"width": 800,
"height": 600,
"resizable": true,
"fullscreen": false
}
]
}
}
```
몇 가지 항목의 내용을 살펴보겠습니다.
방금 만든 `dist/` 디렉토리가 `distDir` 속성에 지정된 것을 볼 수 있습니다.
빌드된 애플리케이션이 고유한 ID를 갖도록 번들 식별자(ID)를 설정하고, 아이콘에는 `icon.png`만 지정했습니다. Tauri의 API나 기능은 사용하지 않으므로, `allowlist`에서 `"all": false`를 설정하여 비활성화했습니다.
창 값에는 적절한 기본값을 사용하여 생성되는 단일 창을 설정할 뿐입니다.
이제 실행 시 간단한 인사를 표시하는 기본적인 "Hello World" 애플리케이션이 완성되었습니다.
## 모델 애플리케이션 실행
올바르게 설정되었는지 확인하기 위해 이 애플리케이션을 빌드해 보겠습니다. WebDriver 테스트도 릴리스 버전용 설정 프로필로 실행하므로, 이 애플리케이션을 `--release` 버전으로 실행합니다.
`cargo run --release`를 실행하면 컴파일 후 다음 애플리케이션이 팝업으로 표시될 것입니다.
<div style={{ textAlign: 'center' }}>
<Image src={HelloTauriWebdriver} alt="Hello Tauri Webdriver" />
</div>
_참고: 애플리케이션을 수정하여 Devtools를 사용하고 싶다면, `--release` 지정 없이 실행하면 오른쪽 클릭 메뉴에서 "Inspect Element/요소 검사"가 표시되어 사용할 수 있습니다._
이제 이 모델 애플리케이션을 이용하여 "WebDriver 프레임워크"를 사용한 테스트를 시작할 준비가 되었습니다.
다음 장부터 [Selenium 이용하기](/ko/develop/tests/webdriver/example/selenium/)와 [WebdriverIO 이용하기](/ko/develop/tests/webdriver/example/webdriverio/) 모두에 대해 이 순서대로 설명합니다.
[완성된 모델 애플리케이션]: https://github.com/chippers/hello_tauri
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,212 @@
---
title: Selenium 이용하기
sidebar:
order: 31
i18nReady: true
---
{/* TODO: REVISE COPY TO V2 */}
import CommandTabs from '@components/CommandTabs.astro';
import TranslationNote from '@components/i18n/TranslationNote.astro';
:::note[모델 애플리케이션]
이 "[Selenium](셀레니움)" 설정 가이드에서는 절차를 따라 읽기 위해 이전 장의 "[모델 애플리케이션의 기본 설정]"을 읽었다고 가정합니다. 그 외에도 일반적인 정보로도 유용할 것입니다.
:::
이 장의 WebDriver 테스트 사례에서는 [Selenium]과 인기 있는 Node.js 테스트 스위트를 사용하므로,
`npm` 또는 `yarn`과 함께 Node.js를 설치한 것을 전제로 합니다([완성된 모델 애플리케이션]에서는 `yarn`이 사용됩니다).
## 테스트용 디렉토리 생성
프로젝트 내에 테스트를 작성할 장소를 만듭시다.
이 프로젝트 사례에서는 "중첩된" 디렉토리를 사용하지만, 이는 나중에 다른 프레임워크에 대해서도 자세히 알아보기 위함이며, 일반적으로는 "하나의 프레임워크"만 필요합니다.
`mkdir -p webdriver/selenium`으로 사용할 디렉토리를 만듭니다. 이하 이 설정 가이드에서는 `webdriver/selenium` 디렉토리 내에 있다고 가정합니다.
## Selenium 프로젝트 초기화
기존 `package.json`을 사용하여 이 테스트 스위트를 부트스트랩(시작)합니다. 사용하는 구체적인 종속성은 이미 선정되었으며, 간단하고 실용적인 솔루션을 소개하기 위함입니다.
이 항목의 마지막 "**> 여기를 클릭...**" 부분에 빈 상태에서 설정하는 절차에 대한 설정 가이드가 접혀 있습니다.
`package.json`:
```json
{
"name": "selenium",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "mocha"
},
"dependencies": {
"chai": "^4.3.4",
"mocha": "^9.0.3",
"selenium-webdriver": "^4.0.0-beta.4"
}
}
```
테스트 프레임워크로 [Mocha](모카)를 실행하는 스크립트가 있으며, 이는 `test` 명령으로 사용할 수 있습니다.
또한 테스트 실행에 사용되는 다양한 종속성도 있습니다.
즉, 테스트 프레임워크로서의 [Mocha], 어설션 라이브러리로서의 [Chai](차이), 그리고 [`selenium-webdriver`]로, 이는 Node.js의 [Selenium] 패키지입니다.
<TranslationNote lang="ko">
**어설션 라이브러리** assertion library: 테스트 시 검증 결과가 예상된 내용인지 여부를 판정하기 위한 도구.
</TranslationNote>
<details>
<summary>여기를 클릭(프로젝트를 빈 상태에서 설정하는 경우)</summary>
종속성을 빈 상태에서 설치하는 경우 다음 명령을 실행합니다.
<CommandTabs
npm="npm install mocha chai selenium-webdriver"
yarn="yarn add mocha chai selenium-webdriver"
/>
또한 `package.json`의 `"scripts"` 키에 `"test": "mocha"` 항목을 추가하는 것이 좋습니다. 이렇게 하면 Mocha 실행을 다음 명령에서 쉽게 호출할 수 있습니다.
<CommandTabs npm="npm test" yarn="yarn test" />
</details>
## 테스트
[WebdriverIO의 테스트 스위트](/ko/develop/debug/tests/webdriver/example/webdriverio/#설정)와 달리 Selenium에는 테스트 스위트가 포함되어 있지 않으며, 테스트 스위트 구축은 개발자에게 맡겨져 있습니다.
여기서는 [Mocha]를 선택했습니다. Mocha는 WebDrivers와 관련이 없는 비교적 중립적인 라이브러리이므로 스크립트의 모든 것을 올바른 순서로 설정하려면 약간의 작업이 필요합니다.
[Mocha]는 기본적으로 `test/test.js`에 테스트 파일을 준비해야 합니다. 그럼 바로 만들어 봅시다.
`test/test.js`:
```javascript
const os = require('os');
const path = require('path');
const { expect } = require('chai');
const { spawn, spawnSync } = require('child_process');
const { Builder, By, Capabilities } = require('selenium-webdriver');
// 필요한 애플리케이션 바이너리 경로 생성
const application = path.resolve(
__dirname,
'..',
'..',
'..',
'target',
'release',
'hello-tauri-webdriver'
);
// 생성된 WebDriver 인스턴스 추적
let driver;
// 시작할 tauri-driver 프로세스 추적
let tauriDriver;
before(async function () {
// 필요에 따라 프로그램을 빌드할 수 있도록 타임아웃을 2분으로 설정
this.timeout(120000);
// 프로그램이 빌드되었는지 확인
spawnSync('cargo', ['build', '--release']);
// tauri-driver 시작
tauriDriver = spawn(
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
[],
{ stdio: [null, process.stdout, process.stderr] }
);
const capabilities = new Capabilities();
capabilities.set('tauri:options', { application });
capabilities.setBrowserName('wry');
// Webdriver 클라이언트 시작
driver = await new Builder()
.withCapabilities(capabilities)
.usingServer('http://127.0.0.1:4444/')
.build();
});
after(async function () {
// Webdriver 세션 중지
await driver.quit();
// tauri-driver 프로세스 강제 종료
tauriDriver.kill();
});
describe('Hello Tauri', () => {
it('should be cordial', async () => {
const text = await driver.findElement(By.css('body > h1')).getText();
expect(text).to.match(/^[hH]ello/);
});
it('should be excited', async () => {
const text = await driver.findElement(By.css('body > h1')).getText();
expect(text).to.match(/!$/);
});
it('should be easy on the eyes', async () => {
// Selenium은 색상 CSS 값을 rgb(r, g, b)로 반환합니다
const text = await driver
.findElement(By.css('body'))
.getCssValue('background-color');
const rgb = text.match(/^rgb\((?<r>\d+), (?<g>\d+), (?<b>\d+)\)$/).groups;
expect(rgb).to.have.all.keys('r', 'g', 'b');
const luma = 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b;
expect(luma).to.be.lessThan(100);
});
});
```
"JS 테스트 프레임워크"에 익숙하다면 `describe`, `it`, `expect` 등은 익숙할 것입니다. 또한 mocha의 설정(셋업)과 해제(티어다운)를 수행하기 위한 다소 복잡한 `before()`와 `after()` 콜백도 준비되어 있습니다.
테스트 본문이 아닌 줄에는 셋업 코드와 티어다운 코드를 설명하는 주석이 기재되어 있습니다.
[WebdriverIO의 테스트 사양](/ko/develop/debug/tests/webdriver/example/webdriverio/#테스트-사양)의 "Spec 파일"에 익숙하다면, WebDriver 관련 항목을 몇 가지 더 설정해야 하므로 테스트 이외의 코드가 더 많아진 것을 알 수 있을 것입니다.
## 테스트 스위트 실행
종속성과 테스트 스크립트 설정이 모두 완료되었으므로 실행해 봅시다.
<CommandTabs npm="npm test" yarn="yarn test" />
다음과 같은 출력이 표시될 것입니다:
```text
➜ selenium git:(main) ✗ yarn test
yarn run v1.22.11
$ Mocha
Hello Tauri
✔ should be cordial (120ms)
✔ should be excited
✔ should be easy on the eyes
3 passing (588ms)
Done in 0.93s.
```
위의 `test/test.js`의 `describe`에서 생성한 `Hello Tauri` 테스트 스위트에서는 `it`에 기재된 세 가지 테스트 항목이 모두 통과한 것을 볼 수 있습니다.
[Selenium]과 함께 테스트 스위트에 "훅업"하는(별도 처리 삽입) 처리를 통해 Tauri 애플리케이션을 전혀 수정하지 않고 "e2e 테스트"를 실행할 수 있었습니다!
<TranslationNote lang="ko">
**e2e 테스트** end-to-end test의 약자. 시스템 전체를 "끝에서 끝까지"(즉, 처음부터 끝까지) 동작 검증하는 테스트 기법. 자동 시스템 전체 검증. 시스템마다 테스트 코드를 준비하면 공수·비용이 증가하므로 테스트 자동화 도구가 사용됩니다.
</TranslationNote>
[모델 애플리케이션의 기본 설정]: /ko/develop/debug/tests/webdriver/example/
[selenium]: https://selenium.dev/ko/
[완성된 모델 프로젝트]: https://github.com/chippers/hello_tauri
[mocha]: https://mochajs.org/
[chai]: https://www.chaijs.com/
[`selenium-webdriver`]: https://www.npmjs.com/package/selenium-webdriver

View File

@@ -0,0 +1,224 @@
---
title: WebdriverIO 이용하기
sidebar:
order: 31
i18nReady: true
---
{/* TODO: REVISE COPY TO V2 */}
import CommandTabs from '@components/CommandTabs.astro';
import TranslationNote from '@components/i18n/TranslationNote.astro';
:::note[모델 애플리케이션]
이 "[WebdriverIO]"(웹드라이버 IO) 설정 가이드에서는, 절차를 따라 읽기 위해, 이전 장의 "[모델 애플리케이션의 기본 설정]"을 읽었다고 가정합니다. 그 외에도 일반적인 정보로도 유용할 것입니다.
:::
이 장의 WebDriver 테스트 사례에서는 [WebdriverIO]와 그 테스트 스위트를 사용하므로,
`npm` 또는 `yarn`과 함께 Node.js가 이미 설치되어 있는 것을 전제로 합니다([완성된 모델 애플리케이션]에서는 `yarn`이 사용됩니다).
## 테스트용 디렉토리 생성
프로젝트 내에 테스트를 작성할 장소를 만듭시다.
이 프로젝트 사례에서는 "중첩된" 디렉토리를 사용하지만, 이는 나중에 다른 프레임워크에 대해서도 자세히 알아보기 위함이며, 일반적으로는 "하나의 프레임워크"만 필요합니다.
`mkdir -p webdriver/webdriverio`로 사용할 디렉토리를 만듭니다. 이하 이 설정 가이드에서는 `webdriver/webdriverio` 디렉토리 내에 있다고 가정합니다.
## WebdriverIO 프로젝트 초기화
기존 `package.json`을 사용하여 이 테스트 스위트를 부트스트랩(시작)합니다. 이미 구체적인 [WebdriverIO] 설정 옵션을 선정했으며, 간단하고 실용적인 솔루션을 소개하기 위함입니다.
이 항목의 마지막 "**> 여기를 클릭...**" 부분에 빈 상태에서 설정하는 절차에 대한 설정 가이드가 접혀 있습니다.
`package.json`:
```json
{
"name": "webdriverio",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "wdio run wdio.conf.js"
},
"dependencies": {
"@wdio/cli": "^7.9.1"
},
"devDependencies": {
"@wdio/local-runner": "^7.9.1",
"@wdio/mocha-framework": "^7.9.1",
"@wdio/spec-reporter": "^7.9.0"
}
}
```
테스트 스위트로 [WebdriverIO] 설정을 실행하는 스크립트가 있으며, 이는 `test` 명령으로 사용할 수 있습니다.
또한, 처음에 설정할 때 `@wdio/cli` 명령으로 추가되는 종속성도 있습니다.
간단히 말해, 이러한 종속성은 로컬 WebDriver 러너, 테스트 프레임워크로서의 [Mocha], 그리고 단순한 Spec Reporter를 사용한 가장 간단한 설정을 위한 것입니다.
<details>
<summary>여기를 클릭(프로젝트를 빈 상태에서 설정하는 경우)</summary>
CLI는 대화형이며, 직접 조작할 도구를 선택할 수 있습니다.
단, 설정 가이드의 설명과 다를 수 있으며, 다른 부분은 직접 설정해야 한다는 점에 유의하십시오.
이 npm 프로젝트에 [WebdriverIO] CLI를 추가합시다.
<CommandTabs npm="npm install @wdio/cli" yarn="yarn add @wdio/cli" />
다음으로, 대화형 config 명령을 실행하여 [WebdriverIO] 테스트 스위트를 설정하려면 다음 명령을 실행합니다:
<CommandTabs npm="npx wdio config" yarn="yarn wdio config" />
</details>
## 설정
`package.json` 내의 `test` 스크립트에 `wdio.conf.js` 파일이 기재되어 있는 것을 눈치채셨을 것입니다.
이는 [WebdriverIO] 설정 파일로, 테스트 스위트의 대부분의 측면을 제어하는 것입니다.
`wdio.conf.js`:
```javascript
const os = require('os');
const path = require('path');
const { spawn, spawnSync } = require('child_process');
// `tauri-driver` 자식 프로세스 추적
let tauriDriver;
exports.config = {
specs: ['./develop/tests/specs/**/*.js'],
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
'tauri:options': {
application: '../../target/release/hello-tauri-webdriver',
},
},
],
reporters: ['spec'],
framework: 'mocha',
mochaOpts: {
ui: 'bdd',
timeout: 60000,
},
// Webdriver 세션에 필요한 Rust 프로젝트가 빌드되었는지 확인
onPrepare: () => spawnSync('cargo', ['build', '--release']),
// Webdriver 요청을 프록시할 수 있도록 세션 시작 전에 `tauri-driver`가 실행 중인지 확인
beforeSession: () =>
(tauriDriver = spawn(
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
[],
{ stdio: [null, process.stdout, process.stderr] }
)),
// 세션 시작 시 생성된 "tauri-driver" 프로세스 정리
afterSession: () => tauriDriver.kill(),
};
```
`exports.config` 객체의 속성에 관심이 있다면 [webdriver 문서]를 참조하십시오.
webdriverIO 고유가 아닌 항목에 대해서는 `onPrepare`, `beforeSession`, `afterSession` 내에서 왜 명령을 실행하는지에 대한 주석이 있습니다.
"스펙(테스트 사양)"도 `"./develop/tests/specs/**/*.js"`로 설정되므로, 다음에 "테스트 사양"을 만듭시다.
## 테스트 사양
"테스트 사양"에는 실제 애플리케이션을 테스트하는 코드가 포함되어 있습니다.
테스트 러너는 이 "테스트 사양"을 읽고 필요에 따라 자동으로 실행합니다. 그럼 지정된 디렉토리에 "테스트 사양"을 만듭시다.
`test/specs/example.e2e.js`:
```javascript
// "16진수 색상" `#abcdef`에서 "휘도(luma 루마)"를 계산
function luma(hex) {
if (hex.startsWith('#')) {
hex = hex.substring(1);
}
const rgb = parseInt(hex, 16);
const r = (rgb >> 16) & 0xff;
const g = (rgb >> 8) & 0xff;
const b = (rgb >> 0) & 0xff;
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
describe('Hello Tauri', () => {
it('should be cordial', async () => {
const header = await $('body > h1');
const text = await header.getText();
expect(text).toMatch(/^[hH]ello/);
});
it('should be excited', async () => {
const header = await $('body > h1');
const text = await header.getText();
expect(text).toMatch(/!$/);
});
it('should be easy on the eyes', async () => {
const body = await $('body');
const backgroundColor = await body.getCSSProperty('background-color');
expect(luma(backgroundColor.parsed.hex)).toBeLessThan(100);
});
});
```
첫 번째 [luma] 함수는 테스트 중 하나에 대한 헬퍼 함수일 뿐이며, 실제 애플리케이션 테스트와는 관련이 없습니다.
다른 테스트 프레임워크에 익숙하다면 `describe`, `it`, `expect` 등 사용된 유사한 함수가 "개방"(외부 액세스 가능)되어 있음을 알 수 있습니다.
기타 API, 예를 들어 `$`와 같은 항목이나 공개된 메서드 등에 대해서는 [WebdriverIO API 문서]에서 설명합니다.
## 테스트 스위트 실행
설정과 테스트 사양이 모두 준비되었으므로 실행해 봅시다!
<CommandTabs npm="npm test" yarn="yarn test" />
다음과 같은 출력이 표시될 것입니다:
```text
➜ webdriverio git:(main) ✗ yarn test
yarn run v1.22.11
$ wdio run wdio.conf.js
Execution of 1 workers started at 2021-08-17T08:06:10.279Z
[0-0] RUNNING in undefined - /develop/tests/specs/example.e2e.js
[0-0] PASSED in undefined - /develop/tests/specs/example.e2e.js
"spec" Reporter:
------------------------------------------------------------------
[wry 0.12.1 linux #0-0] Running: wry (v0.12.1) on linux
[wry 0.12.1 linux #0-0] Session ID: 81e0107b-4d38-4eed-9b10-ee80ca47bb83
[wry 0.12.1 linux #0-0]
[wry 0.12.1 linux #0-0] » /develop/tests/specs/example.e2e.js
[wry 0.12.1 linux #0-0] Hello Tauri
[wry 0.12.1 linux #0-0] ✓ should be cordial
[wry 0.12.1 linux #0-0] ✓ should be excited
[wry 0.12.1 linux #0-0] ✓ should be easy on the eyes
[wry 0.12.1 linux #0-0]
[wry 0.12.1 linux #0-0] 3 passing (244ms)
Spec Files: 1 passed, 1 total (100% completed) in 00:00:01
Done in 1.98s.
```
Spec Reporter 부분에는 `test/specs/example.e2e.js` 파일의 세 가지 테스트 모두와 최종 보고서 `Spec Files: 1 passed, 1 total (100% Complete) in 00:00:01`가 표시됩니다.
[WebdriverIO] 테스트 스위트를 사용하면 몇 줄의 설정과 하나의 명령 실행만으로 Tauri 애플리케이션의 e2e 테스트를 쉽게 실행할 수 있었습니다! 더욱 놀라운 것은 애플리케이션을 전혀 수정할 필요가 없었다는 것입니다.
[모델 애플리케이션의 기본 설정]: /ko/develop/debug/tests/webdriver/example/
[webdriverio]: https://webdriver.io/ko/
[완성된 모델 애플리케이션]: https://github.com/chippers/hello_tauri
[mocha]: https://mochajs.org/
[webdriver 문서]: https://webdriver.io/docs/configurationfile
[webdriverio api 문서]: https://webdriver.io/docs/api
[luma]: https://ko.wikipedia.org/wiki/휘도
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,102 @@
---
title: 지속적 통합(CI)
description: WebDriver 테스트
sidebar:
order: 21
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
Linux와 몇 가지 프로그램을 이용하여 가상 디스플레이를 만들면, CI (지속적 통합 테스트 도구) 상에서 [`tauri-driver`]를 사용하여 [WebDriver] 테스트를 실행할 수 있습니다.
아래에서는 [WebdriverIO]에 의한 [미리 만든 테스트 사례]와 GitHub Actions를 사용하고 있습니다.
여기에는 다음 두 가지 전제가 있습니다:
1. Tauri 애플리케이션은 리포지토리의 루트에 있으며, `cargo build --release`를 실행하면 바이너리가 빌드됩니다.
2. "[WebDriverIO] 테스트 러너"는 `webdriver/webdriverio` 디렉토리에 있으며, 해당 디렉토리에서 `yarn test`가 사용되면 실행됩니다.
아래는 `.github/workflows/webdriver.yml`에 있는 주석이 달린 GitHub Actions 워크플로 파일입니다.
```yaml
# 리포지토리가 푸시될 때 이 액션을 실행
on: [push]
# 워크플로의 이름
name: WebDriver
jobs:
# test라는 이름의 단일 작업
test:
# test 작업의 표시 이름
name: WebDriverIO Test Runner
# 최신 Linux 환경 지정(we want to run on)
runs-on: ubuntu-22.04
# 작업이 **순서대로** 실행할 절차
steps:
# "워크플로 러너"의 코드를 체크아웃(확인)
- uses: actions/checkout@v4
# Tauri가 Linux에서 컴파일하는 데 필요한 시스템 종속성 설치
# `tauri-driver`를 실행하기 위한 추가 종속성 (`webkit2gtk-driver` 및 `xvfb`)에 주의
- name: Tauri dependencies
run: |
sudo apt update && sudo apt install -y \
libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
webkit2gtk-driver \
xvfb
- name: Setup rust-toolchain stable
id: rust-toolchain
uses: dtolnay/rust-toolchain@stable
# 손상된 애플리케이션 테스트를 피하기 위해 WebDriver 테스트 전에 Rust 테스트 실행
- name: Cargo test
run: cargo test
# WebdriverIO 테스트 중에 사용되는 애플리케이션의 릴리스 빌드 실행
- name: Cargo build
run: cargo build --release
# 최신 안정 버전 node 설치(작성 시점)
- name: Node 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
# Yarn을 사용하여 Node.js 종속성 설치
- name: Yarn install
run: yarn install --frozen-lockfile
working-directory: webdriver/webdriverio
# `tauri-driver`의 최신 버전 설치
# 참고: tauri-driver의 버전은 다른 Tauri 버전 번호와 관련이 없습니다
- name: Install tauri-driver
run: cargo install tauri-driver --locked
# WebdriverIO 테스트 스위트 실행
# `xvfb-run`(방금 설치한 종속성)을 실행하여 가상 디스플레이 서버를 만들고 코드를 변경하지 않고 애플리케이션을 헤드리스(무인)로 실행할 수 있도록 합니다
- name: WebdriverIO
run: xvfb-run yarn test
working-directory: webdriver/webdriverio
```
[미리 만든 테스트 사례]: /ko/develop/debug/tests/webdriver/example/webdriverio/
[webdriver]: https://www.w3.org/TR/webdriver/
[`tauri-driver`]: https://crates.io/crates/tauri-driver
[webdriverio]: https://webdriver.io/
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,100 @@
---
title: WebDriver
description: WebDriver 테스트
sidebar:
order: 10
label: 개요
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
[WebDriver]는 주로 자동 테스트를 목적으로 한, 웹 문서와의 상호 작용을 위한 표준화된 인터페이스입니다.
Tauri는 크로스 플랫폼 래퍼 [`tauri-driver`] 하에서 네이티브 플랫폼의 [WebDriver] 서버를 이용하여 [WebDriver] 인터페이스를 지원합니다.
데스크톱에서는 Windows와 Linux만 지원됩니다. macOS에서는 WKWebView 드라이버 도구를 사용할 수 없기 때문입니다.
iOS와 Android에서는 소프트웨어 자동 테스트 에코시스템 [Appium 2]를 통해 작동하지만, 현재로서는 그 프로세스가 간소화되어 있지 않습니다.
## 시스템 의존성
다음 명령을 실행하여 최신 [`tauri-driver`]를 설치하거나 기존 설치를 업데이트합니다:
```shell
cargo install tauri-driver --locked
```
Tauri는 현재 각 플랫폼의 네이티브 [WebDriver] 서버를 이용하고 있으므로, 지원되는 플랫폼에서 [`tauri-driver`]를 실행하려면 다음과 같은 몇 가지 전제 조건이 있습니다.
### Linux의 경우
Linux 플랫폼에서는 `WebKitWebDriver`를 사용합니다. 이 바이너리가 이미 시스템 내에 있는지 확인하십시오(명령 `which WebKitWebDriver`로 확인할 수 있습니다). 일부 배포판에서는 이 바이너리가 일반 WebKit 패키지에 번들로 제공되기 때문입니다.
다른 플랫폼에서는 예를 들어 Debian 기반 배포판의 `webkit2gtk-driver`와 같이 별도의 패키지가 제공될 수 있습니다.
### Windows의 경우
애플리케이션을 빌드하고 테스트하는 Windows Edge 버전과 일치하는 [Microsoft Edge WebDriver] 버전을 반드시 가져와야 합니다.
해당 버전은 최신 Windows 설치에서는 거의 항상 최신 안정 버전일 것입니다.
이 두 버전이 일치하지 않으면 연결 시 "WebDriver 테스트 스위트"가 중단될 수 있습니다.
<TranslationNote lang="ko">
**테스트 스위트** testing suite: 소프트웨어 검증 시 사용하는 일련의 "테스트 케이스"를 효율적으로 실행하기 위해 하나로 묶은 것.
</TranslationNote>
다운로드에는 `msedgedriver.exe`라는 바이너리가 포함되어 있습니다. [`tauri-driver`]는 `$PATH`에서 해당 바이너리를 검색하므로 경로에서 액세스할 수 있는지 확인하거나 [`tauri-driver`]에서 `--native-driver` 옵션을 사용하십시오.
Windows [CI](#지속적-통합ci) 머신에서 Edge와 Edge Driver 버전이 확실히 동기화되도록 하려면 CI 설정 프로세스의 일부로 자동으로 다운로드하고 싶을 수 있습니다.
이 처리 실행 방법에 대한 지침은 나중에 추가될 것으로 보입니다.
## 모델 애플리케이션 사례
<TranslationNote lang="ko">
**모델 애플리케이션** 원문 Example Applications: 소프트웨어 검증 대상이 되는 "애플리케이션 사례"라는 의미이지만, 본고에서는 검증 시 "모델"로 삼는 사례라는 의미에서 "모델 애플리케이션"으로 번역했습니다.
</TranslationNote>
다음은 WebDriver를 사용하여 테스트되는 애플리케이션의 최소 구성 사례를 만드는 단계별 제작 가이드입니다.
이 제작 가이드의 결과와 완성된 최소한의 코드베이스를 빠르게 확인하고 싶다면 https://github.com/chippers/hello_tauri 를 참조하십시오.
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
<CardGrid>
<LinkCard
title="모델 애플리케이션의 기본 설정"
href="/ko/develop/debug/tests/webdriver/example/"
/>
<LinkCard
title="Selenium 이용하기"
href="/ko/develop/debug/tests/webdriver/example/selenium/"
/>
<LinkCard
title="WebdriverIO 이용하기"
href="/ko/develop/debug/tests/webdriver/example/webdriverio/"
/>
</CardGrid>
## 지속적 통합(CI)
위의 사례에는 GitHub Actions를 이용한 테스트를 위한 CI 스크립트도 포함되어 있지만, 이 개념을 좀 더 자세히 설명하는 다음 "WebDriver CI 가이드"(다음 장)도 흥미로울 수 있습니다.
<LinkCard
title="지속적 통합(CI)"
href="/ko/develop/debug/tests/webdriver/ci/"
/>
<TranslationNote lang="ko">
**CI/CD** 소프트웨어 개발에서의 워크플로 자동화 기법. 자세한 내용은 "[GitLab](https://about.gitlab.com/ko-kr/topics/ci-cd/)"을 참조하십시오.
</TranslationNote>
[webdriver]: https://www.w3.org/TR/webdriver/
[`tauri-driver`]: https://crates.io/crates/tauri-driver
[tauri-driver]: https://crates.io/crates/tauri-driver
[Microsoft Edge WebDriver]: https://developer.microsoft.com/ko-kr/microsoft-edge/tools/webdriver/
[Appium 2]: https://appium.io/docs/ko/latest/
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,34 @@
---
title: 테스트
description: Tauri 런타임 안팎에서의 테스트 기법
sidebar:
order: 10
label: 개요
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
Tauri는 모의 런타임(모의 실행)을 이용한 단위 테스트와 통합 테스트를 모두 지원합니다. 모의 런타임에서는 네이티브 WebView 라이브러리가 실행되지 않습니다.
자세한 내용은 다음 장 "[Mock Tauri APIs](모의 런타임)"를 참조하십시오.
Tauri는 또한 WebDriver 프로토콜을 이용한 "엔드 투 엔드"(자동 시스템 전체 검증) 테스트 지원도 제공합니다. 데스크톱과 모바일 모두에서 작동하지만, 데스크톱 WebDriver 클라이언트가 제공되지 않는 macOS에서는 작동하지 않습니다.
자세한 내용은 [WebDriver] 장을 참조하십시오.
Tauri에서는 빌드 자동화 도구 "GitHub Action"의 실행을 돕기 위해 [tauri-action]이 제공되지만, 각 플랫폼이 컴파일에 필요한 라이브러리를 설치했다면 어떤 종류의 "CI/CD 러너"에서도 Tauri를 사용할 수 있습니다.
<TranslationNote lang="ko">
**CI/CD** "Continuous Integration and Continuous
Deployment"(지속적 통합/지속적 배포)의 약자. 러너는 CI/CD와
연동하여 변경된 프로젝트를 자동으로 파이프라인 처리하는 빌드나 테스트를 실행하는 기능.
</TranslationNote>
[Mock Tauri APIs]: /ko/develop/tests/mocking/
[WebDriver]: /ko/develop/debug/tests/webdriver/
[tauri-action]: https://github.com/tauri-apps/tauri-action
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,190 @@
---
title: Mock Tauri APIs(모의 런타임)
sidebar:
order: 10
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
프론트엔드 테스트를 작성할 때, 창을 시뮬레이션하거나 IPC 호출을 가로채기 위한 "임시" Tauri 환경(소위 **모킹**)을 준비하는 것이 일반적입니다.
[`@tauri-apps/api/mocks`] 모듈은 쉽게 이 가상 환경을 구현하기 위한 몇 가지 편리한 도구를 제공합니다:
:::caution
가상 환경에서의 테스트별 변경(모의 상태 변화)을 취소하기 위해, 각 테스트 실행 후에 반드시 "모의"를 클리어하십시오. 자세한 내용은 목차 **Reference**의 "Mock" 장에 있는 [`clearMocks()`] 문서를 참조하십시오.
:::
## IPC 요청
테스트에서 가장 일반적인 검증 사항은 "IPC 요청"을 가로채는 것입니다. 이는 다양한 상황에서 유용합니다. 예를 들어:
- 올바른 백엔드 호출이 이루어지고 있는지 확인
- 백엔드 함수로부터 다른 결과를 시뮬레이션
Tauri에서는 "IPC 요청"을 가로채기 위한 mockIPC 함수를 사용할 수 있습니다. 구체적인 API 세부 정보는 [여기][`mockipc()`]를 참조하십시오.
:::note
아래 예제에서는 테스트 프레임워크로 [Vitest]를 사용하지만, [jest]와 같은 다른 프론트엔드 테스트 라이브러리를 사용할 수도 있습니다.
:::
```javascript
import { beforeAll, expect, test } from "vitest";
import { randomFillSync } from "crypto";
import { mockIPC } from "@tauri-apps/api/mocks";
import { invoke } from "@tauri-apps/api/core";
// "jsdom 테스트 환경"에는 WebCrypto 구현이 포함되어 있지 않습니다
beforeAll(() => {
Object.defineProperty(window, 'crypto', {
value: {
// @ts-ignore
getRandomValues: (buffer) => {
return randomFillSync(buffer);
},
},
});
});
test("invoke simple", async () => {
mockIPC((cmd, args) => {
// 두 숫자를 더하는 "add"라는 Rust 명령을 시뮬레이션합니다
if(cmd === "add") {
return (args.a as number) + (args.b as number);
}
});
});
```
때로는 IPC 호출에 대한 더 많은 정보를 추적하고 싶을 때가 있습니다. 예를 들어, 명령이 몇 번 호출되었는지, 애초에 명령이 호출되었는지 여부 등입니다.
이러한 테스트에는 다른 스파이 도구(감시) 및 모의 도구와 함께 [`mockIPC()`]를 사용할 수 있습니다.
```javascript
import { beforeAll, expect, test, vi } from "vitest";
import { randomFillSync } from "crypto";
import { mockIPC } from "@tauri-apps/api/mocks";
import { invoke } from "@tauri-apps/api/core";
// "jsdom 테스트 환경"에는 WebCrypto 구현이 포함되어 있지 않습니다
beforeAll(() => {
Object.defineProperty(window, 'crypto', {
value: {
// @ts-ignore
getRandomValues: (buffer) => {
return randomFillSync(buffer);
},
},
});
});
test("invoke", async () => {
mockIPC((cmd, args) => {
// 두 숫자를 더하는 "add"라는 Rust 명령을 시뮬레이션합니다
if(cmd === "add") {
return (args.a as number) + (args.b as number);
}
});
// vitest가 제공하는 스파이 도구를 사용하여 모의화된 함수를 추적할 수 있습니다.
const spy = vi.spyOn(window.__TAURI_INTERNALS__, "invoke");
expect(invoke("add", { a: 12, b: 15 })).resolves.toBe(27);
expect(spy).toHaveBeenCalled();
});
```
<TranslationNote lang="ko">
**모의화** mocked function "모의화된 함수". 테스트 환경 등에서 호출되는 모의 함수로 지정되어 가상으로 실행되는 (임시) 함수.
</TranslationNote>
"[사이드카]"(내장된 외부 프로그램)나 셸 명령에 대한 IPC 요청을 모의화하려면, `spawn()` 또는 `execute()`가 호출되었을 때의 이벤트 핸들러 ID를 가져와 이 ID를 사용하여 백엔드가 응답하는 이벤트를 발생시킵니다:
```javascript
mockIPC(async (cmd, args) => {
if (args.message.cmd === 'execute') {
const eventCallbackId = `_${args.message.onEventFn}`;
const eventEmitter = window[eventCallbackId];
// "표준 출력 Stdout" 이벤트는 몇 번이든 호출 가능합니다
eventEmitter({
event: 'Stdout',
payload: 'some data sent from the process',
});
// "프로미스" 처리를 완료하려면 마지막에 "Terminated" 이벤트를 호출합니다
eventEmitter({
event: 'Terminated',
payload: {
code: 0,
signal: 'kill',
},
});
}
});
```
<TranslationNote lang="ko">
**프로미스** Promise: Promise는 JavaScript에서 비동기 처리가 완료되었을 때 결과(resolve 또는 reject)를 반환하는 객체입니다.
</TranslationNote>
## Windows의 경우
Windows에서는 때때로 Windows 고유의 코드(예: 스플래시 스크린 창) 때문에 다른 창의 시뮬레이션이 필요할 수 있습니다.
[`mockWindows()`] 메서드를 사용하면 임시 창 레이블을 만들 수 있습니다. 첫 번째 문자열이 "현재" 창(즉, JavaScript 자체가 해당 창 내에 있다고 인식하는 창)을 식별하고, 다른 문자열은 추가 창으로 처리됩니다.
:::note
[`mockWindows()`]는 창의 존재를 가장할 뿐, 창의 속성을 위장하는 것은 아닙니다. 창의 속성을 시뮬레이션하려면 [`mockIPC()`]를 사용하여 정규 호출을 가로채야 합니다.
:::
```javascript
import { beforeAll, expect, test } from 'vitest';
import { randomFillSync } from 'crypto';
import { mockWindows } from '@tauri-apps/api/mocks';
// "jsdom 테스트 환경"에는 WebCrypto 구현이 포함되어 있지 않습니다
beforeAll(() => {
Object.defineProperty(window, 'crypto', {
value: {
// @ts-ignore
getRandomValues: (buffer) => {
return randomFillSync(buffer);
},
},
});
});
test('invoke', async () => {
mockWindows('main', 'second', 'third');
const { getCurrent, getAll } = await import('@tauri-apps/api/webviewWindow');
expect(getCurrent()).toHaveProperty('label', 'main');
expect(getAll().map((w) => w.label)).toEqual(['main', 'second', 'third']);
});
```
[`@tauri-apps/api/mocks`]: /reference/javascript/api/namespacemocks/
[`mockipc()`]: /reference/javascript/api/namespacemocks/#mockipc
[`mockwindows()`]: /reference/javascript/api/namespacemocks/#mockwindows
[`clearmocks()`]: /reference/javascript/api/namespacemocks/#clearmocks
[Vitest]: https://vitest.dev
[jest]: https://jestjs.io/ko/
[사이드카]: /ko/develop/sidecar/
<div style="text-align: right">
【※ 이 한국어판은, 「Jan 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,162 @@
---
title: VS Code에서의 디버깅
i18nReady: true
---
이 장에서는 [Tauri 앱의 코어 프로세스](/ko/concept/process-model/#코어-프로세스)를 디버깅하기 위한 VS Code 설정에 대해 설명합니다.
## vscode-lldb 확장 기능을 갖춘 모든 플랫폼의 경우
### 사전 준비
[`vscode-lldb`] 확장 기능을 설치하십시오.
[`vscode-lldb`]: https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb
### launch.json 설정
`.vscode/launch.json` 파일을 만들고 다음 JSON 콘텐츠를 붙여넣습니다:
```json title=".vscode/launch.json"
{
// VS Code의 IntelliSense 입력 지원 기능을 사용하여 사용 가능한 속성에 대해 알아보십시오.
// 마우스를 기존 속성 위에 놓으면 해당 설명이 표시됩니다.
// 자세한 내용은 https://go.microsoft.com/fwlink/?linkid=830387을 참조하십시오.
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Tauri Development Debug",
"cargo": {
"args": [
"build",
"--manifest-path=./src-tauri/Cargo.toml",
"--no-default-features"
]
},
// `beforeDevCommand`의 작업을 사용하는 경우, `.vscode/tasks.json`에서 설정해야 합니다.
"preLaunchTask": "ui:dev"
},
{
"type": "lldb",
"request": "launch",
"name": "Tauri Production Debug",
"cargo": {
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
},
// `beforeBuildCommand`의 작업을 사용하는 경우, `.vscode/tasks.json`에서 설정해야 합니다.
"preLaunchTask": "ui:build"
}
]
}
```
이제 `cargo`를 직접 사용하여 Rust 애플리케이션을 빌드하고 개발 모드와 프로덕션 모드 모두에서 로드할 수 있습니다.
즉, Tauri CLI를 사용하지 않으므로 CLI 고유의 기능은 **실행되지 않습니다**. `beforeDevCommand` 및 `beforeBuildCommand` 스크립트는 사전에 실행하거나 위와 같이 `preLaunchTask` 필드에서 **작업으로 설정**해야 합니다. 다음은 개발 서버를 시작하는 `beforeDevCommand` 작업과 `beforeBuildCommand` 작업 두 가지를 포함하는 `.vscode/tasks.json` 파일의 예입니다:
```json title=".vscode/tasks.json"
{
// tasks.json 형식에 대한 문서는
// https://go.microsoft.com/fwlink/?LinkId=733558을 참조하십시오.
"version": "2.0.0",
"tasks": [
{
"label": "ui:dev",
"type": "shell",
// `dev`는 백그라운드에서 실행이 계속됩니다.
// 이상적으로는 `problemMatcher`도 설정해야 합니다.
// https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson을 참조하십시오.
"isBackground": true,
// 이 부분을 자신의 `beforeDevCommand`에 맞게 변경합니다:
"command": "yarn",
"args": ["dev"]
},
{
"label": "ui:build",
"type": "shell",
// 이 부분을 자신의 `beforeBuildCommand`에 맞게 변경합니다:
"command": "yarn",
"args": ["build"]
}
]
}
```
이제 `src-tauri/src/main.rs`나 다른 Rust 파일에 중단점을 설정하고 `F5`를 눌러 디버깅을 시작할 수 있습니다.
## Windows의 Visual Studio Windows 디버거를 사용하는 경우
"Visual Studio Windows Debugger"는 Windows 전용 디버거로, 일반적으로 [`vscode-lldb`]보다 빠르며 열거형(enums)과 같은 일부 Rust 기능 지원도 우수합니다.
### 사전 준비
[C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) 확장 기능을 설치하고 https://code.visualstudio.com/docs/cpp/config-msvc#_prerequisites에 따라 Visual Studio Windows Debuger를 설치하십시오.
### launch.json 및 tasks.json 설정
```json title=".vscode/launch.json"
{
// VS Code의 IntelliSense 입력 지원 기능을 사용하여 사용 가능한 속성에 대해 알아보십시오.
// 마우스를 기존 속성 위에 놓으면 해당 설명이 표시됩니다.
// 자세한 내용은 https://go.microsoft.com/fwlink/?linkid=830387을 참조하십시오.
"version": "0.2.0",
"configurations": [
{
"name": "Launch App Debug",
"type": "cppvsdbg",
"request": "launch",
// 실행 파일(exe) 이름을 실제로 사용하는 exe 파일 이름으로 변경하십시오.
// "릴리스 빌드"(공개판)를 디버깅하려면 `target/debug`를 `release/debug`로 변경하십시오.)
"program": "${workspaceRoot}/src-tauri/target/debug/your-app-name-here.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "ui:dev"
}
]
}
```
Tauri CLI는 사용되지 않으므로 CLI 고유의 기능은 **실행되지 않습니다**. `tasks.json`은 `lldb`의 경우와 동일하지만, 시작 전에 항상 컴파일하고 싶다면 설정 그룹을 추가하여 자신의 `preLaunchTask`를 `launch.json`에서 `tasks.json`으로 타겟팅해야 합니다.
다음은 개발 서버(`beforeDevCommand`에 해당)와 컴파일(`cargo build`)을 그룹으로 실행하는 사례입니다. 이를 사용하려면 `launch.json`의 `preLaunchTask` 설정을 `dev`(또는 그룹에 붙인 이름)로 변경합니다.
```json title=".vscode/tasks.json"
{
// tasks.json 형식에 대한 문서는
// https://go.microsoft.com/fwlink/?LinkId=733558을 참조하십시오.
"version": "2.0.0",
"tasks": [
{
"label": "build:debug",
"type": "cargo",
"command": "build",
"options": {
"cwd": "${workspaceRoot}/src-tauri"
}
},
{
"label": "ui:dev",
"type": "shell",
// `dev`는 백그라운드에서 실행이 계속됩니다.
// 이상적으로는 `problemMatcher`도 설정해야 합니다.
// https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson을 참조하십시오.
"isBackground": true,
// 이 부분을 자신의 `beforeBuildCommand`에 맞게 변경합니다:
"command": "yarn",
"args": ["dev"]
},
{
"label": "dev",
"dependsOn": ["build:debug", "ui:dev"],
"group": {
"kind": "build"
}
}
]
}
```
<div style="text-align: right">
【※ 이 한국어판은, 「Jul 23, 2024 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,523 @@
---
title: 모바일 플러그인 개발
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
:::tip[플러그인 개발]
이 장의 많은 개념은 이전 장의 [플러그인 개발](/ko/develop/plugins/)에서 설명된 기초 위에 구축되었으므로 그 내용을 충분히 이해해 주십시오.
:::
플러그인은 Kotlin(또는 Java)과 Swift로 작성된 네이티브 모바일 코드를 실행할 수 있습니다. 기본 플러그인 템플릿에는 Kotlin을 사용한 "Android 라이브러리 프로젝트"와 Rust 코드에서 어떻게 실행시키는지(트리거하는지)를 설명하는 모바일 커맨드 샘플을 포함한 "Swift 패키지"가 포함되어 있습니다.
## 플러그인 프로젝트 초기화
새로운 플러그인 프로젝트를 초기화하려면 이전 장 [플러그인 개발](/ko/develop/plugins/#플러그인-프로젝트-초기화)의 절차를 따르십시오.
기존 플러그인에 Android 또는 iOS 기능을 추가하고 싶다면, `plugin android init`과 `plugin ios init`을 사용하여 모바일 라이브러리 프로젝트를 부트스트랩(시작)하고 필요한 변경 사항을 통합할 수 있습니다.
기본 플러그인 템플릿은 플러그인 구현을 `desktop.rs`와 `mobile.rs`라는 두 개의 별도 모듈로 분할합니다.
"데스크톱 구현"에서는 Rust 코드를 사용하여 기능을 구현하지만, "모바일 구현"에서는 네이티브 모바일 코드로 메시지를 보내 함수를 실행하고 결과를 얻습니다. 두 구현에서 공통 로직이 필요한 경우, `lib.rs`에서 정의합니다:
```rust title="src/lib.rs"
use tauri::Runtime;
impl<R: Runtime> <plugin-name><R> {
pub fn do_something(&self) {
// 여기에 데스크톱과 모바일 간에 공유되는 구현(이 예에서는 do_something 함수의 내용)을 정의합니다
}
}
```
이 구현은 커맨드와 Rust 코드 양쪽에서 사용 가능한 API를 공유하는 프로세스를 간소화합니다.
### Android 플러그인 개발
Android용 Tauri 플러그인은 `app.tauri.plugin.Plugin`을 확장하고 `app.tauri.annotation.TauriPlugin`으로 어노테이션된 "Kotlin 클래스"로 정의됩니다. `app.tauri.annotation.Command`로 어노테이션된 각 메서드는 Rust 또는 JavaScript에서 호출할 수 있습니다.
<TranslationNote lang="ko">
**어노테이션** annotation. 데이터에 관련 정보를 주석으로 부여하는 것. 자세한
내용은 [Wikipedia](https://ko.wikipedia.org/wiki/자바_애너테이션)를
참조하십시오.
</TranslationNote>
Tauri는 Android 플러그인 구현에 기본적으로 Kotlin을 사용하지만, 필요에 따라 Java로 전환할 수도 있습니다. 플러그인을 생성한 후, Android Studio에서 Kotlin 플러그인 클래스를 마우스 오른쪽 버튼으로 클릭하고 메뉴에서 "Kotlin 파일을 Java 파일로 변환" 옵션을 선택합니다. Kotlin 프로젝트의 Java로의 마이그레이션에서는 Android Studio의 가이드를 따르십시오.
### iOS 플러그인 개발
iOS용 Tauri 플러그인은 `Tauri` 패키지의 `Plugin` 클래스를 확장하는 Swift 클래스로 정의됩니다. `@objc` 속성과 `(_invoke: Invoke)` 매개변수를 가진 각 함수(예: `@objc private func download(_invoke: Invoke) { }`)는 Rust 또는 JavaScript에서 호출할 수 있습니다.
플러그인은 [Swift 패키지](https://www.swift.org/package-manager/)로 정의되어 있으므로 Swift의 패키지 관리자를 사용하여 종속성을 관리할 수 있습니다.
## 플러그인 설정
플러그인 설정 방법에 대한 자세한 내용은 이전 장 "플러그인 개발"의 [플러그인 설정](/ko/develop/plugins/#플러그인-설정)을 참조하십시오.
모바일 플러그인 인스턴스에는 플러그인 설정용 "게터" 커맨드가 있습니다:
<Tabs syncKey="mobileOs">
<TabItem label="Android">
```kotlin
import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.TauriPlugin
import app.tauri.annotation.InvokeArg
@InvokeArg
class Config {
var timeout: Int? = 3000
}
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
private var timeout: Int? = 3000
override fun load(webView: WebView) {
getConfig(Config::class.java).let {
this.timeout = it.timeout
}
}
}
```
</TabItem>
<TabItem label="iOS">
```swift
struct Config: Decodable {
let timeout: Int?
}
class ExamplePlugin: Plugin {
var timeout: Int? = 3000
@objc public override func load(webview: WKWebView) {
do {
let config = try parseConfig(Config.self)
self.timeout = config.timeout
} catch {}
}
}
```
</TabItem>
</Tabs>
## 라이프사이클 이벤트
플러그인은 여러 라이프사이클 이벤트에 후크할 수 있습니다:
- [load](#load): 플러그인이 Webview에 로드되었을 때
- [onNewIntent](#onnewintent): Android 전용. 액티비티가 재개되었을 때
이전 장의 "플러그인 개발"에는 위 이외의 [플러그인 라이프사이클 이벤트](/ko/develop/plugins/#라이프사이클-이벤트)가 기재되어 있습니다.
### "load"
- **언제**: 플러그인이 Webview에 로드되었을 때
- **목적**: 플러그인 초기화 코드 실행
<Tabs syncKey="mobileOs">
<TabItem label="Android">
```kotlin
import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun load(webView: WebView) {
// 여기서 플러그인 설정 실행
}
}
```
</TabItem>
<TabItem label="iOS">
```swift
class ExamplePlugin: Plugin {
@objc public override func load(webview: WKWebView) {
let timeout = self.config["timeout"] as? Int ?? 30
}
}
```
</TabItem>
</Tabs>
### "onNewIntent"
**참고**: 이 플러그인은 Android에서만 사용할 수 있습니다.
- **언제**: 액티비티가 재개되었을 때. 자세한 내용은 [Activity#onNewIntent](<https://developer.android.com/reference/android/app/Activity#onNewIntent(android.content.Intent)>)를 참조하십시오.
- **목적**: "알림"이 클릭되었을 때나 "[딥 링크](https://ko.wikipedia.org/wiki/딥_링크)"에 액세스했을 때 등 애플리케이션 재시작 처리
```kotlin
import android.app.Activity
import android.content.Intent
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun onNewIntent(intent: Intent) {
// 새로운 "인텐트" 이벤트 처리
}
}
```
## 모바일 커맨드 추가
각 모바일 프로젝트에는 Rust 코드에서 호출 가능한 커맨드를 정의할 수 있는 플러그인 클래스가 있습니다:
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs syncKey="mobileOs">
<TabItem label="Android">
```kotlin
import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
val ret = JSObject()
ret.put("path", "/path/to/photo.jpg")
invoke.resolve(ret)
}
}
```
Kotlin의 `suspend` 함수를 사용하려면 커스텀 "[코루틴](https://ko.wikipedia.org/wiki/코루틴)" 스코프를 사용해야 합니다.
```kotlin
import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.TauriPlugin
// 데이터 취득을 목적으로 하는 경우 Dispatchers.IO로 변경합니다
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
scope.launch {
openCameraInner(invoke)
}
}
private suspend fun openCameraInner(invoke: Invoke) {
val ret = JSObject()
ret.put("path", "/path/to/photo.jpg")
invoke.resolve(ret)
}
}
```
</TabItem>
<TabItem label="iOS">
```swift
class ExamplePlugin: Plugin {
@objc public func openCamera(_ invoke: Invoke) throws {
invoke.resolve(["path": "/path/to/photo.jpg"])
}
}
```
</TabItem>
</Tabs>
Rust에서 모바일 커맨드를 호출하려면 [`tauri::plugin::PluginHandle`](https://docs.rs/tauri/2.0.0/tauri/plugin/struct.PluginHandle.html)을 사용합니다.
```rust
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use tauri::Runtime;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CameraRequest {
quality: usize,
allow_edit: bool,
}
#[derive(Deserialize)]
pub struct Photo {
path: PathBuf,
}
impl<R: Runtime> <plugin-name;pascal-case><R> {
pub fn open_camera(&self, payload: CameraRequest) -> crate::Result<Photo> {
self
.0
.run_mobile_plugin("openCamera", payload)
.map_err(Into::into)
}
}
```
## 커맨드 인수
인수는 직렬화되어 커맨드에 전달되며, 모바일 플러그인에서 `Invoke::parseArgs` 함수를 사용하여 구문 분석할 수 있으며, 인수 객체를 설명하는 클래스를 받습니다.
### Android
Android에서는 인수가 `@app.tauri.annotation.InvokeArg`로 어노테이션된 클래스로 정의됩니다. 내부 객체에도 어노테이션을 부여해야 합니다:
```kotlin
import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
@InvokeArg
internal class OpenAppArgs {
lateinit var name: String
var timeout: Int? = null
}
@InvokeArg
internal class OpenArgs {
lateinit var requiredArg: String
var allowEdit: Boolean = false
var quality: Int = 100
var app: OpenAppArgs? = null
}
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
val args = invoke.parseArgs(OpenArgs::class.java)
}
}
```
:::note
선택적 인수는 `var <argumentName>: Type? = null`로 정의됩니다.
기본값을 가진 인수는 `var <argumentName>: Type = <default-value>`로 정의됩니다.
필수 인수는 `lateinit var <argumentName>: Type`으로 정의됩니다.
:::
### iOS
iOS에서는 인수가 `Decodable`을 상속하는 클래스로 정의됩니다. 내부 객체도 Decodable 프로토콜을 상속해야 합니다:
```swift
class OpenAppArgs: Decodable {
let name: String
var timeout: Int?
}
class OpenArgs: Decodable {
let requiredArg: String
var allowEdit: Bool?
var quality: UInt8?
var app: OpenAppArgs?
}
class ExamplePlugin: Plugin {
@objc public func openCamera(_ invoke: Invoke) throws {
let args = try invoke.parseArgs(OpenArgs.self)
invoke.resolve(["path": "/path/to/photo.jpg"])
}
}
```
:::note
선택적 인수는 `var <argumentName>: Type?`로 정의됩니다.
기본값을 가진 인수는 **지원되지 않습니다**.
대신, "null 허용 형식"을 사용하여 커맨드 함수에 기본값을 설정합니다.
필수 인수는 `let <argumentName>: Type`으로 정의됩니다.
:::
## 접근 권한
플러그인이 최종 사용자로부터 접근 권한을 필요로 하는 경우, Tauri는 접근 권한 확인 및 요청 프로세스를 간소화합니다.
<Tabs syncKey="mobileOs">
<TabItem label="Android">
먼저, 필요한 접근 권한 목록과 코드 내에서 각 그룹을 식별하기 위한 별칭을 정의합니다. 이 처리는 `TauriPlugin` 어노테이션 내에서 수행됩니다:
```kotlin
@TauriPlugin(
permissions = [
Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "postNotification")
]
)
class ExamplePlugin(private val activity: Activity): Plugin(activity) { }
```
</TabItem>
<TabItem label="iOS">
먼저, `checkPermissions` 함수와 `requestPermissions` 함수를 재정의합니다:
```swift
class ExamplePlugin: Plugin {
@objc open func checkPermissions(_ invoke: Invoke) {
invoke.resolve(["postNotification": "prompt"])
}
@objc public override func requestPermissions(_ invoke: Invoke) {
// 여기서 접근 권한을 요청합니다
// 이어서 요청을 해결합니다
invoke.resolve(["postNotification": "granted"])
}
}
```
</TabItem>
</Tabs>
Tauri는 플러그인에 대한 두 가지 커맨드 `checkPermissions`와 `requestPermissions`를 자동으로 구현합니다.
이 두 커맨드는 JavaScript 또는 Rust에서 직접 호출할 수 있습니다.
<Tabs syncKey="lang">
<TabItem label="JavaScript">
```javascript
import { invoke, PermissionState } from '@tauri-apps/api/core'
interface Permissions {
postNotification: PermissionState
}
// 접근 권한 상태 확인
const permission = await invoke<Permissions>('plugin:<plugin-name>|checkPermissions')
if (permission.postNotification === 'prompt-with-rationale') {
// 사용자에게 접근 권한이 필요한 이유에 대한 정보를 표시합니다
}
// 접근 권한 요청
if (permission.postNotification.startsWith('prompt')) {
const state = await invoke<Permissions>('plugin:<plugin-name>|requestPermissions', { permissions: ['postNotification'] })
}
```
</TabItem>
<TabItem label="Rust">
```rust
use serde::{Serialize, Deserialize};
use tauri::{plugin::PermissionState, Runtime};
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct PermissionResponse {
pub post_notification: PermissionState,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct RequestPermission {
post_notification: bool,
}
impl<R: Runtime> Notification<R> {
pub fn request_post_notification_permission(&self) -> crate::Result<PermissionState> {
self.0
.run_mobile_plugin::<PermissionResponse>("requestPermissions", RequestPermission { post_notification: true })
.map(|r| r.post_notification)
.map_err(Into::into)
}
pub fn check_permissions(&self) -> crate::Result<PermissionResponse> {
self.0
.run_mobile_plugin::<PermissionResponse>("checkPermissions", ())
.map_err(Into::into)
}
}
```
</TabItem>
</Tabs>
## 플러그인 이벤트
{/* TODO: Is this section a duplicate of Lifecycle Events above? */}
플러그인은 `trigger` 함수를 사용하여 언제든지 이벤트를 발행할 수 있습니다:
<Tabs syncKey="mobileOs">
<TabItem label="Android">
```kotlin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun load(webView: WebView) {
trigger("load", JSObject())
}
override fun onNewIntent(intent: Intent) {
// 새로운 "인텐트" 이벤트 처리
if (intent.action == Intent.ACTION_VIEW) {
val data = intent.data.toString()
val event = JSObject()
event.put("data", data)
trigger("newIntent", event)
}
}
@Command
fun openCamera(invoke: Invoke) {
val payload = JSObject()
payload.put("open", true)
trigger("camera", payload)
}
}
```
</TabItem>
<TabItem label="iOS">
```swift
class ExamplePlugin: Plugin {
@objc public override func load(webview: WKWebView) {
trigger("load", data: [:])
}
@objc public func openCamera(_ invoke: Invoke) {
trigger("camera", data: ["open": true])
}
}
```
</TabItem>
</Tabs>
[`addPluginListener`](/reference/javascript/api/namespacecore/#addpluginlistener)라는 헬퍼 함수를 사용하여 NPM 패키지에서 헬퍼 함수를 호출할 수 있습니다:
```javascript
import { addPluginListener, PluginListener } from '@tauri-apps/api/core';
export async function onRequest(
handler: (url: string) => void
): Promise<PluginListener> {
return await addPluginListener(
'<plugin-name>',
'event-name',
handler
);
}
```

View File

@@ -0,0 +1,499 @@
---
title: 플러그인 개발
i18nReady: true
sidebar:
label: 개요
order: 10
---
{/* TODO: Add a CLI section */}
import TranslationNote from '@components/i18n/TranslationNote.astro';
import CommandTabs from '@components/CommandTabs.astro';
{/* TODO: Link to windowing system, commands for sending messages, and event system */}
:::tip[플러그인 개발]
이 장은 "Tauri 플러그인 개발"에 관한 것입니다. 현재 사용 가능한 플러그인 목록과 그 사용법에 대해서는 목차 **Plugins**의 "개요"에 있는 [기능과 레시피 목록](/ko/plugin/)을 참조하십시오.
:::
플러그인은 Tauri 라이프사이클에 후크하거나, Webview API에 의존하는 Rust 코드를 개방하거나, Rust, Kotlin, Swift 코드로 명령을 처리하는 등 다양한 작업을 수행할 수 있습니다.
Tauri는 Webview 기능을 갖춘 창 시스템, Rust 프로세스와 Webview 간의 메시지 전송 방법, 이벤트 시스템, 그리고 개발 경험을 향상시키는 다양한 도구를 제공합니다. 설계상 Tauri 코어에는 모든 사람에게 필요하지 않은 기능은 포함되어 있지 않습니다. 대신 "플러그인"이라는 Tauri 애플리케이션에 외부 기능을 추가하기 위한 메커니즘을 제공합니다.
Tauri 플러그인은 "Cargo 크레이트"와 명령 및 이벤트의 API 바인딩을 제공하는 선택적 "NPM 패키지"로 구성됩니다. 또한 플러그인 프로젝트에는 Android 라이브러리 프로젝트와 iOS용 Swift 패키지도 포함될 수 있습니다. Android 및 iOS용 플러그인 개발에 대한 자세한 내용은 다음 장 [모바일 플러그인 개발 가이드](/ko/develop/plugins/develop-mobile/)를 참조하십시오.
<TranslationNote lang="ko">
**API 바인딩** 원문 API bindings. "API 바인딩"은 API 호출 시 주고받는 다양한
데이터를 API 사양에 맞게 자동으로 복잡한 데이터 변환 처리를 수행하는
메커니즘입니다.
</TranslationNote>
{/* TODO: https://github.com/tauri-apps/tauri/issues/7749 */}
## 명명 규칙
Tauri 플러그인에는 "접두사"와 그 뒤에 "플러그인 이름"이 붙습니다. "플러그인 이름"은 [`tauri.conf.json > plugins`](/reference/config/#pluginconfig)의 플러그인 설정에서 지정됩니다.
기본적으로 Tauri는 사용자가 만드는 플러그인 크레이트에 `tauri-plugin-`이라는 "접두사"를 붙입니다. 이를 통해 플러그인이 Tauri 커뮤니티 내에서 쉽게 발견되고 Tauri CLI에서도 사용할 수 있게 됩니다. 새 플러그인 프로젝트를 초기화할 때는 "플러그인 이름"을 지정해야 합니다. 생성되는 크레이트 이름은 `tauri-plugin-{플러그인 이름}`, JavaScript NPM 패키지 이름은 `tauri-plugin-{플러그인 이름}-api`가 됩니다(단, 가능하면 [NPM 스코프](https://docs.npmjs.com/about-scopes)를 사용하는 것이 좋습니다). Tauri의 NPM 패키지 명명 규칙은 `@scope-name/plugin-{플러그인 이름}`입니다.
## 플러그인 프로젝트 초기화
새 플러그인 프로젝트를 부트스트랩(시작)하려면 `plugin new`를 실행합니다. NPM 패키지가 필요 없는 경우 `--no-api` CLI 플래그를 사용하십시오. Android 또는 iOS를 지원하도록 플러그인을 초기화하려면 `--android` 또는 `--ios` 플래그를 사용하십시오.
설치 후 다음 명령을 실행하여 플러그인 프로젝트를 만들 수 있습니다.
<CommandTabs npm="npx @tauri-apps/cli plugin new [name]" />
그러면 디렉토리 `tauri-plugin-[name(플러그인 이름)]`에서 플러그인이 초기화되고, 지정한 CLI 플래그에 따라 완성된 프로젝트는 예를 들어 다음과 같이 됩니다.
```
. tauri-plugin-[name(플러그인 이름)]/
├── src/ - Rust 코드
│ ├── commands.rs - webview가 사용할 수 있는 명령 정의
| ├── desktop.rs - 데스크톱 구현
| ├── error.rs - 결과 반환 값에 사용하는 기본 오류 유형
│ ├── lib.rs - 적절한 구현, 설정 상태 ... 재전송
│ ├── mobile.rs - 모바일 구현
│ └── models.rs - 공유되는 구조체
├── permissions/ - (생성된) 명령용 접근 권한 파일 저장
├── android - Android 라이브러리
├── ios - Swift 패키지
├── guest-js - JavaScript API 바인딩 소스 코드
├── dist-js - guest-js에서 변환된 자산
├── Cargo.toml - Cargo 크레이트 메타데이터
└── package.json - NPM 패키지 메타데이터
```
기존 플러그인에 Android 또는 iOS 기능을 추가하려면 `plugin android add`와 `plugin ios add`를 사용하여 모바일 라이브러리 프로젝트를 부트스트랩(시작)하고 필요한 변경 사항을 통합할 수 있습니다.
## 모바일 플러그인 개발
플러그인은 Kotlin(또는 Java)과 Swift로 작성된 네이티브 모바일 코드를 실행할 수 있습니다. 기본 플러그인 템플릿에는 Kotlin을 사용한 "Android 라이브러리 프로젝트"와 "Swift 패키지"가 포함되어 있습니다. Rust 코드에서 어떻게 실행시키는지(트리거하는지)를 보여주는 모바일 명령 샘플도 포함합니다.
모바일용 플러그인 개발에 대한 자세한 내용은 다음 장의 [모바일 플러그인 개발](/ko/develop/plugins/develop-mobile/)을 참조하십시오.
## 플러그인 설정
플러그인이 사용되는 Tauri 애플리케이션에서는 플러그인 설정을 `tauri.conf.json`에서 수행합니다. 항목 `plugin-name`은 실제 "플러그인 이름"입니다.
```json
{
"build": { ... },
"tauri": { ... },
"plugins": {
"plugin-name": {
"timeout": 30
}
}
}
```
플러그인 설정은 `Builder`에 설정되고 실행 시에 구문 분석됩니다. 다음은 플러그인 설정을 지정하는 데 사용되는 `Config` 구조체의 예입니다.
```rust title="src/lib.rs"
use tauri::plugin::{Builder, Runtime, TauriPlugin};
use serde::Deserialize;
// 플러그인 설정 정의
#[derive(Deserialize)]
struct Config {
timeout: usize,
}
pub fn init<R: Runtime>() -> TauriPlugin<R, Config> {
// 대신 `Builder::<R, Option<Config>>`를 사용하여
// 플러그인 설정을 선택 사항으로 만듭니다.
Builder::<R, Config>::new("<plugin-name>")
.setup(|app, api| {
let timeout = api.config().timeout;
Ok(())
})
.build()
}
```
## 라이프사이클 이벤트
플러그인은 여러 라이프사이클 이벤트에 후크할 수 있습니다.
- [setup](#setup): 플러그인이 초기화될 때
- [on_navigation](#on_navigation): Webview가 탐색을 시작할 때
- [on_webview_ready](#on_webview_ready): 새 창이 생성될 때
- [on_event](#on_event): 이벤트 루프 "이벤트" 알림 시
- [on_drop](#on_drop): 플러그인이 삭제될 때
위 이외에 모바일 플러그인 관련 [라이프사이클 이벤트](/ko/develop/plugins/develop-mobile/#라이프사이클-이벤트)도 있습니다.
### "setup"
- **언제**: 플러그인이 초기화될 때
- **목적**: 모바일 플러그인 등록, 상태 관리, 백그라운드 작업 실행
```rust title="src/lib.rs"
use tauri::{Manager, plugin::Builder};
use std::{collections::HashMap, sync::Mutex, time::Duration};
struct DummyStore(Mutex<HashMap<String, String>>);
Builder::new("<plugin-name>")
.setup(|app, api| {
app.manage(DummyStore(Default::default()));
let app_ = app.clone();
std::thread::spawn(move || {
loop {
app_.emit("tick", ());
std::thread::sleep(Duration::from_secs(1));
}
});
Ok(())
})
```
### "on_navigation"
- **언제**: Webview가 탐색을 시작할 때
- **목적**: 탐색 유효성 검사, URL 변경 추적
`false`가 반환되면 탐색이 취소됩니다.
```rust title="src/lib.rs"
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_navigation(|window, url| {
println!("window {} is navigating to {}", window.label(), url);
// 금지된 경우 탐색을 취소합니다.
url.scheme() != "forbidden"
})
```
### "on_webview_ready"
- **언제**: 새 창이 생성될 때
- **목적**: 모든 창에 대해 초기화 스크립트 실행
```rust title="src/lib.rs"
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_webview_ready(|window| {
window.listen("content-loaded", |event| {
println!("webview content has been loaded");
});
})
```
### "on_event"
- **언제**: 이벤트 루프 "이벤트" 알림 시
- **목적**: 창 이벤트, 메뉴 이벤트, 애플리케이션 종료 요청 등 코어 이벤트 처리
이 라이프사이클 후크를 사용하면 모든 이벤트 루프의 "[이벤트](https://docs.rs/tauri/2.0.0/tauri/enum.RunEvent.html)" 알림을 받을 수 있습니다.
```rust title="src/lib.rs"
use std::{collections::HashMap, fs::write, sync::Mutex};
use tauri::{plugin::Builder, Manager, RunEvent};
struct DummyStore(Mutex<HashMap<String, String>>);
Builder::new("<plugin-name>")
.setup(|app, _api| {
app.manage(DummyStore(Default::default()));
Ok(())
})
.on_event(|app, event| {
match event {
RunEvent::ExitRequested { api, .. } => {
// 사용자가 창을 닫도록 요청했고 창이 남아 있지 않습니다.
// 앱 종료 방지:
api.prevent_exit();
}
RunEvent::Exit => {
// 앱이 종료됩니다. 여기서 정리합니다.
let store = app.state::<DummyStore>();
write(
app.path().app_local_data_dir().unwrap().join("store.json"),
serde_json::to_string(&*store.0.lock().unwrap()).unwrap(),
)
.unwrap();
}
_ => {}
}
})
```
### "on_drop"
- **언제**: 플러그인이 삭제될 때
- **목적**: 플러그인이 삭제될 때 코드 실행
자세한 내용은 [`Drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html)을 참조하십시오.
```rust title="src/lib.rs"
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_drop(|app| {
// 플러그인이 삭제되었습니다...
})
```
## Rust API 개방
<TranslationNote lang="ko">
**개방** 원문은
expose(노출하다, 드러내다, 드러내다, 공개하다). 본고에서는 "~에서 볼 수 있도록 하다"라는 관점에서 주로 "개방"이라는 번역어를 사용합니다.
</TranslationNote>
프로젝트의 `desktop.rs` 및 `mobile.rs`에 정의된 플러그인 API는 플러그인과 동일한 이름("파스칼 케이스"로 표기)을 가진 구조체로 사용자에게 내보내집니다. 플러그인이 설정되면 이 구조체의 인스턴스가 생성되어 "상태"로 관리됩니다. 이를 통해 사용자는 플러그인에 정의된 확장 트레이트를 통해 언제든지 `Manager` 인스턴스(예: `AppHandle`, `App`, `Window` 등)를 사용하여 이 구조체를 가져올 수 있습니다.
<TranslationNote lang="ko">
**파스칼 케이스** pascal case. 변수명 등을 복합어로 표기할 때의 명명 규칙 중 하나로, 각 단어의 첫 글자를 "PascalCase"처럼 대문자로 하는 형식. 또한 유사한 표기법으로 "카멜 케이스 camelCase"가 있지만, 카멜 케이스에서는 첫 단어는 대문자를 사용하지 않습니다. 자세한 내용은 Wikipedia의 "[카멜 케이스](https://ko.wikipedia.org/wiki/카멜_표기법)"를 참조하십시오.
</TranslationNote>
예를 들어, [`global-shortcut plugin`](/ko/plugin/global-shortcut/)은 `GlobalShortcutExt` 트레이트의 `global_shortcut` 메서드를 사용하여 읽을 수 있는 `GlobalShortcut` 구조체를 정의합니다.
```rust title="src-tauri/src/lib.rs"
use tauri_plugin_global_shortcut::GlobalShortcutExt;
tauri::Builder::default()
.plugin(tauri_plugin_global_shortcut::init())
.setup(|app| {
app.global_shortcut().register(...);
Ok(())
})
```
## 명령 추가
명령은 `commands.rs` 파일에 정의되어 있습니다. 이는 일반적인 Tauri 애플리케이션의 명령입니다. 애플리케이션 명령과 마찬가지로 AppHandle 및 Window의 각 인스턴스에 직접 액세스하고 "상태"를 확인하며 입력을 가져올 수 있습니다. Tauri 명령에 대한 자세한 내용은 앞서 "프론트엔드에서 Rust 호출" 장의 [명령 가이드](/ko/develop/calling-rust/)를 참조하십시오.
다음 명령은 [의존성 주입](https://ko.wikipedia.org/wiki/의존성_주입)을 통해 `AppHandle`과 `Window` 인스턴스에 액세스하는 방법을 보여주며, 두 개의 입력 매개변수(`on_progress`와 `url`)를 받습니다.
```rust title="src/commands.rs"
use tauri::{command, ipc::Channel, AppHandle, Runtime, Window};
#[command]
async fn upload<R: Runtime>(app: AppHandle<R>, window: Window<R>, on_progress: Channel, url: String) {
// 여기에 명령 로직을 구현합니다.
on_progress.send(100).unwrap();
}
```
명령을 Webview에 개방하려면 `lib.rs`의 `invoke_handler()` 호출에 후크해야 합니다.
```rust title="src/lib.rs"
Builder::new("<plugin-name>")
.invoke_handler(tauri::generate_handler![commands::upload])
```
플러그인 사용자가 JavaScript에서 명령을 쉽게 호출할 수 있도록 `webview-src/index.ts`에 바인딩 함수를 정의하십시오.
```js name="webview-src/index.ts"
import { invoke, Channel } from '@tauri-apps/api/core'
export async function upload(url: string, onProgressHandler: (progress: number) => void): Promise<void> {
const onProgress = new Channel<number>()
onProgress.onmessage = onProgressHandler
await invoke('plugin:<plugin-name>|upload', { url, onProgress })
}
```
테스트하기 전에 반드시 TypeScript 코드를 빌드하십시오.
### 명령 접근 권한
기본적으로 프론트엔드에서 명령에 액세스할 수 없습니다. 명령 중 하나를 실행하려고 하면 "거부" 오류가 발생합니다. 실제로 명령을 사용할 수 있도록 하려면 각 명령을 허용하는 접근 권한도 정의해야 합니다.
#### 접근 권한 파일
접근 권한은 `permissions` 디렉토리 내의 JSON 또는 TOML 파일로 정의됩니다. 각 파일에서는 접근 권한 목록, 접근 권한 세트 목록 및 플러그인의 기본 접근 권한을 정의할 수 있습니다.
##### 접근 권한
접근 권한은 플러그인 명령의 권한을 정의합니다. 명령 목록을 "허용" 또는 "거부"할 수 있으며, 명령별 범위와 전역 범위를 연관시킬 수 있습니다.
```toml title="permissions/start-server.toml"
"$schema" = "schemas/schema.json"
[[permission]]
identifier = "allow-start-server"
description = "Enables the start_server command."
commands.allow = ["start_server"]
[[permission]]
identifier = "deny-start-server"
description = "Denies the start_server command."
commands.deny = ["start_server"]
```
##### 범위(적용 범위)
범위를 사용하면 플러그인은 개별 명령에 대해 더 세분화된 제한을 정의할 수 있습니다.
각 접근 권한에는 명령별로 또는 플러그인 전체에 대해 "허용" 또는 "거부"되는 내용을 정의하는 범위 객체 목록을 정의합니다.
`shell` 플러그인에서 생성이 "허용"되는 바이너리 목록용 범위 데이터를 보유하는 구조체 샘플을 정의해 보겠습니다.
```rust title="src/scope.rs"
#[derive(Debug, schemars::JsonSchema)]
pub struct Entry {
pub binary: String,
}
```
###### 명령 범위
플러그인 사용자(소비자)는 자신의 "보안 설정" 파일에서 특정 명령의 범위를 정의할 수 있습니다(자세한 내용은 [영어 문서](/reference/acl/scope/) 참조).
명령별 범위는 [`tauri::ipc::CommandScope`](https://docs.rs/tauri/2.0.0/tauri/ipc/struct.CommandScope.html) 구조체를 사용하여 읽을 수 있습니다.
<TranslationNote lang="ko">
**플러그인 사용자(소비자)** plugin consumer. "소비자"는 소비자의 의미이지만,
본고에서는 읽기 쉽게 "사용자"로 했습니다. consumer 라는 단어가 사용된 이유는
"플러그인 사용자가 반드시 인간이 아니기 때문(서비스를 소비하는 것이
사람/명령/시스템 등이기 때문)"이라는 설명이
[GitHub](https://github.com/Kong/kong/issues/4391)에 있습니다.
</TranslationNote>
```rust title="src/commands.rs"
use tauri::ipc::CommandScope;
use crate::scope::Entry;
async fn spawn<R: tauri::Runtime>(app: tauri::AppHandle<R>, command_scope: CommandScope<'_, Entry>) -> Result<()> {
let allowed = command_scope.allows();
let denied = command_scope.denies();
todo!()
}
```
###### 전역 범위
접근 권한에 "허용" 또는 "거부"할 명령이 정의되어 있지 않은 경우 "범위 권한"으로 간주되며, 플러그인에는 전역 범위만 정의됩니다.
<TranslationNote lang="ko">
**범위 권한** 정규 번역 불명. 원문 its considered a scope permission(문맥
불명).
</TranslationNote>
```toml title="permissions/spawn-node.toml"
[[permission]]
identifier = "allow-spawn-node"
description = "This scope permits spawning the `node` binary."
[[permission.scope.allow]]
binary = "node"
```
전역 범위는 [`tauri::ipc::GlobalScope`](https://docs.rs/tauri/2.0.0/tauri/ipc/struct.GlobalScope.html) 구조체를 사용하여 읽을 수 있습니다.
```rust title="src/commands.rs"
use tauri::ipc::GlobalScope;
use crate::scope::Entry;
async fn spawn<R: tauri::Runtime>(app: tauri::AppHandle<R>, scope: GlobalScope<'_, Entry>) -> Result<()> {
let allowed = scope.allows();
let denied = scope.denies();
todo!()
}
```
:::note
유연성을 위해 전역 범위와 명령 범위를 모두 확인하는 것이 좋습니다.
<TranslationNote lang="ko">
**유연성을 위해** for flexibility(문맥 불명, 직역). "자유도?", "융통성?",
"탄력적인 운영?"
</TranslationNote>
:::
###### 스키마(데이터 구조 정의)
범위 항목(범위 설정)에는 플러그인 사용자(소비자)가 범위 형식을 인식하고 IDE에서 자동 완성할 수 있도록 "JSON 스키마"를 생성하기 위한 `schemars` 종속성이 필요합니다.
<TranslationNote lang="ko">
**JSON 스키마** JSON schema. JSON 데이터의 구조(키, 값, 객체, 배열, 데이터
유형, 제약 조건 등)를 정의하고 데이터 형식이 적합한지 검증하기 위한 도구.
</TranslationNote>
스키마를 정의하려면 먼저 Cargo.toml 파일에 종속성을 추가합니다.
```toml
# scope.rs 모듈은 앱 코드와 빌드 스크립트 간에 공유되므로 종속성과 빌드 종속성 모두에 schemars를 추가해야 합니다.
[dependencies]
schemars = "0.8"
[build-dependencies]
schemars = "0.8"
```
빌드 스크립트에 다음 코드를 추가합니다.
```rust title="build.rs"
#[path = "src/scope.rs"]
mod scope;
const COMMANDS: &[&str] = &[];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.global_scope_schema(schemars::schema_for!(scope::Entry))
.build();
}
```
##### 접근 권한 세트
"접근 권한 세트"는 사용자가 더 높은 추상화 수준에서 플러그인을 관리할 수 있는 개별 접근 권한 그룹입니다.
예를 들어, 하나의 API가 여러 명령을 사용하거나 명령 컬렉션에 논리적 관계가 있는 경우 해당 명령을 포함하는 세트를 정의해야 합니다.
```toml title="permissions/websocket.toml"
"$schema" = "schemas/schema.json"
[[set]]
identifier = "allow-websocket"
description = "Allows connecting and sending messages through a WebSocket"
permissions = ["allow-connect", "allow-send"]
```
##### 기본 접근 권한
"기본 접근 권한"은 식별자 "`default`"를 가진 특별한 접근 권한 세트입니다. 필요한 명령은 기본적으로 활성화하는 것이 좋습니다.
예를 들어, `http` 플러그인은 `request` 명령이 허용되지 않으면 쓸모가 없습니다.
```toml title="permissions/default.toml"
"$schema" = "schemas/schema.json"
[default]
description = "Allows making HTTP requests"
permissions = ["allow-request"]
```
#### 자동 생성된 접근 권한
각 명령의 접근 권한을 정의하는 가장 간단한 방법은 `build.rs` 파일에 정의된 플러그인 빌드 스크립트의 "자동 생성" 옵션을 사용하는 것입니다.
상수 "COMMANDS" 내에서 명령 목록을 "[snake_case](https://ko.wikipedia.org/wiki/스네이크_케이스)"(스네이크 케이스)로 정의합니다(명령 함수 이름과 일치해야 함). 그러면 Tauri는 자동으로 `allow-$commandname`과 `deny-$commandname` 접근 권한을 생성합니다.
다음 예에서는 `allow-upload` 및 `deny-upload` 접근 권한을 생성합니다.
```rust title="src/commands.rs"
const COMMANDS: &[&str] = &["upload"];
fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
}
```
자세한 내용은 목차 **Security**의 "[접근 권한 Permissions](/ko/security/permissions/)" 장을 참조하십시오.
## "상태" 관리
플러그인은 Tauri 애플리케이션과 마찬가지로 "상태 state"를 관리할 수 있습니다. 자세한 내용은 목차 **Develop**의 "[상태 관리](/ko/develop/state-management/)" 장을 참조하십시오.

View File

@@ -0,0 +1,147 @@
---
title: Rust에서 프론트엔드 호출하기
sidebar:
order: 1
---
`@tauri-apps/api` NPM 패키지는 전역 이벤트와 Webview 특정 이벤트를 모두 감지(수신)하기 위한 API를 제공합니다.
- 전역 이벤트 감지
```ts
import { listen } from '@tauri-apps/api/event';
type DownloadStarted = {
url: string;
downloadId: number;
contentLength: number;
};
listen<DownloadStarted>('download-started', (event) => {
console.log(
`downloading ${event.payload.contentLength} bytes from ${event.payload.url}`
);
});
```
- Webview 특정 이벤트 감지
```ts
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
const appWebview = getCurrentWebviewWindow();
appWebview.listen<string>('logged-in', (event) => {
localStorage.setItem('session-token', event.payload);
});
```
The `listen` 함수는 애플리케이션의 전체 "[라이프타임](https://doc.rust-lang.org/rust-by-example/ja/scope/lifetime.html)" 기간 동안 이벤트 리스너 등록이 유지됩니다.
이벤트 감지(수신)를 중지하려면 `listen` 함수가 반환하는 `unlisten` 함수를 사용할 수 있습니다:
```js
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('download-started', (event) => {});
unlisten();
```
:::note
컴포넌트가 언마운트될 때 등 실행 컨텍스트가 범위(유효 범위)를 벗어나는 경우 항상 `unlisten` 함수를 사용하십시오.
페이지가 다시 로드되거나 다른 URL로 이동하면 리스너는 자동으로 등록 해제됩니다.
단, 이 메커니즘은 "싱글 페이지 애플리케이션(SPA)" 라우터에는 적용되지 않습니다.
> > > 《번역 주》 **싱글 페이지 애플리케이션** 하나의 페이지에서 콘텐츠를 전환하는 애플리케이션이나 웹 페이지의 구조. 자세한 내용은 [Wikipedia](https://ko.wikipedia.org/wiki/단일_페이지_애플리케이션)를 참조하십시오.
> > > :::
또한 Tauri는 이벤트를 한 번만 감지(수신)하기 위한 유틸리티 함수를 제공합니다:
```js
import { once } from '@tauri-apps/api/event';
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
once('ready', (event) => {});
const appWebview = getCurrentWebviewWindow();
appWebview.once('ready', () => {});
```
:::note
프론트엔드에서 발행된 이벤트는 위의 API에 의해 등록된 리스너도 트리거합니다.
자세한 내용은 다음 장 [프론트엔드에서 Rust 호출하기] 설명을 참조하십시오.
:::
#### Rust 이벤트 감지
전역 이벤트와 Webview 특정 이벤트 모두 Rust에 등록된 리스너에게 전달됩니다.
- 전역 이벤트 감지
```rust title="src-tauri/src/lib.rs"
use tauri::Listener;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
app.listen("download-started", |event| {
if let Ok(payload) = serde_json::from_str::<DownloadStarted>(&event.payload()) {
println!("downloading {}", payload.url);
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
- Webview 특정 이벤트 감지
```rust title="src-tauri/src/lib.rs"
use tauri::{Listener, Manager};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let webview = app.get_webview_window("main").unwrap();
webview.listen("logged-in", |event| {
let session_token = event.data;
// save token..
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
The `listen` 함수는 애플리케이션의 전체 "라이프타임" 기간 동안 이벤트 리스너 등록이 유지됩니다.
이벤트 감지(수신)를 중지하려면 `listen` 함수가 반환하는 `unlisten` 함수를 사용할 수 있습니다:
```rust
// unlisten outside of the event handler scope:
let event_id = app.listen("download-started", |event| {});
app.unlisten(event_id);
// unlisten when some event criteria is matched
let handle = app.handle().clone();
app.listen("status-changed", |event| {
if event.data == "ready" {
handle.unlisten(event.id);
}
});
```
또한 Tauri는 이벤트를 한 번만 감지(수신)하기 위한 유틸리티 함수를 제공합니다:
```rust
app.once("ready", |event| {
println!("app is ready");
});
```
이 경우 이벤트 리스너는 첫 번째 트리거 후 즉시 등록 해제됩니다.
[프론트엔드에서 Rust 호출하기]: /ko/develop/calling-rust/

View File

@@ -0,0 +1,270 @@
---
title: Rust에서 프론트엔드 호출하기
sidebar:
order: 1
i18nReady: true
---
import { Content as FrontendListen } from './_sections/frontend-listen.mdx';
이 문서는 Rust 코드에서 애플리케이션의 프론트엔드와 통신하는 방법에 대한 지침을 담고 있습니다.
프론트엔드에서 Rust 코드와 통신하는 방법에 대해서는 다음 절의 "[프론트엔드에서 Rust 호출하기]"를 참조하십시오.
Tauri 애플리케이션의 Rust 측에서는 "Tauri 이벤트 시스템"을 이용하거나, "채널"을 사용하거나, 또는 JavaScript 코드를 직접 검증함으로써 프론트엔드를 호출할 수 있습니다.
## 이벤트 시스템
Tauri에는 Rust와 프론트엔드 간의 양방향 통신이 가능한 간단한 "이벤트 시스템"이 포함되어 있습니다.
이 이벤트 시스템은 소량의 데이터를 스트리밍해야 하는 경우나, 다중 소비자/다중 생산자 패턴(예: 푸시 알림 시스템 등)을 구현해야 하는 상황을 고려하여 설계되었습니다.
저지연(레이턴시) 또는 고처리량 상황을 위한 설계는 아닙니다. 스트리밍 데이터에 최적화된 구현에 대해서는 [채널](#채널-channels) 항목을 참조하십시오.
"Tauri 명령"과 "Tauri 이벤트"의 큰 차이점은 이벤트에는 강력한 형식 지원이 없고, 이벤트 페이로드(데이터 본체)가 항상 JSON 문자열이기 때문에 큰 메시지에는 적합하지 않으며, 이벤트 데이터와 채널을 세밀하게 제어하기 위한 [보안 수준] 시스템이 지원되지 않는다는 것입니다.
구조체 [AppHandle] 및 [WebviewWindow]의 형식(타입)은 이벤트 시스템 트레이트의 [Listener] 및 [Emitter]를 구현합니다.
이벤트는 "전역"(모든 "리스너"에게 전달됨) 또는 "Webview 특정"(지정된 레이블과 일치하는 Webview에만 전달됨) 중 하나가 될 수 있습니다.
### 전역 이벤트
전역 이벤트를 트리거(시작)하려면 [Emitter#emit] 함수를 사용합니다:
```rust title="src-tauri/src/lib.rs"
use tauri::{AppHandle, Emitter};
#[tauri::command]
fn download(app: AppHandle, url: String) {
app.emit("download-started", &url).unwrap();
for progress in [1, 15, 50, 80, 100] {
app.emit("download-progress", progress).unwrap();
}
app.emit("download-finished", &url).unwrap();
}
```
:::note
전역 이벤트는 **모든** 리스너에게 전달됩니다.
:::
### Webview 이벤트
특정 Webview에 의해 지정된 리스너에 대해 이벤트를 트리거하려면 [Emitter#emit_to] 함수를 사용합니다:
```rust title="src-tauri/src/lib.rs"
use tauri::{AppHandle, Emitter};
#[tauri::command]
fn login(app: AppHandle, user: String, password: String) {
let authenticated = user == "tauri-apps" && password == "tauri";
let result = if authenticated { "loggedIn" } else { "invalidCredentials" };
app.emit_to("login", "login-result", result).unwrap();
}
```
[Emitter#emit_filter]를 호출하여 Webview 목록에 이벤트를 트리거할 수도 있습니다.
다음 예에서는 "open-file" 이벤트를 메인 및 파일 뷰어 Webview에 발행합니다:
```rust title="src-tauri/src/lib.rs"
use tauri::{AppHandle, Emitter, EventTarget};
#[tauri::command]
fn open_file(app: AppHandle, path: std::path::PathBuf) {
app.emit_filter("open-file", path, |target| match target {
EventTarget::WebviewWindow { label } => label == "main" || label == "file-viewer",
_ => false,
}).unwrap();
}
```
:::note
Webview 특정 이벤트는 일반적인 전역 이벤트 리스너에 대해서는 트리거**되지 않습니다**.
**어떤** 이벤트든 감지(수신)하려면 `listen` 함수 대신 `listen_any` 함수를 사용해야 합니다. 이 함수는 발행된 이벤트를 "캐치올"(모두 포착)하는 리스너를 정의합니다.
:::
### 이벤트 페이로드
이벤트 페이로드는 임의의 [직렬화 가능 serializable][Serialize] 형식이 될 수 있으며, 이 형식은 [Clone] 트레이트도 구현할 수 있습니다.
이벤트마다 많은 정보를 발행하는 객체를 사용하여 "다운로드 이벤트 예"를 확장해 보겠습니다.
```rust title="src-tauri/src/lib.rs"
use tauri::{AppHandle, Emitter};
use serde::Serialize;
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct DownloadStarted<'a> {
url: &'a str,
download_id: usize,
content_length: usize,
}
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct DownloadProgress {
download_id: usize,
chunk_length: usize,
}
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct DownloadFinished {
download_id: usize,
}
#[tauri::command]
fn download(app: AppHandle, url: String) {
let content_length = 1000;
let download_id = 1;
app.emit("download-started", DownloadStarted {
url: &url,
download_id,
content_length
}).unwrap();
for chunk_length in [15, 150, 35, 500, 300] {
app.emit("download-progress", DownloadProgress {
download_id,
chunk_length,
}).unwrap();
}
app.emit("download-finished", DownloadFinished { download_id }).unwrap();
}
```
### 이벤트 감지(리스닝)
Tauri는 Webview와 Rust 양쪽 인터페이스에서 이벤트를 감지(수신)하기 위한 API를 제공합니다.
#### 프론트엔드 이벤트 감지
<FrontendListen />
## 채널 Channels
> > > 《번역 주》 **채널** "유로, 전송로".
이벤트 시스템은 애플리케이션에서 "전역"으로 사용할 수 있는 간단한 양방향 통신을 수행하도록 설계되었습니다.
내부적으로는 직접 JavaScript 코드를 검증하므로 대량의 데이터를 전송하는 데는 적합하지 않을 수 있습니다.
채널은 빠르고 순서가 지정된 데이터를 전달하도록 설계되었습니다. 따라서 다운로드 진행 상황, 자식 프로세스 출력, WebSocket 메시지와 같은 스트리밍 작업에 내부적으로 사용됩니다.
위의 "다운로드 명령 예"를 "이벤트 시스템" 대신 "채널"을 사용하도록 다시 작성해 보겠습니다.
```rust title="src-tauri/src/lib.rs"
use tauri::{AppHandle, ipc::Channel};
use serde::Serialize;
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase", tag = "event", content = "data")]
enum DownloadEvent<'a> {
#[serde(rename_all = "camelCase")]
Started {
url: &'a str,
download_id: usize,
content_length: usize,
},
#[serde(rename_all = "camelCase")]
Progress {
download_id: usize,
chunk_length: usize,
},
#[serde(rename_all = "camelCase")]
Finished {
download_id: usize,
},
}
#[tauri::command]
fn download(app: AppHandle, url: String, on_event: Channel<DownloadEvent>) {
let content_length = 1000;
let download_id = 1;
on_event.send(DownloadEvent::Started {
url: &url,
download_id,
content_length,
}).unwrap();
for chunk_length in [15, 150, 35, 500, 300] {
on_event.send(DownloadEvent::Progress {
download_id,
chunk_length,
}).unwrap();
}
on_event.send(DownloadEvent::Finished { download_id }).unwrap();
}
```
다운로드 명령을 호출할 때는 채널을 만들고 그것을 인수로 지정해야 합니다.
```ts
import { invoke, Channel } from '@tauri-apps/api/core';
type DownloadEvent =
| {
event: 'started';
data: {
url: string;
downloadId: number;
contentLength: number;
};
}
| {
event: 'progress';
data: {
downloadId: number;
chunkLength: number;
};
}
| {
event: 'finished';
data: {
downloadId: number;
};
};
const onEvent = new Channel<DownloadEvent>();
onEvent.onmessage = (message) => {
console.log(`got download event ${message.event}`);
};
await invoke('download', {
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-schema-generator/schemas/config.schema.json',
onEvent,
});
```
## JavaScript 검증
Webview [컨텍스트](https://ko.wikipedia.org/wiki/컨텍스트)에서 JavaScript 코드를 직접 실행하려면 [`WebviewWindow#eval`] 함수를 사용할 수 있습니다.
```rust title="src-tauri/src/lib.rs"
use tauri::Manager;
tauri::Builder::default()
.setup(|app| {
let webview = app.get_webview_window("main").unwrap();
webview.eval("console.log('hello from Rust')")?;
Ok(())
})
```
검증되는 스크립트가 그렇게 단순하지 않고 Rust 객체로부터의 입력을 사용해야 하는 경우, [serialize-to-javascript] 크레이트의 사용을 권장합니다.
[`WebviewWindow#eval`]: https://docs.rs/tauri/2.0.0/tauri/webview/struct.WebviewWindow.html#method.eval
[serialize-to-javascript]: https://docs.rs/serialize-to-javascript/latest/serialize_to_javascript/
[AppHandle]: https://docs.rs/tauri/2.0.0/tauri/struct.AppHandle.html
[WebviewWindow]: https://docs.rs/tauri/2.0.0/tauri/webview/struct.WebviewWindow.html
[Listener]: https://docs.rs/tauri/2.0.0/tauri/trait.Listener.html
[Emitter]: https://docs.rs/tauri/2.0.0/tauri/trait.Emitter.html
[Emitter#emit]: https://docs.rs/tauri/2.0.0/tauri/trait.Emitter.html#tymethod.emit
[Emitter#emit_to]: https://docs.rs/tauri/2.0.0/tauri/trait.Emitter.html#tymethod.emit_to
[Emitter#emit_filter]: https://docs.rs/tauri/2.0.0/tauri/trait.Emitter.html#tymethod.emit_filter
[Clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html
[Serialize]: https://serde.rs/impl-serialize.html
[프론트엔드에서 Rust 호출하기]: /ko/develop/calling-rust/
[보안 수준]: /ko/security/capabilities/

View File

@@ -0,0 +1,701 @@
---
title: 프론트엔드에서 Rust 호출하기
sidebar:
order: 1
i18nReady: true
---
import { Content as FrontendListen } from './_sections/frontend-listen.mdx';
이 문서는 애플리케이션의 프론트엔드에서 Rust 코드와 통신하는 방법에 대한 지침을 담고 있습니다.
Rust 코드에서 프론트엔드와 통신하는 방법에 대해서는 이전 절의 [Rust에서 프론트엔드 호출하기]를 참조하십시오.
Tauri는 더 동적인 [이벤트 시스템](#이벤트-시스템)과 함께 형식 안전성을 갖춘 Rust 함수에 액세스하기 위한 [명령](#명령) 프리미티브를 제공합니다.
## 명령
Tauri는 웹 앱에서 Rust 함수를 호출하기 위한 간단하면서도 강력한 "명령 `command`" 시스템을 제공합니다.
"명령"은 인수를 받아들이고 값을 반환할 수 있습니다. 또한 오류를 반환하거나 `async`(비동기)로 만들 수도 있습니다.
### 기본 예제
명령은 `src-tauri/src/lib.rs` 파일에서 정의할 수 있습니다.
명령을 만들려면 함수를 추가하고 `#[tauri::command]`로 주석을 달기만 하면 됩니다:
```rust title="src-tauri/src/lib.rs"
#[tauri::command]
fn my_custom_command() {
println!("I was invoked from JavaScript!");
}
```
:::note
명령 이름은 고유해야 합니다.
:::
:::note
`lib.rs` 파일에 정의된 명령은 "[글루 코드](https://ko.wikipedia.org/wiki/글루_코드) 생성"에 대한 제약 때문에 `pub`(공개)으로 지정할 수 없습니다.
"공개 함수"로 지정하면 다음과 같은 오류가 표시됩니다:
````
error[E0255]: the name `__cmd__command_name` is defined multiple times 《`__cmd__command_name`이라는 이름이 여러 번 정의되었습니다》
--> src/lib.rs:28:8
|
27 | #[tauri::command]
| ----------------- previous definition of the macro `__cmd__command_name` here 《매크로 `__cmd__command_name`의 이전 정의는 여기》
28 | pub fn x() {}
| ^ `__cmd__command_name` reimported here 《`__cmd__command_name`은 여기에 다시 가져옵니다》
|
= note: `__cmd__command_name` must be defined only once in the macro namespace of this module 《참고: `__cmd__command_name`은 이 모듈의 매크로 네임스페이스에 한 번만 정의해야 합니다》
```
:::
명령 목록은 다음과 같이 "빌더" 함수에 제공해야 합니다.
```rust title="src-tauri/src/lib.rs" ins={4}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_custom_command])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
````
이제 JavaScript 코드에서 명령을 호출할 수 있습니다.
```javascript
// Tauri API의 npm 패키지를 사용하는 경우:
import { invoke } from '@tauri-apps/api/core';
// Tauri global script를 사용하는 경우(npm 패키지를 사용하지 않을 때)
// `tauri.conf.json`의 `app.withGlobalTauri`를 반드시 true로 설정하십시오.
const invoke = window.__TAURI__.core.invoke;
// 명령을 호출합니다
invoke('my_custom_command');
```
#### 다른 모듈에 명령 정의하기
애플리케이션에서 많은 구성 요소를 정의하거나 구성 요소를 그룹화할 수 있는 경우, `lib.rs` 파일에 명령 정의를 채워 넣는 대신 다른 모듈에 명령을 정의할 수 있습니다.
예를 들어, `src-tauri/src/commands.rs` 파일에 명령을 정의해 보겠습니다.
```rust title="src-tauri/src/commands.rs"
#[tauri::command]
pub fn my_custom_command() {
println!("I was invoked from JavaScript!");
}
```
:::note
다른 모듈에 명령을 정의하는 경우 해당 명령을 `pub`으로 지정해야 합니다.
:::
:::note
명령 이름은 해당 명령이 정의된 모듈에 국한되지 않으므로 모듈 간에도 고유해야 합니다.
:::
`lib.rs` 파일에서는 모듈을 정의하고 그에 따른 명령 목록을 제공합니다:
```rust title="src-tauri/src/lib.rs" ins={6}
mod commands;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![commands::my_custom_command])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
명령 목록의 "접두사 `commands::`"에 유의하십시오. 이는 이 명령 함수에 대한 전체 경로를 의미합니다.
이 예의 명령 이름은 `my_custom_command`이므로 프론트엔드 내에서 `invoke("my_custom_command")`를 실행하여 호출할 수 있으며, 접두사 `commands::`는 무시됩니다.
#### WASM(웹 어셈블리)
Rust 프론트엔드를 사용하여 인수 없이 `invoke()`를 호출하는 경우, 프론트엔드 코드를 다음과 같이 변경해야 합니다.
그 이유는 Rust가 선택적 인수를 지원하지 않기 때문입니다.
```rust ins={4-5}
#[wasm_bindgen]
extern "C" {
// 인수 없이 호출
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)]
async fn invoke_without_args(cmd: &str) -> JsValue;
// 인수가 있는 호출(기본값)
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
// 이 둘은 다른 이름이어야 합니다!
}
```
### 인수 전달
명령 핸들러는 인수를 받을 수 있습니다:
```rust
#[tauri::command]
fn my_custom_command(invoke_message: String) {
println!("I was invoked from JavaScript, with this message: {}", invoke_message);
}
```
인수는 camelCase 키를 가진 JSON 객체로 전달해야 합니다.
> > > 《번역 주》 영어 복합어 표기법에 대하여:
> > > ・**camelCase** "[카멜 케이스](https://ko.wikipedia.org/wiki/카멜_표기법)" 연결된 단어의 첫 글자를 대문자로 쓰는 표기법
> > > ・**snake_case** "[스네이크 케이스](https://ko.wikipedia.org/wiki/스네이크_케이스)" 연결할 단어 사이에 밑줄(\_)을 넣고 모두 소문자로 쓰는 표기법
```javascript
invoke('my_custom_command', { invokeMessage: 'Hello!' });
```
:::note
`rename_all` 속성을 가진 인수에는 `snake_case`를 사용할 수 있습니다:
```rust
#[tauri::command(rename_all = "snake_case")]
fn my_custom_command(invoke_message: String) {}
```
```javascript
invoke('my_custom_command', { invoke_message: 'Hello!' });
```
:::
인수는 [`serde::Deserialize`]를 구현하는 한 어떤 형식이든 가능합니다.
해당 JavaScript:
```javascript
invoke('my_custom_command', { invoke_message: 'Hello!' });
```
### 데이터 반환
명령 핸들러도 데이터를 반환합니다:
```rust
#[tauri::command]
fn my_custom_command() -> String {
"Hello from Rust!".into()
}
```
`invoke` 함수("호출" 함수)는 반환 값에 따라 처리 내용이 결정되는 "프로미스"를 반환합니다:
```javascript
invoke('my_custom_command').then((message) => console.log(message));
```
반환되는 데이터는 [`serde::Serialize`]를 구현하는 한 어떤 형식이든 상관없습니다.
#### 배열 버퍼 반환
[`serde::Serialize`]를 구현하는 반환 값은 응답이 프론트엔드로 전송될 때 JSON 형식으로 직렬화됩니다.
이 방법에서는 파일이나 다운로드 HTTP 응답과 같은 큰 데이터를 반환하려고 하면 애플리케이션 속도가 저하될 수 있습니다.
배열 버퍼를 최적화된 방법으로 반환하려면 [`tauri::ipc::Response`]를 사용합니다.
> > > 《번역 주》 **직렬화** serialize: 여러 병렬 데이터를 "직렬화"(한 줄로 나열하는 작업)하여 파일 저장이나 네트워크 송수신이 가능하도록 변환하는 처리.
```rust
use tauri::ipc::Response;
#[tauri::command]
fn read_file() -> Response {
let data = std::fs::read("/path/to/file").unwrap();
tauri::ipc::Response::new(data)
}
```
### 오류 처리
핸들러가 처리에 실패하여 오류를 반환해야 하는 경우, 명령 함수에 `Result`를 반환하게 합니다.
```rust
#[tauri::command]
fn login(user: String, password: String) -> Result<String, String> {
if user == "tauri" && password == "tauri" {
// 처리 성공
Ok("logged_in".to_string())
} else {
// 처리 실패
Err("invalid credentials".to_string())
}
}
```
명령이 오류를 반환하는 경우, "프로미스"는 "처리 실패", 그렇지 않은 경우에는 "처리 성공"이 됩니다:
```javascript
invoke('login', { user: 'tauri', password: '0j4rijw8=' })
.then((message) => console.log(message))
.catch((error) => console.error(error));
```
위에서 언급했듯이, 오류를 포함하여 명령에서 반환되는 모든 것은 [`serde::Serialize`]를 구현해야 합니다.
그러나 Rust 표준 라이브러리 또는 외부 크레이트의 오류 유형을 사용하는 경우, 대부분의 오류 유형은 [`serde::Serialize`]를 구현하지 않으므로 문제가 발생할 수 있습니다.
이 문제를 해결하는 간단한 시나리오는 `map_err`를 사용하여 이러한 오류를 `String`으로 변환하는 것입니다.
```rust
#[tauri::command]
fn my_custom_command() -> Result<(), String> {
std::fs::File::open("path/to/file").map_err(|err| err.to_string())?;
// 성공하면 `null`을 반환합니다
Ok(())
}
```
이 해결책은 그다지 일반적이지 않으므로 `serde::Serialize`를 구현하는 고유한 오류 유형을 만드는 것이 좋습니다.
다음 예에서는 [`thiserror`] 크레이트를 사용하여 오류 유형을 만듭니다.
이를 통해 `thiserror::Error` 트레이트를 파생시켜 열거형(enum)을 오류 유형으로 변환할 수 있습니다.
자세한 내용은 [관련 문서(영어)](https://serde.rs/)를 참조하십시오.
```rust
// 프로그램에서 발생할 수 있는 모든 오류를 나타내는 오류 유형을 만듭니다
#[derive(Debug, thiserror::Error)]
enum Error {
#[error(transparent)]
Io(#[from] std::io::Error)
}
// "serde::Serialize"를 수동으로 구현해야 합니다
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
fn my_custom_command() -> Result<(), Error> {
// 이제 오류가 반환됩니다
std::fs::File::open("path/that/does/not/exist")?;
// 성공하면 `null`을 반환합니다
Ok(())
}
```
사용자 지정 오류 유형은 발생할 수 있는 모든 오류를 명시적으로 나타내는 이점이 있어 어떤 오류가 발생할 수 있는지 즉시 식별할 수 있습니다.
이를 통해 나중에 코드를 검토하거나 리팩토링할 때 다른 사람(및 자신)의 시간을 크게 절약할 수 있습니다.<br/>
또한 오류 유형이 직렬화되는 방식을 완전히 관리할 수도 있습니다.
위의 예에서는 오류 메시지를 문자열로만 반환했지만, 각 오류에 코드를 할당하여 매우 유사한 모양의 "TypeScript 오류 열거형"에 쉽게 매핑할 수 있습니다. 예를 들어:
```rust
#[derive(Debug, thiserror::Error)]
enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("failed to parse as string: {0}")]
Utf8(#[from] std::str::Utf8Error),
}
#[derive(serde::Serialize)]
#[serde(tag = "kind", content = "message")]
#[serde(rename_all = "camelCase")]
enum ErrorKind {
Io(String),
Utf8(String),
}
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let error_message = self.to_string();
let error_kind = match self {
Self::Io(_) => ErrorKind::Io(error_message),
Self::Utf8(_) => ErrorKind::Utf8(error_message),
};
error_kind.serialize(serializer)
}
}
#[tauri::command]
fn read() -> Result<Vec<u8>, Error> {
let data = std::fs::read("/path/to/file")?;
Ok(data)
}
```
프론트엔드에서는 이제 `{ kind: 'io' | 'utf8', message: string }` 오류 객체가 표시됩니다:
```ts
type ErrorKind = {
kind: 'io' | 'utf8';
message: string;
};
invoke('read').catch((e: ErrorKind) => {});
```
### 비동기 명령
Tauri에서는 UI가 멈추거나 속도가 느려지는 것을 방지하기 위해 부하가 큰 작업을 실행할 때 "비동기 명령"을 사용하는 것이 좋습니다.
:::note
비동기 명령에서는 [`async_runtime::spawn`]을 사용하여 다른 비동기 작업에서 실행됩니다.
키워드 "_async_"가 없는 명령은 *#[tauri::command(async)]*로 정의되지 않는 한 메인 스레드에서 실행됩니다.
:::
**명령을 비동기적으로 실행해야 하는 경우, 해당 명령을 `async`로 선언하기만 하면 됩니다.**
:::caution
Tauri를 사용하여 비동기 함수를 만들 때는 주의가 필요합니다.
현재 "빌린 인수"(상속된 인수)를 비동기 함수의 [시그니처](https://ko.wikipedia.org/wiki/타입_시그니처)에 그대로 포함할 수 없습니다.
이러한 유형의 일반적인 예로는 `&str` 및 `State<'_, Data>` 등이 있습니다.
이 제약은 https://github.com/tauri-apps/tauri/issues/2533 (영어)에서 논의되고 있으며, 해결 방법은 아래에 나와 있습니다.
:::
"빌린 형식"을 사용하는 경우 추가 변경을 해야 합니다. 주요 옵션은 다음 두 가지입니다:
**옵션 1**: `&str`과 같은 형식을 `String`과 같은 빌리지 않은 유사한 형식으로 변환합니다.
이 방법은 `State<'_, Data>`와 같은 모든 형식에서 작동하지 않을 수 있습니다.
_예:_
```rust
// "&str" 대신 "String"을 사용하여 비동기 함수를 선언합니다("&str"은 빌려왔기 때문에 지원되지 않습니다)
#[tauri::command]
async fn my_custom_command(value: String) -> String {
// 다른 비동기 함수를 호출하고 그 처리가 완료될 때까지 기다립니다
some_async_function().await;
value
}
```
**옵션 2**: 반환 값 형식을 [`Result`]로 래핑합니다. 이 방법은 구현이 조금 더 어렵지만 모든 형식에서 작동합니다.
반환 값 형식 `Result<a, b>`를 사용하고, `a`를 "반환하려는 형식"으로 바꿉니다. `null`을 반환하려면 `()`로 바꿉니다. 또한 `b`를 문제가 발생했을 때 반환할 "오류 형식"으로 바꿉니다. 선택적 오류를 반환하지 않으려면 `()`로 바꿉니다. 예를 들어:
- `Result<String, ()>` "String 형식"을 반환하고 오류는 반환하지 않습니다.
- `Result<(), ()>` "`null`"을 반환합니다.
- `Result<bool, Error>` 위의 [오류 처리](#오류-처리) 항목에서처럼 "부울 값" 또는 "오류"를 반환합니다.
_예:_
```rust
// 형식 빌림 문제를 피하기 위해 "Result<String, ()>"를 반환합니다
#[tauri::command]
async fn my_custom_command(value: &str) -> Result<String, ()> {
// 다른 비동기 함수를 호출하고 그 처리가 완료될 때까지 기다립니다
some_async_function().await;
// 반환 값은 "`Ok()`"로 래핑해야 한다는 점에 유의하십시오
Ok(format!(value))
}
```
##### JavaScript에서 호출하기
JavaScript에서의 명령 호출은 "프로미스"를 반환하므로 다른 명령과 동일하게 작동합니다:
```javascript
invoke('my_custom_command', { value: 'Hello, Async!' }).then(() =>
console.log('Completed!')
);
```
### 채널
"Tauri 채널"은 프론트엔드로의 스트리밍 HTTP 응답과 같은 스트리밍 데이터에 대한 권장 메커니즘입니다.
다음 예에서는 파일을 읽고 프론트엔드에 4096바이트 청크(데이터 분할 단위)로 진행 상황을 알립니다:
```rust
use tokio::io::AsyncReadExt;
#[tauri::command]
async fn load_image(path: std::path::PathBuf, reader: tauri::ipc::Channel<&[u8]>) {
// 설명 간결화를 위해 이 예에서는 오류 처리가 포함되어 있지 않습니다
let mut file = tokio::fs::File::open(path).await.unwrap();
let mut chunk = vec![0; 4096];
loop {
let len = file.read(&mut chunk).await.unwrap();
if len == 0 {
// "길이=0"은 "파일의 끝"을 의미합니다
break;
}
reader.send(&chunk).unwrap();
}
}
```
자세한 내용은 "Rust에서 프론트엔드 호출하기"의 [채널] 설명을 참조하십시오.
### 명령에서 WebviewWindow에 액세스하기
명령은 메시지를 호출한 `WebviewWindow`의 인스턴스에 액세스할 수 있습니다:
```rust title="src-tauri/src/lib.rs"
#[tauri::command]
async fn my_custom_command(webview_window: tauri::WebviewWindow) {
println!("WebviewWindow: {}", webview_window.label());
}
```
### 명령에서 AppHandle에 액세스하기
명령은 `AppHandle`의 인스턴스에 액세스할 수 있습니다:
```rust title="src-tauri/src/lib.rs"
#[tauri::command]
async fn my_custom_command(app_handle: tauri::AppHandle) {
let app_dir = app_handle.path_resolver().app_dir();
use tauri::GlobalShortcutManager;
app_handle.global_shortcut_manager().register("CTRL + U", move || {});
}
```
### Managed State(관리 상태)에 액세스하기
Tauri는 `tauri::Builder`의 `manage` 함수를 사용하여 "상태 state"를 관리할 수 있습니다.
"상태 state"에는 `tauri::State`를 사용한 명령으로 액세스할 수 있습니다:
```rust title="src-tauri/src/lib.rs"
struct MyState(String);
#[tauri::command]
fn my_custom_command(state: tauri::State<MyState>) {
assert_eq!(state.0 == "some state value", true);
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.manage(MyState("some state value".into()))
.invoke_handler(tauri::generate_handler![my_custom_command])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
### Raw Request에 액세스하기
Tauri 명령에서는 바디 페이로드(헤더 부분을 제외한 본문 부분)의 원시 데이터와 요청 헤더를 포함하는 [`tauri::ipc::Request`] 객체 전체에도 액세스할 수 있습니다.
```rust
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("unexpected request body")]
RequestBodyMustBeRaw,
#[error("missing `{0}` header")]
MissingHeader(&'static str),
}
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
fn upload(request: tauri::ipc::Request) -> Result<(), Error> {
let tauri::ipc::InvokeBody::Raw(upload_data) = request.body() else {
return Err(Error::RequestBodyMustBeRaw);
};
let Some(authorization_header) = request.headers().get("Authorization") else {
return Err(Error::MissingHeader("Authorization"));
};
// 업로드 중 ...
Ok(())
}
```
프론트엔드에서는 페이로드 인수에 ArrayBuffer 또는 Uint8Array를 지정하여 Raw Request 본문을 보내는 "invoke()"를 호출할 수 있습니다. 세 번째 인수에 요청 헤더를 포함할 수도 있습니다:
```js
const data = new Uint8Array([1, 2, 3]);
await __TAURI__.core.invoke('upload', data, {
headers: {
Authorization: 'apikey',
},
});
```
### 여러 명령 만들기
"`tauri::generate_handler!` 매크로"는 명령 배열을 받습니다. 여러 명령을 등록하는 경우 invoke_handler를 여러 번 호출할 수 없습니다. 마지막 호출만 사용됩니다. 각 명령을 하나씩 `tauri::generate_handler!` 호출에 전달해야 합니다.
```rust title="src-tauri/src/lib.rs"
#[tauri::command]
fn cmd_a() -> String {
"Command a"
}
#[tauri::command]
fn cmd_b() -> String {
"Command b"
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![cmd_a, cmd_b])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
### 결합된 프로그램 예
위의 기능 중 일부 또는 전부를 결합할 수 있습니다:
```rust title="src-tauri/src/lib.rs"
struct Database;
#[derive(serde::Serialize)]
struct CustomResponse {
message: String,
other_val: usize,
}
async fn some_other_function() -> Option<String> {
Some("response".into())
}
#[tauri::command]
async fn my_custom_command(
window: tauri::Window,
number: usize,
database: tauri::State<'_, Database>,
) -> Result<CustomResponse, String> {
println!("Called from {}", window.label());
let result: Option<String> = some_other_function().await;
if let Some(message) = result {
Ok(CustomResponse {
message,
other_val: 42 + number,
})
} else {
Err("No result".into())
}
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.manage(Database {})
.invoke_handler(tauri::generate_handler![my_custom_command])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
```javascript
import { invoke } from '@tauri-apps/api/core';
// Invocation from JavaScript
invoke('my_custom_command', {
number: 42,
})
.then((res) =>
console.log(`Message: ${res.message}, Other Val: ${res.other_val}`)
)
.catch((e) => console.error(e));
```
## 이벤트 시스템
"이벤트 시스템"은 프론트엔드와 Rust 간의 더 간결한 통신 메커니즘입니다.
명령과 달리 이벤트는 형식 안전하지 않으며, 항상 비동기적이며, 값을 반환할 수 없고, JSON 페이로드만 지원합니다.
### 전역 이벤트
전역 이벤트를 트리거하려면 [event.emit] 또는 [WebviewWindow#emit] 함수를 사용할 수 있습니다:
```js
import { emit } from '@tauri-apps/api/event';
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
// emit(eventName, payload)
emit('file-selected', '/path/to/file');
const appWebview = getCurrentWebviewWindow();
appWebview.emit('route-changed', { url: window.location.href });
```
:::note
전역 이벤트는 **모든** 리스너에게 전달됩니다.
:::
### Webview 이벤트
개별 Webview에 의해 등록된 리스너에 대해 이벤트를 트리거하려면 [event.emitTo] 또는 [WebviewWindow#emitTo] 함수를 사용할 수 있습니다:
```js
import { emitTo } from '@tauri-apps/api/event';
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
// emitTo(webviewLabel, eventName, payload)
emitTo('settings', 'settings-update-requested', {
key: 'notification',
value: 'all',
});
const appWebview = getCurrentWebviewWindow();
appWebview.emitTo('editor', 'file-changed', {
path: '/path/to/file',
contents: 'file contents',
});
```
:::note
Webview 특정 이벤트는 일반적인 전역 이벤트 리스너에 대해서는 **트리거되지 않습니다**.
**모든** 이벤트를 감지(수신)하려면 [event.listen] 함수에 `{ target: { kind: 'Any' } }` 옵션을 지정해야 합니다. 이는 리스너가 발행된 이벤트를 모두 포착하는 "캐치올"로 기능하도록 정의하는 것입니다.
```js
import { listen } from '@tauri-apps/api/event';
listen(
'state-changed',
(event) => {
console.log('got state changed event', event);
},
{
target: { kind: 'Any' },
}
);
```
:::
### 이벤트 감지
<FrontendListen />
Rust 코드에서 이벤트를 감지(수신)하거나 이벤트를 발행하는 방법에 대해서는 이전 장 "Rust에서 프론트엔드 호출하기"의 [이벤트 시스템 설명]을 참조하십시오.
[Rust에서 프론트엔드 호출하기]: /ko/develop/calling-frontend/
[`async_runtime::spawn`]: https://docs.rs/tauri/2.0.0/tauri/async_runtime/fn.spawn.html
[`serde::serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
[`serde::deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html
[`tauri::ipc::Response`]: https://docs.rs/tauri/2.0.0/tauri/ipc/struct.Response.html
[`tauri::ipc::Request`]: https://docs.rs/tauri/2.0.0/tauri/ipc/struct.Request.html
[`thiserror`]: https://github.com/dtolnay/thiserror
[`result`]: https://doc.rust-lang.org/std/result/index.html
[event.emit]: /reference/javascript/api/namespaceevent/#emit
[event.listen]: /reference/javascript/api/namespaceevent/#listen
[WebviewWindow#emit]: /reference/javascript/api/namespacewebviewwindow/#emit
[event.emitTo]: /reference/javascript/api/namespaceevent/#emitto
[WebviewWindow#emitTo]: /reference/javascript/api/namespacewebviewwindow/#emitto
[이벤트 시스템 설명]: /ko/develop/calling-frontend/#이벤트-시스템
[채널]: /ko/develop/calling-frontend/#채널-channels
[프론트엔드에서 Rust 호출하기]: /ko/develop/calling-rust/

View File

@@ -0,0 +1,286 @@
---
title: 설정 파일
sidebar:
order: 1
i18nReady: true
---
import CommandTabs from '@components/CommandTabs.astro';
Tauri는 애플리케이션을 구축하기 위한 툴킷이므로 프로젝트 설정을 구성하기 위한 파일이 많을 수 있습니다. 흔히 볼 수 있는 일반적인 파일은 `tauri.conf.json`, `package.json`, `Cargo.toml` 등일 것입니다. 이 장에서는 어떤 파일을 수정해야 하는지 올바르게 판단할 수 있도록 각각에 대해 간단히 설명합니다.
> > > 《번역 주》 **설정**과 **구성** 둘 다 configuration의 번역어. 본고에서는 엄격한 구별 없이 사용하고 있으므로, 번역문에 위화감이 있는 경우 적절히 읽어주십시오.
## Tauri 설정
"Tauri 설정"은 웹 앱 소스 정의, 애플리케이션 메타데이터 설명, 번들 설정, 플러그인 구성 설정 및 창, 트레이 아이콘, 메뉴 등의 설정으로 런타임 동작 변경에 사용됩니다.
이 파일은 "Tauri 런타임"과 "Tauri CLI"에서 사용됩니다. "빌드 설정"을 정의하거나([`tauri build`][before-build-command]나 [`tauri dev`][before-dev-command]가 시작되기 전에 실행되는 명령 등), 앱의 [이름](/reference/config/#productname)이나 [버전](/reference/config/#version)을 설정하거나, [Tauri 런타임 제어][appconfig], [플러그인 설정] 등을 할 수 있습니다.
:::tip
모든 옵션에 대해서는 [Reference의 Configuration](참고 정보/설정) 항목을 참조하십시오.
:::
### 지원되는 형식
기본 Tauri 설정 형식은 "JSON"입니다. "JSON5" 또는 "TOML" 형식도 `Cargo.toml`의 `tauri` 및 `tauri-build` 종속성에 `config-json5` 또는 `config-toml` 기능 플래그를 각각 추가하여 활성화할 수 있습니다.
```toml title=Cargo.toml
[build-dependencies]
tauri-build = { version = "2.0.0", features = [ "config-json5" ] }
[dependencies]
tauri = { version = "2.0.0", features = [ "config-json5" ] }
```
체계와 값은 모든 형식에서 동일하지만, 서식 설정은 각 파일의 형식과 일치해야 합니다:
```json5 title=tauri.conf.json or tauri.conf.json5
{
build: {
devUrl: 'http://localhost:3000',
// start the dev server
beforeDevCommand: 'npm run dev',
},
bundle: {
active: true,
icon: ['icons/app.png'],
},
app: {
windows: [
{
title: 'MyApp',
},
],
},
plugins: {
updater: {
pubkey: 'updater pub key',
endpoints: ['https://my.app.updater/{{target}}/{{current_version}}'],
},
},
}
```
```toml title=Tauri.toml
[build]
dev-url = "http://localhost:3000"
# start the dev server
before-dev-command = "npm run dev"
[bundle]
active = true
icon = ["icons/app.png"]
[[app.windows]]
title = "MyApp"
[plugins.updater]
pubkey = "updater pub key"
endpoints = ["https://my.app.updater/{{target}}/{{current_version}}"]
```
JSON5와 TOML은 주석을 지원하며, TOML에서는 더 관용적인 "케밥 케이스"를 설정 이름에 사용할 수 있다는 점에 유의하십시오.
> > > 《번역 주》 **케밥 케이스** 원문 kebab-case. 복합어를 만들 때 소문자 단어 사이에 하이픈(-)을 넣어 만드는 명명 규칙. 글자를 꼬치에 꽂은 모양으로 보이기 때문에 "케밥 케이스"라고 불립니다.
### 플랫폼별 설정
기본 설정 파일 외에 Tauri는 다음 위치에서 플랫폼별 설정을 읽을 수 있습니다:
- Linux용: `tauri.linux.conf.json` 또는 `Tauri.linux.toml`
- Windows용: `tauri.windows.conf.json` 또는 `Tauri.windows.toml`
- macOS용: `tauri.macos.conf.json` 또는 `Tauri.macos.toml`
- Android용: `tauri.android.conf.json` 또는 `Tauri.android.toml`
- iOS용: `tauri.ios.conf.json` 또는 `Tauri.ios.toml`
플랫폼별 설정 파일은 [JSON Merge Patch (RFC 7396)] 사양에 따라 기본 설정 객체와 통합(병합)됩니다.
예를 들어, 다음과 같은 기본 `tauri.conf.json`이 있다고 가정합니다:
```json title=tauri.conf.json
{
"productName": "MyApp",
"bundle": {
"resources": ["./resources"]
},
"plugins": {
"deep-link": {}
}
}
```
또한 지정된 플랫폼별 `tauri.linux.conf.json`:
```json title=tauri.linux.conf.json
{
"productName": "my-app",
"bundle": {
"resources": ["./linux-assets"]
},
"plugins": {
"cli": {
"description": "My app",
"subcommands": {
"update": {}
}
},
"deep-link": {}
}
}
```
Linux용 최종 구성은 다음 객체와 같습니다:
> > > 《번역 주》 **최종 구성** 원문은 resolved configuration. 직역 "해결된 설정/구성". "최종적으로 결정된" 의미로 해석하여 번역했습니다. 다음 항목 "설정 확장"에서의 표현도 마찬가지입니다.
```json
{
"productName": "my-app",
"bundle": {
"resources": ["./linux-assets"]
},
"plugins": {
"cli": {
"description": "My app",
"subcommands": {
"update": {}
}
},
"deep-link": {}
}
}
```
또한 CLI(명령줄 인터페이스)를 통해 병합할 설정을 수행할 수도 있습니다. 자세한 내용은 다음 항목을 참조하십시오.
### 설정 확장
Tauri CLI를 사용하면 `dev`, `android dev`, `ios dev`, `build`, `android build`, `ios build` 또는 `bundle` 명령 중 하나를 실행할 때 Tauri 설정을 확장할 수 있습니다.
확장 설정은 JSON 문자열을 그대로 또는 JSON 파일 경로로 `--config` 인수로 제공할 수 있습니다.
Tauri는 [JSON Merge Patch (RFC 7396)] 사양을 사용하여 제공된 설정 값을 원래의 최종 구성 객체와 병합합니다.
이 메커니즘을 사용하면 애플리케이션의 여러 버전을 정의하거나 애플리케이션 번들을 구성할 때 유연성을 높일 수 있습니다.
예를 들어, 정식 버전과 완전히 분리된 _베타 버전_ 애플리케이션을 배포하려면 이 기능을 사용하여 다른 애플리케이션 이름과 식별자를 설정할 수 있습니다:
```json title=src-tauri/tauri.beta.conf.json
{
"productName": "My App Beta",
"identifier": "com.myorg.myappbeta"
}
```
이 분리된 _베타 버전_ 앱을 배포하려면 빌드 시 다음 설정 파일을 만듭니다:
<CommandTabs
npm="npm run tauri build -- --config src-tauri/tauri.beta.conf.json"
yarn="yarn tauri build --config src-tauri/tauri.beta.conf.json"
pnpm="pnpm tauri build --config src-tauri/tauri.beta.conf.json"
deno="deno task tauri build --config src-tauri/tauri.beta.conf.json"
bun="bun tauri build --config src-tauri/tauri.beta.conf.json"
cargo="cargo tauri build --config src-tauri/tauri.beta.conf.json"
/>
## `Cargo.toml`
Cargo의 매니페스트 파일은 앱이 의존하는 Rust 크레이트, 앱에 대한 메타데이터 및 기타 Rust 관련 기능을 선언하는 데 사용됩니다. Rust를 사용하여 앱의 백엔드 개발을 할 생각이 없다면 이 파일을 많이 변경하지 않을 수 있지만, 이러한 파일이 있고 그것이 무엇을 하는지 아는 것이 중요합니다.
다음은 Tauri 프로젝트의 최소한의 `Cargo.toml` 파일 예입니다:
```toml title=Cargo.toml
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
default-run = "app"
edition = "2021"
rust-version = "1.57"
[build-dependencies]
tauri-build = { version = "2.0.0" }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "2.0.0", features = [ ] }
```
주의해야 할 가장 중요한 부분은 `tauri-build`와 `tauri`의 종속성입니다. 일반적으로 이 둘은 모두 Tauri CLI와 마찬가지로 최신 "최신 버그 수정판(마이너 버전)"이어야 하지만, 이는 엄격하게 필수는 아닙니다. 앱 실행 중에 문제가 발생하면 모든 Tauri 버전(`tauri` 및 `tauri-cli`)이 각각의 "최신 버그 수정판"(마이너 릴리스의 최신 버전)인지 확인해야 합니다.
Cargo의 버전 번호는 [시맨틱 버전 관리](Semver) 방식([참고](https://ko.wikipedia.org/wiki/유의적_버전))을 사용합니다. `src-tauri` 폴더 내에서 `cargo update`를 실행하면 모든 종속성에 대해 Semver 호환 최신 버전이 가져옵니다. 예를 들어, `tauri-build`의 버전으로 `2.0.0`을 지정하면 Cargo는 최신 Semver 호환 버전인 `2.0.0.0`을 감지하고 다운로드합니다. Tauri는 중대한 변경이 도입될 때 "메이저 버전 번호"를 업데이트합니다. 즉, 최신 마이너 버전과 패치 버전 업데이트에서는 자신의 코드가 [최신 기능으로] 손상될 걱정 없이 항상 안전하게 업그레이드할 수 있습니다.
특정 크레이트 버전을 사용하려면 종속성 버전 번호 앞에 `=`를 추가하여 지정한 버전을 사용할 수 있습니다:
```
tauri-build = { version = "=2.0.0" }
```
또한 `tauri` 종속성의 `features=[]` 부분에 주의해야 합니다. `tauri dev`와 `tauri build`를 실행하면 "Tauri 설정"에 따라 프로젝트에서 어떤 기능을 활성화해야 하는지 자동으로 판단합니다. `tauri` 기능 플래그에 대한 자세한 내용은 [이 문서(영어)][tauri Cargo features]를 참조하십시오.
애플리케이션을 빌드하면 `Cargo.lock` 파일이 생성됩니다. 이 파일은 주로 개발 중 머신 간에 동일한 종속성이 사용되도록 하는 데 사용됩니다(Node.js의 `yarn.lock`, `pnpm-lock.yaml` 또는 `package-lock.json`과 유사합니다). 일관된 빌드를 얻기 위해 이 파일을 소스 리포지토리에 커밋하는 것이 좋습니다.
Cargo 매니페스트 파일에 대한 자세한 내용은 [공식 문서(영어)][cargo-manifest]를 참조하십시오.
## `package.json`
이것은 Node.js에서 사용되는 패키지 파일입니다. Tauri 앱의 프론트엔드가 Node.js 기반 기술(`npm`, `yarn`, `pnpm` 등)을 사용하여 개발된 경우 이 파일은 프론트엔드 종속성과 스크립트를 구성하는 데 사용됩니다.
Tauri 프로젝트의 최소한의 `package.json` 파일은 다음 예와 같습니다:
```json title=package.json
{
"scripts": {
"dev": "command to start your app development mode",
"build": "command to build your app frontend",
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "^2.0.0.0",
"@tauri-apps/cli": "^2.0.0.0"
}
}
```
Tauri 애플리케이션에서 사용되는 프론트엔드의 시작 및 빌드에 사용되는 명령을 저장하는 데는 `"scripts"` 섹션을 사용하는 것이 일반적입니다.
위의 `package.json` 파일에서는 "`dev` 명령"과 "`build` 명령"을 지정하고 있습니다. "`dev` 명령"은 프론트엔드 프레임워크를 시작하기 위해 `yarn dev` 또는 `npm run dev`를 사용하여 실행되며, "`build` 명령"은 프로덕션 환경에서 Tauri에 의해 추가되는 프론트엔드 웹 자산을 빌드하기 위해 `yarn build` 또는 `npm run build`를 사용하여 실행됩니다.
이러한 스크립트를 사용하는 가장 편리한 방법은 "[Tauri 설정](#tauri-설정)"의 [beforeDevCommand][before-dev-command] 및 [beforeBuildCommand][before-build-command] 후크를 통해 Tauri CLI에서 해당 스크립트를 후크하는 것입니다:
> > > 《번역 주》 **후크** 원문 hooks. 프로그램의 특정 지점(후크)에 사용자가 고유한 처리를 추가(후크)할 수 있도록 하는 메커니즘([Wikipedia](https://ko.wikipedia.org/wiki/후킹))
```json title=tauri.conf.json
{
"build": {
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn build"
}
}
```
:::note
"스크립트" 섹션 내의 `"tauri"` 지정은 `npm`을 사용하는 경우에만 필요합니다.
:::
종속성 객체는 `yarn`, `pnpm install` 또는 `npm install` 중 하나를 실행할 때(이 경우 Tauri CLI 및 API에서) Node.js가 어떤 종속성을 다운로드할지 지정합니다.
`package.json` 파일 외에 `yarn.lock`, `pnpm-lock.yaml` 또는 `package-lock.json` 파일이 표시될 수 있습니다. 이러한 파일은 나중에 종속성을 다운로드할 때 개발 중에 사용한 것과 정확히 동일한 버전을 확실히 얻는 데 도움이 됩니다(Rust의 `Cargo.lock`과 유사합니다).
"`package.json` 파일 형식"에 대한 자세한 내용은 [공식 문서][npm-package](영어)를 참조하십시오.
[reference의 configuration]: /reference/config/
[before-dev-command]: /reference/config/#beforedevcommand-1
[before-build-command]: /reference/config/#beforebuildcommand
[appconfig]: /reference/config/#appconfig
[configure plugins]: /reference/config/#plugins
[시맨틱 버전 관리]: https://semver.org
[cargo-manifest]: https://doc.rust-lang.org/cargo/reference/manifest.html
[npm-package]: https://docs.npmjs.com/cli/v8/configuring-npm/package-json
[tauri Cargo features]: https://docs.rs/tauri/2.0.0/tauri/#cargo-features
[JSON Merge Patch (RFC 7396)]: https://datatracker.ietf.org/doc/html/rfc7396
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 29, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,136 @@
---
title: 앱 아이콘
sidebar:
order: 1
---
{/* TODO: More platform specific explanations like macOS requiring padding in the icon (waiting for https://github.com/tauri-apps/tauri/pull/11037) */}
import CommandTabs from '@components/CommandTabs.astro';
import TranslationNote from '@components/i18n/TranslationNote.astro';
Tauri는 Tauri 로고를 기반으로 한 기본 아이콘 세트가 포함되어 공개되지만, 자신의 애플리케이션을 출시할 때는 그렇게 하고 싶지 않을 수 있습니다. 이 기본 처리를 피하기 위해 Tauri는 받은 입력 파일(기본적으로 `"./app-icon.png"`)에서 다양한 플랫폼에 필요한 모든 아이콘을 만드는 "`icon` 명령"을 제공합니다.
:::note[아이콘 파일 유형에 대한 참고]
- `icon.icns` = macOS용
- `icon.ico` = Windows용
- `*.png` = Linux용
- `Square*Logo.png` & `StoreLogo.png` = 현재 미사용, "AppX/MS Store"용
일부 아이콘 유형은 위에서 가정한 플랫폼 이외에도 사용될 수 있습니다(특히 `png`). 따라서 특정 플랫폼만 대상으로 빌드하는 경우에도 모든 아이콘 유형을 포함하는 것이 좋습니다.
:::
<TranslationNote lang="ko">
**AppX** Windows 애플리케이션 설치에 필요한 모든 파일(메타데이터, 파일, 자격 증명 포함)을 포함한 애플리케이션 배포 및 설치에 사용되는 배포 가능한 패키지 파일 형식. [[참고](https://docs.fileformat.com/ko/programming/appx/)]
</TranslationNote>
## 명령 사용법
<CommandTabs
npm="npm run tauri icon"
yarn="yarn tauri icon"
pnpm="pnpm tauri icon"
cargo="cargo tauri icon"
deno="deno task tauri icon"
/>
```console
> pnpm tauri icon --help
Generate various icons for all major platforms
[주요 플랫폼용 다양한 아이콘 생성]
Usage: pnpm run tauri icon [OPTIONS] [INPUT]
[사용법: pnpm run tauri icon [OPTION 지정] [인수 INPUT]]
Arguments:[인수]
[INPUT] Path to the source icon (squared PNG or SVG file with transparency) [default: ./app-icon.png]
[소스 아이콘 경로(투명 배경의 정사각형 PNG 또는 SVG 파일) [기본 경로 설정: ./app-icon.png]]
Options:[옵션 지정]
-o, --output <OUTPUT> Output directory. Default: 'icons' directory next to the tauri.conf.json file
[-o, 출력 대상] 출력 디렉토리. 기본값: tauri.conf.json 파일 옆의 'icons' 디렉토리]
-v, --verbose... Enables verbose logging
[-v, 상세 보고서 표시] 상세 로깅 활성화]
-p,
--png <PNG> Custom PNG icon sizes to generate. When set, the default icons are not generated
[-p, --png, PNG] 생성할 PNG 아이콘 크기를 사용자 정의합니다. 설정하면 기본 아이콘이 생성되지 않습니다.]
--ios-color <IOS_COLOR> The background color of the iOS icon - string as defined in the W3C's CSS Color Module Level 4 <https://www.w3.org/TR/css-color-4/> [default: #fff]
[-p, --ios, IOS_COLOR] iOS 아이콘의 배경색. W3C의 CSS 색상 모듈 레벨 4에 정의된 문자열. 기본값: #fff(흰색)]
-h, --help Print help
[-h, 도움말] 도움말 인쇄]
-V, --version Print version
[-V, 버전] 버전 인쇄]
```
"**데스크톱** 아이콘"은 모두 기본적으로 `src-tauri/icons` 폴더에 배치되며, 빌드된 앱에 자동으로 포함됩니다. 아이콘을 다른 위치에서 가져오려면 `tauri.conf.json` 파일의 다음 부분을 편집하십시오:
```json
{
"bundle": {
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
```
"**모바일** 아이콘"은 Xcode 및 Android Studio 프로젝트 내에 직접 배치됩니다.
## 아이콘 직접 만들기
아이콘을 직접 만들고 싶다면, 예를 들어 작은 크기용으로 간단한 디자인을 원하거나 CLI의 내부 이미지 크기 조정에 의존하고 싶지 않은 경우, 직접 만든 아이콘이 몇 가지 요구 사항을 충족해야 한다는 점에 유의하십시오:
- `icon.icns`: [`icns`] 파일(Apple Icon Image format)에 필요한 레이어의 "크기와 이름"은 [Tauri 리포지토리](영어 사이트)에 기재되어 있습니다.
- `icon.ico`: [`ico`] 파일(ICO file format)에는 16, 24, 32, 48, 64, 256 픽셀의 각 레이어가 포함되어 있어야 합니다. _개발 중인_ ICO 이미지를 최적으로 표시하려면 32 픽셀 레이어를 첫 번째 레이어로 해야 합니다.
- `png`: PNG 아이콘의 요구 사항은 "너비 == 높이", "RGBA"(RGB + 투명도), "픽셀당 32비트"(각 채널당 8비트)입니다. 데스크톱용으로 일반적으로 요구되는 크기는 32, 128, 256, 512 픽셀입니다. 최소한 `tauri icon`의 출력 크기인 "`32x32.png`", "`128x128.png`", "`128x128@2x.png`", "`icon.png`"를 준비해 두는 것이 좋습니다.
### Android용
Android용으로도 위와 동일한 요구 사항을 충족하는 PNG 아이콘(단, 크기가 다른 것)이 필요합니다. 아이콘은 Android Studio 프로젝트 안에 직접 배치해야 합니다:
- `src-tauri/gen/android/app/src/main/res/`
- `mipmap-hdpi/`
- `ic_launcher.png` & `ic_launcher_round.png`: 49x49px
- `ic_launcher_foreground.png`: 162x162px
- `mipmap-mdpi/`
- `ic_launcher.png` & `ic_launcher_round.png`: 48x48px
- `ic_launcher_foreground.png`: 108x108px
- `mipmap-xhdpi/`
- `ic_launcher.png` & `ic_launcher_round.png`: 96x96px
- `ic_launcher_foreground.png`: 216x216px
- `mipmap-xxhdpi/`
- `ic_launcher.png` & `ic_launcher_round.png`: 144x144px
- `ic_launcher_foreground.png`: 324x324px
- `mipmap-xxxhdpi/`
- `ic_launcher.png` & `ic_launcher_round.png`: 192x192px
- `ic_launcher_foreground.png`: 432x432px
`tauri icon`을 사용할 수 없는 경우, 대신 Android Studio의 [Image Asset Studio]를 확인하는 것이 좋습니다.
### iOS용
iOS용으로도 위 요구 사항을 충족하는 PNG 아이콘이 필요하지만, **투명도 없이** 크기도 다릅니다. 또한 Xcode 프로젝트 내의 `src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/`에 직접 배치해야 합니다. 다음 아이콘이 필요합니다:
- 20px의 1x, 2x, 3x 버전과 2x 버전의 추가 아이콘
- 29px의 1x, 2x, 3x 버전과 2x 버전의 추가 아이콘
- 40px의 1x, 2x, 3x 버전과 2x 버전의 추가 아이콘
- 60px의 2x, 3x 버전
- 76px의 1x, 2x 버전
- 83.5px의 2x 버전
- 512px의 2x 버전을 `AppIcon-512@2x.png`로 저장
파일 이름은 `AppIcon-{size}x{size}@{scaling}{extra}.png` 형식이 됩니다. 20px 아이콘의 경우, 20x20, 40x40, 60x60 크기의 아이콘을 각각 `AppIcon-20x20@1x.png`, `AppIcon-20x20@2x.png`, `AppIcon-20x20@3x.png`라는 이름으로 저장하고, `2x` 버전을 추가로 `AppIcon-20x20@2x-1.png`("추가 아이콘")로 저장해야 합니다.
[Tauri 리포지토리]: https://github.com/tauri-apps/tauri/blob/1.x/tooling/cli/src/helpers/icns.json
[`icns`]: https://en.wikipedia.org/wiki/Apple_Icon_Image_format
[`ico`]: https://ko.wikipedia.org/wiki/ICO_(파일_포맷)
[image asset studio]: https://developer.android.com/studio/write/create-app-icons?hl=ko

View File

@@ -0,0 +1,249 @@
---
title: 개발
description: Tauri를 이용한 프로그램 개발의 중심 개념
sidebar:
order: 0
label: 개요
i18nReady: true
---
import CommandTabs from '@components/CommandTabs.astro';
[Tauri란?](/ko/start/) 장에서 모든 설정을 마쳤다면, Tauri를 사용하여 애플리케이션을 실행할 준비가 된 것입니다.
"UI 프레임워크" 또는 "JavaScript 번들러"를 사용하는 경우, 개발 프로세스를 신속하게 하는 개발 서버에 연결할 수 있을 가능성이 있습니다. 따라서 앱의 "개발 URL"과 그것을 시작하는 "스크립트"를 설정하지 않았다면, "Reference(참고 정보)" 장에 있는 [devUrl](/ko/reference/config/#devurl) 및 [beforeDevCommand](/ko/reference/config/#beforedevcommand) 설정 값을 사용하여 설정할 수 있습니다:
```json title=tauri.conf.json
{
"build": {
"devUrl": "http://localhost:3000",
"beforeDevCommand": "npm run dev"
}
}
```
:::note
어떤 프레임워크든 고유한 개발 도구가 있습니다. 그러한 도구 전체를 다루거나 그 정보를 최신 상태로 유지하는 것은 이 가이드의 목적이 아닙니다.
자신이 선택한 프레임워크의 관련 문서를 참조하여 그 내용을 학습하고 올바른 설정 값을 확정하십시오.
:::
"UI 프레임워크"도 "모듈 번들러"도 사용하지 않는 경우, Tauri에서 "프론트엔드 소스 코드"를 로드하면 Tauri CLI에 의해 개발 서버가 시작됩니다:
```json title=tauri.conf.json
{
"build": {
"frontendDist": "./src"
}
}
```
위의 예에서는 `src` 폴더에 프론트엔드에서 로드된 다른 애셋과 함께 `index.html` 파일이 포함되어 있어야 한다는 점에 유의하십시오.
:::caution[기본 개발 서버 보안]
내장 Tauri 개발 서버는 "상호 인증"이나 "암호화"를 지원하지 않습니다. 따라서 신뢰할 수 없는 네트워크에서의 개발에는 사용하지 마십시오.
자세한 내용은 [개발 서버의 보안 관련 고려 사항](/ko/security/lifecycle/#개발-서버)을 참조하십시오.
> > > 《번역 주》 **기본 개발 서버** 원문은 "plain/vanilla Dev Server". 옵션이나 사용자 정의를 전혀 포함하지 않은 완전히 기본 상태의 서버.
:::
### 데스크톱 애플리케이션 개발
데스크톱용 애플리케이션을 개발하려면 `tauri dev` 명령을 실행합니다.
<CommandTabs
npm="npm run tauri dev"
yarn="yarn tauri dev"
pnpm="pnpm tauri dev"
deno="deno task tauri dev"
bun="bun tauri dev"
cargo="cargo tauri dev"
/>
처음 이 명령을 실행하는 경우, Rust 패키지 관리자가 필요한 모든 패키지를 다운로드하고 빌드하는 데 **몇 분**이 걸릴 수 있습니다.
이러한 데이터는 캐시되어 있으며, 코드는 재빌드만 필요하므로 이후 빌드는 훨씬 빨라집니다.
Rust 빌드가 완료되면 Webview가 열리고 웹 앱이 표시됩니다.
웹 앱을 변경할 수 있으며, 도구가 지원하는 경우 브라우저처럼 Webview도 자동으로 업데이트됩니다.
#### "웹 인스펙터" 열기
Webview를 마우스 오른쪽 버튼으로 클릭하고 "검사(Inspect)"를 클릭하거나, Windows 및 Linux에서는 단축키 `Ctrl + Shift + I`, macOS에서는 단축키 `Cmd + Option + I`를 사용하여 "웹 인스펙터"를 열어 애플리케이션을 디버깅할 수 있습니다.
### 모바일 애플리케이션 개발
모바일 개발은 데스크톱 버전 개발과 유사하지만, 플랫폼에 따라 `tauri android dev` 또는 `tauri ios dev`를 실행해야 합니다:
<CommandTabs
npm="npm run tauri [android|ios] dev"
yarn="yarn tauri [android|ios] dev"
pnpm="pnpm tauri [android|ios] dev"
deno="deno task tauri [android|ios] dev"
bun="bun tauri [android|ios] dev"
cargo="cargo tauri [android|ios] dev"
/>
처음 이 명령을 실행하는 경우, Rust 패키지 관리자가 필요한 모든 패키지를 다운로드하고 빌드하는 데 **몇 분**이 걸릴 수 있습니다.
이러한 데이터는 캐시되어 있으며, 코드는 재빌드만 필요하므로 이후 빌드는 훨씬 빨라집니다.
#### 개발 서버
모바일용 개발 서버도 데스크톱용과 유사하게 작동하지만, iOS 물리적 장치에서 실행하는 경우 `TAURI_DEV_HOST` 환경 변수로 정의되고 Tauri CLI에서 제공하는 특정 주소에 응답(수신)하도록 설정해야 합니다.
이 주소는 "공용 네트워크 주소"(기본 동작) 또는 iOS 물리적 장치의 "TUN 주소" 중 하나입니다. 후자는 더 안전하지만 현재로서는 장치에 연결하려면 Xcode가 필요합니다.
iOS 장치 주소를 사용하려면 dev 명령을 실행하기 전에 Xcode를 열고 "창(Window)" > "장치 및 시뮬레이터(Devices and Simulation)" 메뉴에서 장치가 네트워크를 통해 연결되어 있는지 확인해야 합니다.
그런 다음 `tauri ios dev --force-ip-prompt`를 실행하여 iOS 장치 주소(**::2**로 끝나는 IPv6 주소)를 선택해야 합니다.
개발 서버가 iOS 장치에서 액세스할 수 있는 올바른 호스트에서 응답(수신)하도록 하려면 `TAURI_DEV_HOST` 값이 제공된 경우 이를 사용하도록 설정을 미세 조정해야 합니다. 다음은 Vite 설정 예입니다:
```js
import { defineConfig } from 'vite';
const host = process.env.TAURI_DEV_HOST;
// https://vitejs.dev/config/
export default defineConfig({
clearScreen: false,
server: {
host: host || false,
port: 1420,
strictPort: true,
hmr: host
? {
protocol: 'ws',
host,
port: 1421,
}
: undefined,
},
});
```
자세한 내용은 각 프레임워크의 "설정 가이드"를 확인하십시오.
:::note
[create-tauri-app](https://github.com/tauri-apps/create-tauri-app)을 사용하여 만든 프로젝트는 추가 설정 없이 바로 사용할 수 있는 모바일 개발용 개발 서버가 설정됩니다.
:::
#### 장치 선택
기본적으로 "모바일 dev 명령"은 연결된 장치에서 애플리케이션을 실행하려고 시도하고 사용할 시뮬레이터를 선택하라는 메시지를 표시합니다. 실행 대상을 미리 정의하려면 "장치 이름" 또는 "시뮬레이터 이름"을 인수로 지정합니다:
<CommandTabs
npm="npm run tauri ios dev 'iPhone 15'"
yarn="yarn tauri ios dev 'iPhone 15'"
pnpm="pnpm tauri ios dev 'iPhone 15'"
deno="deno task tauri ios dev 'iPhone 15'"
bun="bun tauri ios dev 'iPhone 15'"
cargo="cargo tauri ios dev 'iPhone 15'"
/>
#### Xcode 또는 Android Studio 사용
또는 Xcode 또는 Android Studio를 사용하여 애플리케이션을 개발할 수도 있습니다.
이를 통해 명령줄 도구 대신 IDE를 사용하여 개발 문제를 해결할 수 있습니다.
연결된 장치 또는 시뮬레이터에서 실행하는 대신 모바일 IDE를 열려면 `--open` 플래그를 사용하십시오:
<CommandTabs
npm="npm run tauri [android|ios] dev --open"
yarn="yarn tauri [android|ios] dev --open"
pnpm="pnpm tauri [android|ios] dev --open"
deno="deno task tauri [android|ios] dev --open"
bun="bun tauri [android|ios] dev --open"
cargo="cargo tauri [android|ios] dev --open"
/>
:::note
애플리케이션을 iOS 물리적 장치에서 실행하는 경우 `--host` 인수도 지정해야 하며, 개발 서버 측에서는 호스트로 `process.env.TAURI_DEV_HOST` 값을 사용해야 합니다.
자세한 내용은 각 프레임워크의 "설정 가이드"를 확인하십시오.
<CommandTabs
npm="npm run tauri [android|ios] dev --open --host"
yarn="yarn tauri [android|ios] dev --open --host"
pnpm="pnpm tauri [android|ios] dev --open --host"
deno="deno task tauri [android|ios] dev --open --host"
bun="bun tauri [android|ios] dev --open --host"
cargo="cargo tauri [android|ios] dev --open --host"
/>
:::
:::caution[(경고)]
Xcode 또는 Android Studio를 사용하려면 Tauri CLI 프로세스가 실행 중이어야 하며, 강제 종료할 수 없습니다.
`tauri [android|ios] dev --open` 명령을 사용하여 IDE를 닫을 때까지 해당 프로세스를 실행 상태로 두십시오.
:::
#### "웹 인스펙터" 열기
- iOS
iOS 애플리케이션의 "웹 인스펙터"에 액세스하려면 Safari를 사용해야 합니다.
Mac 컴퓨터에서 Safari를 열고 메뉴 막대에서 **Safari > 설정(Setting)**을 선택하고 **고급(Advanced)**을 클릭한 다음 **웹 개발자용 기능 표시(Show features for web developers)**를 선택합니다.
물리적 장치에서 실행하는 경우 **설정(Settings) > Safari > 고급(Advanced)**에서 **웹 인스펙터(Web Inspector)**를 활성화해야 합니다.
모든 절차를 수행하면 Safari에 **개발(Develop)** 메뉴가 표시되고, 거기에 검증해야 할 연결된 장치와 애플리케이션이 있습니다.
장치 또는 시뮬레이터를 선택하고 **localhost(로컬 호스트)**를 클릭하여 "Safari 개발 도구" 창을 엽니다.
- Android
"인스펙터"는 Android 에뮬레이터에서는 기본적으로 활성화되어 있지만 물리적 장치에서는 활성화해야 합니다.
Android 장치를 컴퓨터에 연결하고 Android 장치에서 **설정(Settings)** 앱을 열고 **정보(About)**를 선택한 다음 "빌드 번호"까지 스크롤하여 일곱 번 탭합니다.
이렇게 하면 Android 장치의 "개발자 모드"와 **개발자 옵션(Developer Options)** 설정이 활성화됩니다.
장치에서 애플리케이션 디버깅을 활성화하려면 **개발자 옵션(Developer Options)** 설정에 들어가 개발자 옵션 스위치를 켜고 **USB 디버깅(USB Debugging)**을 활성화해야 합니다.
:::note
각 Android 배포판에는 "개발자 모드"를 활성화하는 고유한 방법이 있습니다. 자세한 내용은 각 제조업체의 설명서를 확인하십시오.
:::
Android용 "웹 인스펙터"는 Google Chrome의 DevTools를 이용하며, Chrome 브라우저에서 `chrome://inspect`를 검색하면 액세스할 수 있습니다.
Android 애플리케이션이 실행 중인 경우 장치 또는 에뮬레이터가 "원격 장치 목록"에 표시되어야 하며, 장치에서 **검사(inspect)**를 클릭하면 "개발자 도구"를 열 수 있습니다.
#### 문제 해결
1. Xcode에서의 빌드 스크립트 실행 오류
Tauri는 Tauri CLI를 실행하는 빌드 단계를 생성하여 iOS Xcode 프로젝트에 연결(후크)하지만, 이는 실행 시 로드되는 라이브러리로 Rust 소스를 컴파일하기 위한 것입니다.
빌드 단계는 "Xcode 프로세스 컨텍스트"에서 실행되므로 PATH 추가와 같은 셸 수정을 수행하지 못할 수 있습니다. 이 때문에 "Node.js 버전 관리자"와 같은 도구를 사용하는 경우 호환성 문제가 있을 수 있으므로 주의하십시오.
2. iOS 앱 첫 실행 시 네트워크 허용 요청 프롬프트
처음 `tauri ios dev`를 실행하면 로컬 네트워크의 장치를 검색하고 연결할 수 있는 권한을 요청하는 iOS 메시지가 표시될 수 있습니다.
iOS 장치에서 개발 서버에 액세스하려면 개발 서버를 로컬 네트워크에 공개해야 하므로 이 권한이 필요합니다.
장치에서 앱을 실행하려면 "허용(Allow)"을 클릭하고 애플리케이션을 다시 시작해야 합니다.
### 소스 코드 변경에 대한 대응
Webview가 실시간으로 변경 내용을 반영하는 것과 마찬가지로 Tauri도 Rust 파일의 변경을 감시하고 있으며, 파일을 변경하면 애플리케이션이 자동으로 재빌드되고 재시작됩니다.
이 동작은 `tauri dev` 명령에 `--no-watch` 플래그를 사용하여 비활성화할 수 있습니다.
변경이 감시되는 파일을 제한하려면 "src-tauri" 폴더에 `.taurignore` 파일을 만듭니다. 이 파일은 일반적인 ".gitignore 파일"과 동일하게 작동하므로 임의의 폴더나 파일을 무시할 수 있습니다:
```filename=.taurignore
build/
src/generated/*.rs
deny.toml
```
### "브라우저 개발 도구" 사용
Tauri의 API는 앱 창에서만 작동하므로 일단 Tauri API 사용을 시작하면 시스템 브라우저에서 프론트엔드를 열 수 없게 됩니다.
브라우저 개발자 도구를 사용하려면 Tauri API 호출을 HTTP 서버를 통해 브리지하도록 [tauri-invoke-http](https://github.com/tauri-apps/tauri-invoke-http)를 설정하십시오.
### 소스 관리
"결정론적 빌드"를 제공하기 위해 Cargo가 잠금 파일을 사용하므로 프로젝트 리포지토리에서 `src-tauri/Cargo.lock`과 `src-tauri/Cargo.toml`을 git에 **커밋해야 합니다**.
따라서 모든 애플리케이션에서 `Cargo.lock`을 체크인(등록)하는 것이 좋습니다. `src-tauri/target` 폴더 또는 그 안의 파일은 **커밋하지 마십시오**.
> > > 《번역 주》 **결정론적 빌드** 원문은 "deterministic builds". determinstic이란 "알고리즘에 결정성이 있어 다음 단계가 항상 (확정적으로) 하나로 정해지는 것", 즉, "동일한 소스 코드를 사용하여 컴파일했을 때 확실히 동일한 바이너리 데이터를 재현하는 빌드 기법"을 말합니다(자세한 내용은 Wikipedia [재현 가능한 빌드](https://ko.wikipedia.org/wiki/재현_가능한_빌드)를 참조하십시오).
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 29, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,165 @@
---
title: 추가 파일 포함
sidebar:
order: 1
i18nReady: true
---
프론트엔드(`frontendDist`)에 직접 포함되지 않은 파일이나 바이너리에 인라인(포함)하기에는 너무 큰 파일 등을 추가로 애플리케이션 번들에 포함해야 할 수 있습니다. 이러한 파일을 "`resources`"(리소스)라고 합니다.
선택한 파일을 번들링하려면 `tauri.conf.json` 파일 내의 `bundle` 객체에 `resources` 속성을 추가합니다.
`tauri.conf.json` 설정에 대한 자세한 내용은 [여기(영어)][tauri.bundle]를 참조하십시오.
`resources` 속성에는 파일 또는 디렉토리를 절대 경로 또는 상대 경로로 지정한 대상 파일이나 디렉토리 문자열 목록이 필요합니다. 디렉토리 내의 파일을 여러 개 한 번에 지정해야 하는 경우 "글로브 패턴"을 사용할 수 있습니다.
> > > 《번역 주》 **글로브 패턴** 원문은 glob patterns. "와일드카드 문자"를 사용하여 파일명/폴더명 패턴을 지정하는 방법. 자세한 내용은 "[Wikipedia](https://ko.wikipedia.org/wiki/글로브)"를 참조하십시오.
다음 예는 설정 내용을 설명하기 위한 것입니다. 모든 내용이 포함된 완전한 `tauri.conf.json` 파일이 아니므로 주의하십시오:
```json title=tauri.conf.json
{
"bundle": {
"resources": [
"/absolute/path/to/textfile.txt",
"relative/path/to/jsonfile.json",
"resources/**/*"
]
}
}
```
또는 파일 복사 대상을 변경하려면 `resources` 설정에서 "맵 객체"를 지정할 수도 있습니다. 다음 예는 다른 소스의 파일을 동일한 `resources` 폴더로 가져오는 방법을 보여줍니다:
> > > 《번역 주》 **맵 객체** 원문 "a map object". 키와 값을 일대일로 매핑하기 위한 데이터 구조.
```json title=tauri.conf.json
{
"bundle": {
"resources": {
"/absolute/path/to/textfile.txt": "resources/textfile.txt",
"relative/path/to/jsonfile.json": "resources/jsonfile.json",
"resources/**/*": "resources/"
}
}
}
```
:::note
Tauri의 [접근 권한 메커니즘](/reference/acl/capability/)에서는 절대 경로와 상위 구성 요소(`../`)를 포함하는 경로는 `"$RESOURCE/**"`를 통해서만 허용됩니다. `"path/to/file.txt"`와 같은 상대 경로는 `"$RESOURCE/path/to/file.txt"`와 같이 명시적으로 지정하면 사용할 수 있습니다.
:::
## 소스 경로 구문
다음 설명에서 "대상 리소스 디렉토리"(대상 디렉토리)는 객체 표기법에서는 "콜론 뒤의 값" 또는 배열 표기법에서는 "원본 파일 경로를 재구성한 것" 중 하나입니다.
> > > 《번역 주》 **객체 표기법** 원문은 the object notation. 경량 텍스트 기반 데이터 교환용 형식. 자세한 내용은 Wikipedia의 "[JavaScript Object Notation (JSON)](https://ko.wikipedia.org/wiki/JSON)" 등을 참조하십시오.
> > > **배열 표기법** 원문 the array notation. 거대수 표기법?
- `"dir/file.txt"`: 이 표기법은 `file.txt` 파일을 "대상 리소스 디렉토리"에 복사합니다.
- `"dir/"`: 이 표기법은 모든 파일**과 디렉토리**를 _재귀적으로(그대로)_ "대상 리소스 디렉토리"에 복사합니다. 현재 파일과 디렉토리의 "파일 시스템 계층 구조"를 그대로 유지하는 경우에도 이를 사용할 수 있습니다.
- `"dir/*"`: 이 표기법은 `dir` 디렉토리 내의 "모든 파일"을 _비재귀적으로_(즉, 그대로가 아니라 하위 디렉토리가 무시되어) "대상 리소스 디렉토리"에 복사합니다.
- `"dir/**`: 이 표기법은 `**`가 "디렉토리에만 일치"를 의미하므로 파일을 찾을 수 없어 "오류"가 발생합니다.
- `"dir/**/*"`: 이 표기법은 `dir` 디렉토리 내의 "모든 파일"(`dir/` 내의 모든 파일과 모든 하위 디렉토리 내의 모든 파일)을 "대상 리소스 디렉토리"에 _재귀적으로_(그대로) 복사합니다.
- `"dir/**/**`: 이 표기법은 `**`가 "디렉토리에만 일치"를 의미하므로 파일을 찾을 수 없어 "오류"가 발생합니다.
## Rust 파일에 액세스
다음 예는 다음과 같은 "i18n"(국제화 지원) json 파일을 추가로 번들링하는 경우입니다:
> > > 《번역 주》 **i18n** i18n = internationalization(국제화). 다음 예에서는 "독일어 지원(언어 코드 de)"의 de.json을 추가하고, "안녕하세요(hello)"와 "안녕히 가세요(bye)"에 해당하는 독일어를 추가합니다.
```json title=de.json
{
"hello": "Guten Tag!",
"bye": "Auf Wiedersehen!"
}
```
이 경우 이러한 파일은 `tauri.conf.json` 옆의 `lang`(언어) 디렉토리에 저장됩니다.
따라서 위에서 설명한 대로 `resources`에 `"lang/*"`을 추가합니다.
Rust 측에서는 [`App`] 및 [`AppHandle`]에서 얻을 수 있는 [`PathResolver`] 인스턴스가 필요합니다:
```rust
tauri::Builder::default()
.setup(|app| {
// 지정하는 경로는 `tauri.conf.json > bundle > resources`에 정의된 것과
// 동일한 구문을 따라야 합니다.
let resource_path = app.path().resolve("lang/de.json", BaseDirectory::Resource)?;
let file = std::fs::File::open(&resource_path).unwrap();
let lang_de: serde_json::Value = serde_json::from_reader(file).unwrap();
// 다음 문장으로 "'Guten Tag!'"가 터미널에 인쇄됩니다
println!("{}", lang_de.get("hello").unwrap());
Ok(())
})
```
```rust
#[tauri::command]
fn hello(handle: tauri::AppHandle) -> String {
let resource_path = handle.path().resolve("lang/de.json", BaseDirectory::Resource)?;
let file = std::fs::File::open(&resource_path).unwrap();
let lang_de: serde_json::Value = serde_json::from_reader(file).unwrap();
lang_de.get("hello").unwrap()
}
```
## JavaScript 파일에 액세스
다음은 위의 예를 기반으로 합니다.
`$RESOURCE` 폴더에 대한 액세스 권한과 필요한 [`plugin-fs`] API를 활성화하려면 액세스 제어 목록 설정이 필요하다는 점에 유의하십시오:
```json title=src-tauri/capabilities/default.json ins={14-15}
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"fs:allow-read-text-file",
"fs:allow-resource-read-recursive"
]
}
```
:::note
이 예의 `fs:allow-resource-read-recursive`는 `$RESOURCE` 폴더, 파일 및 하위 디렉토리 전체에 대한 완전한 재귀 읽기 액세스를 허용하는 데 사용됩니다.
다른 옵션에 대해서는 [접근 권한 설정]을, 더 세분화된 제어에 대해서는 [범위(적용 범위)]를 읽어보십시오.
:::
```javascript
import { resolveResource } from '@tauri-apps/api/path';
import { readTextFile } from '@tauri-apps/plugin-fs';
const resourcePath = await resolveResource('lang/de.json');
const langDe = JSON.parse(await readTextFile(resourcePath));
console.log(langDe.hello); // This will print 'Guten Tag!' to the devtools console
```
[tauri.bundle]: /reference/config/#bundleconfig
[`pathresolver`]: https://docs.rs/tauri/latest/tauri/path/struct.PathResolver.html
[`app`]: https://docs.rs/tauri/latest/tauri/struct.App.html
[`apphandle`]: https://docs.rs/tauri/latest/tauri/struct.AppHandle.html
[`plugin-fs`]: /reference/javascript/fs/
[접근 권한 설정]: /ko/plugin/file-system/#scopes
[범위(적용 범위)]: /ko/reference/acl/scope/
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 13, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,249 @@
---
title: 외부 바이너리 포함
sidebar:
order: 1
i18nReady: true
---
애플리케이션에 기능을 추가하거나 사용자가 추가 종속성(Node.js나 Python 등)을 설치하지 못하게 하려면 외부 바이너리를 포함해야 할 수 있습니다. 이러한 바이너리를 "**사이드카** `sidecar`"라고 합니다.
바이너리는 모든 프로그래밍 언어로 작성된 실행 파일입니다. 일반적인 사용 예로는 `pyinstaller`를 사용하여 번들된 Python CLI 애플리케이션이나 API 서버 등이 있습니다.
원하는 바이너리를 번들링하려면 `tauri.conf.json`의 `tauri > bundle` 객체에 `externalBin` 속성을 추가합니다.
`externalBin` 설정에는 절대 경로 또는 상대 경로를 사용하여 대상 바이너리를 지정하는 "문자열 목록"이 필요합니다.
다음은 "사이드카" 설정을 설명하기 위한 "Tauri 설정"의 발췌(스니펫)입니다:
```json title="src-tauri/tauri.conf.json"
{
"bundle": {
"externalBin": [
"/absolute/path/to/sidecar",
"../relative/path/to/binary",
"binaries/my-sidecar"
]
}
}
```
:::note
상대 경로는 `src-tauri` 디렉토리에 있는 `tauri.conf.json` 파일을 기준으로 표기합니다.
따라서 `binaries/my-sidecar`는 `<PROJECT ROOT>/src-tauri/binaries/my-sidecar`를 나타냅니다.
:::
지원되는 모든 아키텍처에서 외부 바이너리가 작동하도록 하려면 지정된 경로에 "동일한 이름"과 "접미사 `-$TARGET_TRIPLE`"(대상 트리플)을 가진 바이너리가 있어야 합니다.
예를 들어, `"externalBin": ["binaries/my-sidecar"]`의 경우, Linux에서는 실행 파일 "`src-tauri/binaries/my-sidecar-x86_64-unknown-linux-gnu`"가, Apple Silicon을 탑재한 Mac OS에서는 실행 파일 "`src-tauri/binaries/my-sidecar-aarch64-apple-darwin`"이 필요합니다.
> > > 《번역 주》 **대상 트리플** 원문은 target triple. Rust에서 크로스 컴파일을 수행할 때 아키텍처를 지정하는 방식으로, 컴파일 대상(target)을 세 가지(triple) 항목 "CPU 제품군 이름", "제조사 이름", "OS 이름"으로 지정합니다. 위의 설명 예에서는 `aarch64-apple-darwin`과 같이 하이픈으로 연결된 표기법이 사용됩니다.
다음 명령으로 표시되는 "`host:`" 속성을 보면 **현재** 플랫폼의 "접미사 `-$TARGET_TRIPLE`"을 알 수 있습니다:
```sh
rustc -Vv
```
대부분의 Unix 시스템에 탑재된 `grep` 명령과 `cut` 명령을 사용할 수 있는 경우, 다음 명령으로 대상 트리플을 직접 추출할 수 있습니다:
```shell
rustc -Vv | grep host | cut -f2 -d' '
```
Windows에서는 shell 대신 PowerShell을 사용합니다:
```powershell
rustc -Vv | Select-String "host:" | ForEach-Object {$_.Line.split(" ")[1]}
```
다음 예는 대상 트리플을 바이너리에 추가하는 Node.js 스크립트입니다.
```javascript
import { execSync } from 'child_process';
import fs from 'fs';
const extension = process.platform === 'win32' ? '.exe' : '';
const rustInfo = execSync('rustc -vV');
const targetTriple = /host: (\S+)/g.exec(rustInfo)[1];
if (!targetTriple) {
console.error('Failed to determine platform target triple');
}
fs.renameSync(
`src-tauri/binaries/sidecar${extension}`,
`src-tauri/binaries/sidecar-${targetTriple}${extension}`
);
```
이 스크립트는 실행되는 아키텍처와 다른 아키텍처용으로 컴파일한 경우 작동하지 않으므로, 자신만의 빌드 스크립트를 만들기 위한 출발점으로 사용하십시오.
## Rust에서 실행하기
:::note
플러그인을 올바르게 설정하고 초기화하려면 먼저 [셸 플러그인 가이드](/ko/plugin/shell/)를 따르십시오.
플러그인을 초기화하고 구성하지 않으면 다음 예는 작동하지 않습니다.
:::
Rust 측에서는 `tauri_plugin_shell::ShellExt` 트레이트를 가져오고 AppHandle에서 `shell().sidecar()` 함수를 호출합니다:
> > > 《번역 주》 **트레이트** 원문은 trait(성격의 "특징", "특성", 유전적인 "형질"을 나타내는 단어). 『[Rust 한국어판](https://doc.rust-kr.org/ch10-02-traits.html)』에서는 다른 유형에 대해 공통된 동작을 정의하는 것과 같은 설명이 있습니다. "유형의 형질" = "유형질?"
```rust
use tauri_plugin_shell::ShellExt;
use tauri_plugin_shell::process::CommandEvent;
let sidecar_command = app.shell().sidecar("my-sidecar").unwrap();
let (mut rx, mut _child) = sidecar_command
.spawn()
.expect("Failed to spawn sidecar");
tauri::async_runtime::spawn(async move {
// stdout(표준 출력) 등의 이벤트를 읽습니다
while let Some(event) = rx.recv().await {
if let CommandEvent::Stdout(line_bytes) = event {
let line = String::from_utf8_lossy(&line_bytes);
window
.emit("message", Some(format!("'{}'", line)))
.expect("failed to emit event");
// stdin(표준 입력)에 씁니다
child.write("message from Rust\n".as_bytes()).unwrap();
}
}
});
```
:::note
`sidecar()` 함수에는 "파일 이름"만 필요하며, 배열 `externalBin`에 설정된 "경로" 자체는 필요하지 **않습니다**.
예를 들어, 다음과 같은 설정이 되어 있다고 가정합니다:
```json title="src-tauri/tauri.conf.json"
{
"bundle": {
"externalBin": ["binaries/app", "my-sidecar", "../scripts/sidecar"]
}
}
```
적절하게 "사이드카"를 실행하려면 `app.shell().sidecar(name)`을 호출합니다. 이때 `name`은 예를 들어 `"binaries/app"`와 같은 경로가 아니라 `"app"`, `"my-sidecar"` 또는 `"sidecar"` 중 하나가 됩니다.
:::
이 코드를 Tauri 명령 내에 배치하면 AppHandle을 쉽게 전달할 수 있으며, 빌더 스크립트 내에 AppHandle에 대한 참조를 저장하면 애플리케이션 내 어디에서나 AppHandle에 액세스할 수 있습니다.
## JavaScript에서 실행하기
"사이드카"를 실행하는 경우, Tauri에서는 자식 프로세스에서 `execute` 또는 `spawn` 메서드를 실행할 권한을 "사이드카"에 부여해야 합니다. 이 권한을 부여하려면 파일 `<PROJECT ROOT>/src-tauri/capabilities/default.json`으로 이동하여 다음 섹션을 권한 배열에 추가합니다. 앞서 "참고"란에서 설명한 "상대 경로 기술 방법"에 따라 "사이드카"를 기술하는 것을 잊지 마십시오.
```json title="src-tauri/capabilities/default.json" ins={4-12}
{
"permissions": [
"core:default",
{
"identifier": "shell:allow-execute",
"allow": [
{
"name": "binaries/app",
"sidecar": true
}
]
}
]
}
```
:::note
사이드카 자식 프로세스는 `command.execute()` 메서드를 사용하여 시작되므로 `shell:allow-execute` 식별자가 사용됩니다. 이를 `command.spawn()`으로 실행하려면 식별자를 `shell:allow-spawn`으로 변경하거나 위와 동일한 구조이지만 식별자를 `shell:allow-spawn`으로 변경한 다른 항목을 배열에 추가해야 합니다.
:::
JavaScript 코드 내에서는 `@tauri-apps/plugin-shell` 모듈에서 `Command` 클래스를 가져오고 `sidecar` 정적 메서드를 사용합니다.
```javascript
import { Command } from '@tauri-apps/plugin-shell';
const command = Command.sidecar('binaries/my-sidecar');
const output = await command.execute();
```
:::note
`Command.sidecar`로 보내는 문자열은 `externalBin` 설정 배열에 정의된 문자열 중 하나와 일치해야 합니다.
:::
## 인수 전달
일반적인 [명령][std::process::Command]을 실행하는 경우와 마찬가지로 Sidecar의 명령에 인수를 전달할 수 있습니다.
인수는 **정적 static**(예: `-o` 또는 `serve`) 또는 **동적 dynamic**(예: `<file_path>` 또는 `localhost:<PORT>`) 중 하나가 될 수 있습니다. 인수는 호출하는 순서대로 정의합니다. "정적 인수"는 그대로 정의되지만, "동적 인수"는 정규식을 사용하여 정의합니다.
먼저, `src-tauri/capabilities/default.json`에 사이드카 명령에 전달해야 하는 인수를 정의합니다:
```json title="src-tauri/capabilities/default.json" ins={8-24}
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
{
"identifier": "shell:allow-execute",
"allow": [
{
"args": [
"arg1",
"-a",
"--arg2",
{
"validator": "\\S+"
}
],
"name": "binaries/my-sidecar",
"sidecar": true
}
]
}
]
}
```
:::note
만약 Tauri v1 버전에서 마이그레이션하는 경우, Tauri v2 CLI의 `migrate` 명령으로 이 처리를 실행할 수 있습니다. 자세한 내용은 "Tauri 1.0에서 업그레이드"의 [자동 마이그레이션](/ko/start/migrate/from-tauri-1/#자동-마이그레이션) 항목을 읽어보십시오.
:::
이제 사이드카 명령을 호출하려면 **모든** 인수를 배열로 전달하기만 하면 됩니다.
Rust에서는:
```rust
use tauri_plugin_shell::ShellExt;
#[tauri::command]
async fn call_my_sidecar(app: tauri::AppHandle) {
let sidecar_command = app
.shell()
.sidecar("my-sidecar")
.unwrap()
.args(["arg1", "-a", "--arg2", "any-string-that-matches-the-validator"]);
let (mut _rx, mut _child) = sidecar_command.spawn().unwrap();
}
```
JavaScript에서는:
```javascript
import { Command } from '@tauri-apps/plugin-shell';
// 인수 배열은 `capabilities/default.json`에 지정된 것과 완전히 일치해야 합니다.
const command = Command.sidecar('binaries/my-sidecar', [
'arg1',
'-a',
'--arg2',
'any-string-that-matches-the-validator',
]);
const output = await command.execute();
```
[std::process::Command]: https://doc.rust-lang.org/std/process/struct.Command.html
<div style="text-align: right">
【※ 이 한국어판은, 「Jan 06, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,206 @@
---
title: 상태 관리
sidebar:
order: 1
i18nReady: true
---
Tauri 애플리케이션에서는 종종 애플리케이션의 현재 상태를 추적하거나 애플리케이션과 관련된 다양한 것들의 라이프사이클을 관리해야 합니다. Tauri에서는 [`Manager`] API를 사용하여 애플리케이션의 상태를 관리하고, 명령이 호출되었을 때의 상태를 읽기 위한 간단한 방법을 제공합니다.
다음은 간단한 예입니다:
```rust
use tauri::{Builder, Manager};
struct AppData {
welcome_message: &'static str,
}
fn main() {
Builder::default()
.setup(|app| {
app.manage(AppData {
welcome_message: "Welcome to Tauri!",
});
Ok(())
})
.run(tauri::generate_context!())
.unwrap();
}
```
[`Manager`] 트레이트를 구현하는 모든 유형(예: [`App`] 인스턴스)은 나중에 해당 상태에 액세스할 수 있습니다:
```rust
let data = app.state::<AppData>();
```
각 명령의 상태 액세스를 포함하여 자세한 내용은 [상태 액세스](#상태-액세스) 섹션을 참조하십시오.
## 가변성
Rust에서는 여러 스레드 간에 공유되는 값이나 소유권이 [`Arc`](또는 Tauri의 [`State`])와 같은 공유 포인터를 통해 제어되는 값을 직접 변경할 수 없습니다. 그렇게 하면 (예: 두 개의 쓰기가 동시에 발생하는 등) 데이터 경합이 발생할 수 있기 때문입니다.
이를 피하기 위해 [**내부 가변성**](https://doc.rust-kr.org/ch15-05-interior-mutability.html)이라는 개념을 사용합니다. 예를 들어, 표준 라이브러리의 [`Mutex`](뮤텍스)는 "상태를 래핑"하는 데 사용할 수 있습니다. 이를 통해 값을 변경해야 할 때 잠그고 변경이 끝나면 잠금을 해제합니다.
> > > 《번역 주》 **Mutex** "Mutex"는 "mutual exclusion"(상호 배제)의 약자로, 어떤 경우에도 하나의 스레드에만 데이터에 대한 액세스를 허용하는 메커니즘입니다. "`Mutex` 뮤텍스"에 대한 자세한 설명은 [Rust Book 16.3](https://doc.rust-kr.org/ch16-03-shared-state.html)을 참조하십시오.
```rust
use std::sync::Mutex;
use tauri::{Builder, Manager};
#[derive(Default)]
struct AppState {
counter: u32,
}
fn main() {
Builder::default()
.setup(|app| {
app.manage(Mutex::new(AppState::default()));
Ok(())
})
.run(tauri::generate_context!())
.unwrap();
}
```
"뮤텍스"를 잠그면 상태를 변경할 수 있습니다:
```rust
let state = app.state::<Mutex<AppState>>();
// 뮤텍스를 잠그고 가변 액세스를 얻습니다:
let mut state = state.lock().unwrap();
// 상태를 변경합니다:
state.counter += 1;
```
범위가 끝나거나 `MutexGuard`가 삭제되면 "뮤텍스"는 자동으로 잠금 해제되어 애플리케이션의 다른 부분이 내부 데이터에 액세스하고 해당 데이터를 변경할 수 있게 됩니다.
### 비동기 뮤텍스 사용 기회
> > > 《번역 주》 **Tokio** "Tokio"는 Rust용 비동기 런타임 라이브러리입니다.
[Tokio의 `Mutex`](https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use) 문서에서 인용하면, 다음과 같이 Tokio가 제공하는 것과 같은 비동기 뮤텍스 대신 표준 라이브러리의 [`Mutex`]를 사용해도 괜찮은 경우가 많습니다:
> 일반적으로 믿어지는 것과는 반대로, 비동기 코드에서 표준 라이브러리의 일반 Mutex를 사용해도 문제없으며, 종종 그것이 선호됩니다. ... 비동기 뮤텍스의 주요 사용 사례는 데이터베이스 연결과 같은 IO 리소스에 대한 공유 가변 액세스를 제공하는 것입니다.
이 두 `Mutex` 간의 트레이드오프(일장일단)를 이해하려면 각각의 위 링크된 문서를 충분히 읽어보는 것이 좋습니다. 비동기 뮤텍스가 필요하게 될 _수도 있는_ 이유 중 하나는 "대기 지점"을 넘어 `MutexGuard`를 유지해야 하는 경우입니다.
### `Arc`는 필요한가?
> > > 《번역 주》 **Arc** "[구조체 Arc](https://doc.rust-kr.org/rust-by-example/std/arc.html)"(Struct `Arc`). Atomically Reference Counted(원자적 참조 카운트)의 약자.
Rust에서는 여러 스레드 간에 값의 소유권을 공유하기 위해 [`Arc`]가 일반적으로 사용됩니다(보통 `Arc<Mutex<T>>` 형태로 [`Mutex`]와 함께 사용됩니다). 그러나 [`State`]에 저장된 것에 대해서는 [`Arc`]를 사용할 필요가 없습니다. 왜냐하면 Tauri가 대신 이를 실행하기 때문입니다.
`State`의 수명 요구 사항으로 인해 "상태"를 새 스레드로 이동할 수 없는 경우, 대신 `AppHandle`을 해당 새 스레드로 이동하여 아래 "[Manager 트레이트를 사용하여 상태에 액세스하기](#manager-트레이트를-사용하여-상태에-액세스하기)" 항목에서 보여주는 것처럼 "상태"를 가져올 수 있습니다. `AppHandle`은 이러한 유스케이스(사용 사례)에서 의도적으로 복제가 저렴합니다.
> > > 《번역 주》 **의도적으로 복제가 저렴** 원문 deliberately cheap to clone. (문맥 불명: `AppHandle`에서 유사한 처리를 간편하게 수행할 수 있도록 한다는 의미?)
## 상태 액세스
### 명령 내 상태 액세스
```rust
#[tauri::command]
fn increase_counter(state: State<'_, Mutex<AppState>>) -> u32 {
let mut state = state.lock().unwrap();
state.counter += 1;
state.counter
}
```
명령에 대한 자세한 내용은 "[프론트엔드에서 Rust 호출하기](/ko/develop/calling-rust/)" 장을 참조하십시오.
#### 비동기 명령
`async` 명령을 사용하고 Tokio의 비동기 [`Mutex`](https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html)를 사용하려면 다음과 같이 유사한 방법으로 설정하면 "상태"에 액세스할 수 있습니다.
```rust
#[tauri::command]
async fn increase_counter(state: State<'_, Mutex<AppState>>) -> Result<u32, ()> {
let mut state = state.lock().await;
state.counter += 1;
Ok(state.counter)
}
```
비동기 명령을 사용하는 경우 반환 유형은 [`Result`]여야 한다는 점에 유의하십시오.
### [`Manager`] 트레이트를 사용하여 상태에 액세스하기
경우에 따라 다른 스레드 내나 `on_window_event`와 같은 이벤트 핸들러 내와 같이 명령 외부에서 "상태"에 액세스해야 할 수 있습니다. 이러한 경우 [`Manager`] 트레이트를 구현하는 유형(`AppHandle` 등)의 `state()` 메서드를 사용하여 상태를 가져올 수 있습니다:
```rust
use std::sync::Mutex;
use tauri::{Builder, Window, WindowEvent, Manager};
#[derive(Default)]
struct AppState {
counter: u32,
}
// 이벤트 핸들러 내:
fn on_window_event(window: &Window, _event: &WindowEvent) {
// 전역 상태를 가져올 수 있도록 앱에 대한 핸들을 가져옵니다.
let app_handle = window.app_handle();
let state = app_handle.state::<Mutex<AppState>>();
// 뮤텍스를 잠그고 "상태"에 가변적으로 액세스합니다.
let mut state = state.lock().unwrap();
state.counter += 1;
}
fn main() {
Builder::default()
.setup(|app| {
app.manage(Mutex::new(AppState::default()));
Ok(())
})
.on_window_event(on_window_event)
.run(tauri::generate_context!())
.unwrap();
}
```
이 방법은 명령 주입(외부에서의 명령 실행)에 의존할 수 없는 경우에 유용합니다. 예를 들어, `AppHandle`을 사용하는 것이 더 간단한 스레드에 "상태"를 이동해야 하는 경우나 명령 컨텍스트 내에 존재하지 않는 경우 등입니다.
> > > 《번역 주》 **명령 주입에 의존할 수 없음** 원문은 cannot rely on command injection. (문맥 불명)
> > > 《번역 주》 **명령 컨텍스트** 원문 a command context. 명령 실행에 필요한 정보나 환경.
## 유형 불일치
:::caution
구조체 [`State`]의 매개변수에 잘못된 유형을 사용하면 "컴파일 시 오류"가 아니라 "런타임 패닉"이 발생합니다.
예를 들어, `State<'_, Mutex<AppState>>` 대신 `State<'_, AppState>`를 사용하면 해당 유형으로 관리되는 "상태"가 존재하지 않게 됩니다.
:::
필요한 경우 이 실수를 방지하기 위해 "상태"를 "[유형 별칭](https://doc.rust-kr.org/ch19-04-advanced-types.html)"으로 래핑할 수도 있습니다:
```rust
use std::sync::Mutex;
#[derive(Default)]
struct AppStateInner {
counter: u32,
}
type AppState = Mutex<AppStateInner>;
```
단, 유형 별칭은 그대로 사용하고 [`Mutex`]로 다시 래핑하지 않도록 하십시오. 그렇지 않으면 동일한 문제를 일으킬 수 있습니다.
[`Manager`]: https://docs.rs/tauri/latest/tauri/trait.Manager.html
[`State`]: https://docs.rs/tauri/latest/tauri/struct.State.html
[`Mutex`]: https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html
[`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
[`App`]: https://docs.rs/tauri/latest/tauri/struct.App.html
[`Result`]: https://doc.rust-lang.org/stable/std/result/index.html
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 28, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,62 @@
---
title: 종속성 업데이트
sidebar:
order: 1
i18nReady: true
---
{/* TODO: Add plugin update example */}
import CommandTabs from '@components/CommandTabs.astro';
## npm 패키지 업데이트
`tauri` 패키지를 사용하는 경우:
<CommandTabs
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
yarn="yarn up @tauri-apps/cli @tauri-apps/api"
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
/>
다음 명령을 사용하면 명령줄에서 Tauri의 최신 버전을 감지할 수도 있습니다.
<CommandTabs
npm="npm outdated @tauri-apps/cli"
yarn="yarn outdated @tauri-apps/cli"
pnpm="pnpm outdated @tauri-apps/cli"
/>
## Cargo 패키지 업데이트
오래된 패키지는 [`cargo outdated`] 또는 crates.io 페이지 [tauri] / [tauri-build]에서 확인할 수 있습니다.
`src-tauri/Cargo.toml` 파일로 이동하여 `tauri`와 `tauri-build`를 다음과 같이 변경합니다:
```toml
[build-dependencies]
tauri-build = "%version%"
[dependencies]
tauri = { version = "%version%" }
```
여기서 `%version%`은 [tauri-build] / [tauri]의 해당 버전 번호입니다.
그런 다음 다음 작업을 실행합니다:
```shell
cd src-tauri
cargo update
```
또는 [cargo-edit]이 제공하는 `cargo upgrade` 명령을 실행하여 이러한 모든 처리를 자동으로 실행할 수도 있습니다.
[`cargo outdated`]: https://github.com/kbknapp/cargo-outdated
[tauri]: https://crates.io/crates/tauri/versions
[tauri-build]: https://crates.io/crates/tauri-build/versions
[cargo-edit]: https://github.com/killercup/cargo-edit
<div style="text-align: right">
【※ 이 한국어판은, 「Jul 23, 2024 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,389 @@
---
title: App Store에서 배포
sidebar:
order: 1
i18nReady: true
---
import CommandTabs from '@components/CommandTabs.astro';
import TranslationNote from '@components/i18n/TranslationNote.astro';
[Apple App Store]는 Apple사가 운영하는 앱 마켓플레이스입니다.
이 App Store를 통해 macOS 및 iOS를 대상으로 한 Tauri 앱을 배포할 수 있습니다.
이 장에서는 "앱을 직접 App Store에 배포하는" 방법만 다룹니다.
macOS 배포 옵션 및 설정에 대한 자세한 내용은 종합적인 "[App Bundle][App Bundle로 배포]" 장을 참조하십시오.
## 필요 조건
iOS와 macOS 앱을 배포하려면 [Apple Developer] 프로그램에 등록해야 합니다.
또한 [macOS][macOS 코드 서명]와 [iOS][iOS 코드 서명]의 코드 서명을 설정해야 합니다.
## 앱 아이콘 변경
`tauri ios init`을 실행하여 Xcode 프로젝트를 생성한 후, `tauri icon` 명령을 사용하여 앱 아이콘을 업데이트할 수 있습니다.
<CommandTabs
npm="npm run tauri icon /path/to/app-icon.png -- --ios-color #fff"
yarn="yarn tauri icon /path/to/app-icon.png --ios-color #fff"
pnpm="pnpm tauri icon /path/to/app-icon.png --ios-color #fff"
deno="deno task tauri icon /path/to/app-icon.png --ios-color #fff"
bun="bun tauri icon /path/to/app-icon.png --ios-color #fff"
cargo="cargo tauri icon /path/to/app-icon.png --ios-color #fff"
/>
인수 `--ios-color`는 iOS 아이콘의 배경색을 정의합니다.
## 설정
Apple Developer 프로그램에 등록한 후, Tauri 앱을 App Store에서 배포하기 위한 첫 번째 단계는 앱을 [App Store Connect][app-store-connect-apps]에 등록하는 것입니다.
:::note
"_Bundle ID_" 필드에 지정된 값은 [`tauri.conf.json > identifier`]에 정의된 식별자와 일치**해야 합니다**.
:::
## 빌드 및 업로드
Tauri CLI는 앱을 macOS 및 iOS용으로 패키징할 수 있습니다. 단, macOS 컴퓨터에서 실행해야 합니다.
Tauri는 [`tauri.conf.json > version`]에 정의된 값에서 [`CFBundleVersion`](https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundleversion) (번들 버전)을 가져옵니다.
다른 번들 버전 체계, 예를 들어 "연속 부호" 등이 필요한 경우,
[`tauri.conf.json > bundle > iOS > bundleVersion`] 또는 [`tauri.conf.json > bundle > macOS > bundleVersion`] 설정에서 고유한 번들 버전을 지정할 수 있습니다:
```json title="tauri.conf.json" ins={4}
{
"bundle": {
"iOS": {
"bundleVersion": "100"
}
}
}
```
:::caution
"코드 서명"이 필요합니다. [macOS][macOS 코드 서명] 및 [iOS][iOS 코드 서명]의 "코드 서명" 관련 문서를 참조하십시오.
:::
Tauri는 iOS 앱에 Xcode를 이용하므로, iOS용 아카이브 및 배포에 Tauri CLI 대신 Xcode를 사용할 수 있다는 점에 유의하십시오.
iOS 프로젝트를 Xcode에서 열고 빌드하려면 다음 명령을 실행합니다:
<CommandTabs
npm="npm run tauri ios build -- --open"
yarn="yarn tauri ios build --open"
pnpm="pnpm tauri ios build --open"
deno="deno task tauri ios build --open"
bun="bun tauri ios build --open"
cargo="cargo tauri ios build --open"
/>
### macOS에서
앱을 App Store에 업로드하려면 먼저 모든 필요한 설정 옵션이 입력되었는지 확인해야 합니다. 그런 다음 App Bundle을 패키징하고 서명된 `.pkg` 파일을 만들어 업로드할 수 있습니다.
다음 각 항목에서 이 프로세스를 순서대로 설명합니다.
#### 설정
앱이 App Store 검증 시스템에서 수락되려면 앱에 몇 가지 설정 항목이 포함되어 있어야 합니다.
:::tip
여기서는 App Store 제출용으로 앱을 설정하는 절차에 대해 설명합니다.
다음 설정 변경을 "App Store용으로 빌드하는" 경우에만 적용하려면 다른 Tauri 설정 파일을 만듭니다.
```json title="src-tauri/tauri.appstore.conf.json
{
"bundle": {
"macOS": {
"entitlements": "./Entitlements.plist",
"files": {
"embedded.provisionprofile": "path/to/profile-name.provisionprofile"
}
}
}
}
```
그런 다음 Tauri 앱을 App Store용으로 번들링할 때 해당 설정 파일을 기본 설정 파일과 병합합니다:
<CommandTabs
npm="npm run tauri build -- --no-bundle
npm run tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
yarn="yarn tauri build --no-bundle
yarn tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
pnpm="pnpm tauri build --no-bundle
pnpm tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
deno="deno task tauri build --no-bundle
deno task tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
bun="bun tauri build --no-bundle
bun tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
cargo="cargo tauri build --no-bundle
cargo tauri bundle -- --bundles app --target universal-apple-darwin --config src-tauri/tauri.appstore.conf.json"
/>
이 방법은 다음과 같은 경우에 특히 유용합니다.
- 앱을 App Store에 업로드하기 위해 CI/CD를 설정하지만 로컬에서 "[프로비저닝 프로필]"이 필요하지 않은 경우
- App Store 이외에서 배포하기 위해 앱을 컴파일하는 경우
<TranslationNote lang="ko">
**프로비저닝 프로필** provision profile. iOS/macOS 앱 개발자가 진짜임을 나타내는 인증서. "[개발용](https://developer.apple.com/kr/help/glossary/development-provisioning-profile/)"과 "[배포용](https://developer.apple.com/kr/help/glossary/distribution-provisioning-profile/)" 두 종류가 있습니다.
</TranslationNote>
:::
- Category(카테고리 항목)
앱을 App Store에 표시하려면 [`tauri.conf.json > bundle > category`](카테고리 항목)를 명시해야 합니다:
```json title="tauri.conf.json" ins={3}
{
"bundle": {
"category": "Utility"
}
}
```
- Provisioning profile(프로비저닝 프로필)
또한 앱을 Apple에 수락받으려면 "프로비저닝 프로필"도 만들어야 합니다.
Apple Developer 사이트의 "[Identifiers](https://developer.apple.com/account/resources/identifiers/list)(ID)" 페이지에서 새로운 "[App ID]"를 만들고, "[Bundle ID]" 값이 [`tauri.conf.json > identifier`]에 설정된 ID(식별자)와 일치하는지 확인합니다.
그런 다음 [Profiles](https://developer.apple.com/account/resources/profiles/list) 페이지로 이동하여 새로운 "프로비저닝 프로필"을 만듭니다.
App Store에서 macOS 앱을 배포하는 경우 "Mac App Store Connect" 프로필이어야 합니다.
적절한 "앱 ID"를 선택하고 "코드 서명"에 사용하는 "인증서"와 연결합니다.
"프로비저닝 프로필"을 만든 후 다운로드하여 잘 아는 위치에 저장하고, "[App Bundle](앱 번들)에 포함되도록 Tauri를 설정합니다:
```json title="tauri.conf.json" ins={4-6}
{
"bundle": {
"macOS": {
"files": {
"embedded.provisionprofile": "path/to/profile-name.provisionprofile"(프로비저닝 프로필 경로 기재)
}
}
}
}
```
- Info.plist(정보 속성 목록)
<TranslationNote lang="ko">
**정보 속성 목록** Information Property List. 자세한 내용은 [Info.plist](영어)를 참조하십시오.
</TranslationNote>
앱은 "암호화 수출 규제"(가칭)를 준수해야 합니다.
자세한 내용은 [Apple사 공식 문서](https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations?language=objc)(영어)를 참조하십시오.
src-tauri 폴더에 Info.plist 파일을 만듭니다:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/> # or `true` if your app uses encryption
</dict>
</plist>
```
- Entitlements(인타이틀먼트/자격)
<TranslationNote lang="ko">
**인타이틀먼트** entitlement: "권리, 자격"을 부여하거나 부여된 "권리, 자격". 여기서는 정보나 데이터, 자원 등을 이용할 자격, 권리의 부여나 제한을 하는 것. Apple사 용어 해설은 [여기](https://developer.apple.com/kr/help/glossary/?q=인타이틀먼트).
</TranslationNote>
앱을 App Store에서 배포하려면 액세스 제어 기능인 [App Sandbox]를 포함해야 합니다.
또한 "코드 서명" 자격 설정에서 "App ID"와 "[team ID]"도 설정해야 합니다.
`src-tauri` 폴더에 `Entitlements.plist` 파일을 만듭니다:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.application-identifier</key>
<string>$TEAM_ID.$IDENTIFIER</string>
<key>com.apple.developer.team-identifier</key>
<string>$TEAM_ID</string>
</dict>
</plist>
```
`$IDENTIFIER`는 [`tauri.conf.json > identifier`]의 값으로, `$TEAM_ID`는 Apple Developer "team ID"의 값으로 바꿔야 한다는 점에 유의하십시오. "team ID"는 프로비저닝 프로필용으로 만든 [Identifier](https://developer.apple.com/account/resources/identifiers/list)의 `App ID Prefix` 섹션에 있습니다.
그리고 macOS 번들 설정 [`tauri.conf.json > bundle > macOS > entitlements`]에서 이 `Entitlements.plist` 파일을 참조합니다.
```json title="tauri.conf.json" ins={4}
{
"bundle": {
"macOS": {
"entitlements": "./Entitlements.plist"
}
}
}
```
인타이틀먼트(자격)를 적용하려면 코드 서명을 활성화하고 애플리케이션을 빌드해야 합니다.
"App Sandbox" 환경에서 앱을 실행했을 때 앱이 작동하는지 확인하십시오.
<TranslationNote lang="ko">
**App Sandbox** macOS에 구현된 보안 기능. 자세한 내용은 [Apple사 사이트](https://developer.apple.com/kr/help/glossary/app-sandbox/)를 참조하십시오.
</TranslationNote>
#### 빌드
macOS 애플리케이션은 `.pkg` 파일로 App Store에 업로드해야 합니다.
다음 명령을 실행하여 앱을 macOS App Bundle(확장자는 `.app`)로 패키징합니다:
```
tauri build --bundles app --target universal-apple-darwin
```
:::note
위의 명령은 유니버설 앱 바이너리 애플리케이션을 생성하여 "Apple 실리콘"과 "Intel 프로세서"를 모두 지원합니다.
만약 "Apple 실리콘"만 지원하고 싶다면, [`tauri.conf.json > bundle > macOS > minimumSystemVersion`]을 `12.0`으로 변경해야 합니다:
```json title="tauri.conf.json" ins={4}
{
"bundle": {
"macOS": {
"minimumSystemVersion": "12.0"
}
}
}
```
그리고 사용하는 Mac 시스템에 따라 CLI 명령과 출력 경로를 변경합니다:
- 빌드에 사용하는 시스템이 "Apple 실리콘"을 사용하는 경우, 인수 "`--target universal-apple-darwin`"을 삭제하고, 다음 `.pkg` 생성 명령에서 참조되는 경로에서 "`target/universal-apple-darwin/release`" 대신 "`target/release`"를 사용합니다.
- 빌드에 사용하는 시스템이 "Intel 칩"을 사용하는 경우:
- Rust Apple 실리콘 타겟을 설치합니다:
```
rustup target add aarch64-apple-darwin
```
- 인수 "`universal-apple-darwin`"을 "`aarch64-apple-darwin`"으로 변경하고, 다음 `.pkg` 생성 명령에서 참조되는 경로에서 "`target/universal-apple-darwin/release`" 대신 "`target/aarch64-apple-darwin/release`"를 사용합니다.
:::
설정 옵션에 대한 자세한 내용은 [App Bundle로 배포] 장을 참조하십시오.
App Bundle에서 서명된 `.pkg`를 생성하려면 다음 명령을 실행합니다:
```
xcrun productbuild --sign "<certificate signing identity>" --component "target/universal-apple-darwin/release/bundle/macos/$APPNAME.app" /Applications "$APPNAME.pkg"
```
【주의】 _$APPNAME_ 부분은 자신의 앱 이름으로 바꿔야 합니다.
:::note
_Mac Installer Distribution_ 서명 인증서를 사용하여 "Mac 인스톨러 패키지"에 서명해야 합니다.
:::
#### 업로드
이제 명령줄 유틸리티(CLI)인 [`altool`]을 사용하여 앱 패키지를 App Store에 업로드할 수 있습니다:
```
xcrun altool --upload-app --type macos --file "$APPNAME.pkg" --apiKey $APPLE_API_KEY_ID --apiIssuer $APPLE_API_ISSUER
```
【주의】 `altool`은 앱을 업로드하기 위해 [App Store Connect] API 키가 필요하다는 점에 유의하십시오.
자세한 내용은 아래 [인증] 항목을 참조하십시오.
그런 다음 앱은 Apple에 의해 검증되고 승인되면 [TestFlight]를 사용할 수 있게 됩니다.
<TranslationNote lang="ko">
**altool** ※ "이 공증 도구의 "인증" 기능은 2023-11-01을 기해 폐지되고 `notarytool`로 이전될 것"이라는 [Apple Technote] 2023-05-30 릴리스가 있었습니다. App store에 앱 업로드는 계속할 수 있는 것 같지만, 필요에 따라 최신 상황을 확인해 주십시오. "TN3147: Apple has deprecated `altool` for the purposes of notarization"
</TranslationNote>
### iOS에서
iOS 앱을 빌드하려면 `tauri ios build` 명령을 실행합니다.
<CommandTabs
npm="npm run tauri ios build -- --export-method app-store-connect"
yarn="yarn tauri ios build --export-method app-store-connect"
pnpm="pnpm tauri ios build --export-method app-store-connect"
deno="deno task tauri ios build --export-method app-store-connect"
bun="bun tauri ios build --export-method app-store-connect"
cargo="cargo tauri ios build --export-method app-store-connect"
/>
생성된 [IPA 파일]은 `src-tauri/gen/apple/build/arm64/$APPNAME.ipa`에 있습니다.
<TranslationNote lang="ko">
**IPA 파일** IPA file: iOS 애플리케이션의 아카이브 파일로, iOS Package Archive(확장자 .ipa)의 약자입니다.
</TranslationNote>
_$APPNAME_ 부분을 자신의 앱 이름으로 바꿔야 한다는 점에 유의하십시오.
이제 `altool` CLI를 사용하여 iOS 앱을 App Store에 업로드할 수 있습니다:
```
xcrun altool --upload-app --type ios --file "src-tauri/gen/apple/build/arm64/$APPNAME.ipa" --apiKey $APPLE_API_KEY_ID --apiIssuer $APPLE_API_ISSUER
```
`altool`은 앱을 업로드하기 위해 [App Store Connect] API 키가 필요하다는 점에 유의하십시오.
자세한 내용은 아래 [인증] 항목을 참조하십시오.
그런 다음 앱은 Apple에 의해 검증되고 승인되면 [TestFlight]를 사용할 수 있게 됩니다.
### 인증
iOS 및 macOS 앱은 인증에 App Store Connect API 키를 이용하는 `altool`을 사용하여 업로드됩니다.
새로운 API 키를 만들려면 [App Store Connect Users and Access page]를 열고, "Integrations(통합) > Individual Keys tab(개별 키 탭)"을 선택하고, "Add(추가)" 버튼을 클릭하여 "이름"과 "the Developer access(개발자 액세스)"를 선택합니다.
"`APPLE_API_ISSUER`"(발급자 ID)는 키 테이블 상단에 표시되고, "`APPLE_API_KEY_ID`"는 해당 테이블의 "키 ID" 열의 값이 됩니다.
"비밀 키 private key" 다운로드도 필요하지만, 이는 한 번만 실행되며 페이지를 새로고침한 후에만 표시됩니다(버튼이 새로 생성된 키에 해당하는 테이블 행에 표시됩니다).
이 비밀 키 파일의 경로는 "`AuthKey\_<APPLE_API_KEY_ID>.p8`"으로, 다음 디렉토리 중 하나에 저장해야 합니다: `<current-working-directory>/private_keys`, `~/private_keys`, `~/.private_keys` 또는 `~/.appstoreconnect/private_keys`입니다.
[App Bundle로 배포]: /ko/distribute/macos-application-bundle/
[Apple Developer]: https://developer.apple.com/kr/
[Apple App Store]: https://www.apple.com/kr/app-store/
[`altool`]: https://help.apple.com/itc/apploader/#/apdATD1E53-D1E1A1303-D1E53A1126
[macOS 코드 서명]: /ko/distribute/sign/macos/
[iOS 코드 서명]: /ko/distribute/sign/ios/
[app-store-connect-apps]: https://appstoreconnect.apple.com/apps
[`tauri.conf.json > identifier`]: /reference/config/#identifier
[`tauri.conf.json > bundle > category`]: /reference/config/#category
[`tauri.conf.json > bundle > macOS > entitlements`]: /reference/config/#entitlements
[`tauri.conf.json > bundle > macOS > minimumSystemVersion`]: /reference/config/#minimumsystemversion
[App Store Connect's Users and Access page]: https://appstoreconnect.apple.com/access/users
[인증]: #인증
[App Bundle]: https://developer.apple.com/kr/help/glossary/?q=app%20bundle
[App ID]: https://developer.apple.com/kr/help/glossary/?q=앱ID
[App Sandbox]: https://developer.apple.com/kr/help/glossary/?q=App%20Sandbox
[App Store Connect]: https://developer.apple.com/kr/help/glossary/?q=App%20Store%20Connect
[Apple Technote]: https://developer.apple.com/documentation/technotes/tn3147-migrating-to-the-latest-notarization-tool?changes=_3_3
[Bundle ID]: https://developer.apple.com/kr/help/glossary/?q=번들ID
[Info.plist]: https://developer.apple.com/documentation/bundleresources/information-property-list
[IPA 파일]: https://ko.wikipedia.org/wiki/IPA_(파일_포맷)
[team ID]: https://developer.apple.com/kr/help/glossary/?q=team
[TestFlight]: https://developer.apple.com/kr/help/glossary/?q=TestFlight
[프로비저닝 프로필]: https://developer.apple.com/kr/help/glossary/?q=프로필
<div style="text-align: right">
【※ 이 한국어판은, 「May 21, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,75 @@
---
title: AppImage로 배포
sidebar:
order: 1
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
"`AppImage`"는 시스템에 설치된 패키지에 의존하지 않고, 대신 애플리케이션에 필요한 종속성과 파일을 모두 번들로 묶은 배포 형식입니다. 이 때문에 출력 파일은 커지지만, 많은 Linux 배포판에서 지원되며 설치 없이 실행할 수 있어 배포가 용이합니다. 사용자는 파일을 실행 파일(`chmod a+x MyProject.AppImage`)로 만들기만 하면 실행할 수 있습니다(`./MyProject.AppImage`).
AppImage는 편리하며, 각 배포판의 패키지 관리자용 패키지를 만들 수 없는 경우에도 배포 프로세스를 간소화합니다. 그렇지만 파일 크기가 원래 2~6MB 정도에서 70MB 이상으로 커지므로 사용에 신중을 기해야 합니다.
## GStreamer를 통한 멀티미디어 지원
앱이 오디오/비디오 재생을 수행하는 경우, `tauri.conf.json > bundle > linux > appimage > bundleMediaFramework`("미디어 프레임워크 번들" 플래그)를 활성화해야 합니다. 이렇게 하면 미디어 재생에 필요한 gstreamer 파일이 추가되어 AppImage 번들 크기가 증가합니다. 이 플래그는 현재 Ubuntu 빌드 시스템에서만 완벽하게 지원됩니다. 앱 실행 시 필요할 수 있는 모든 플러그인이 자신의 빌드 시스템에 설치되어 있는지 확인하십시오.
:::caution
[GStreamer]의 `ugly` 패키지 내 플러그인에는 "앱의 일부로 배포하기 어려운" 라이선스가 있는 것이 있을 수 있습니다.
<TranslationNote lang="ko">
**GStramer**의 라이선스 문제: GStreamer 자체는 LGPL로 라이선스가 부여되지만, 플러그인 라이브러리 그룹 중에는 다른 라이선스로 배포되는 경우가 있을 수 있으므로 사용되는 플러그인의 라이선스에 주의하십시오. 라이선스 관련 자세한 내용은 [GStreamer website](영어 사이트)를 참조하십시오.
</TranslationNote>
:::
{/* TODO: Add some reference links for gst setup/plugins */}
## 사용자 지정 파일
Tauri의 "`resources` 기능"("[추가 파일 포함](/ko/develop/resources/)" 장 참조)을 사용하지 않고 사용자 지정 파일을 AppImage에 포함하려면, 대상 파일이나 폴더 목록을 `tauri.conf.json > bundle > linux > appimage > files`에 지정합니다. 이 설정 객체는 AppImage 내의 경로를 파일 시스템상의 파일 경로로, `tauri.conf.json` 파일로부터의 상대 경로로 확장(매핑)합니다. 다음은 설정 예시입니다:
```json title="tauri.conf.json"
{
"bundle": {
"linux": {
"appimage": {
"files": {
"/usr/share/README.md": "../README.md", // "../README.md" 파일을 "<appimage>/usr/share/README.md"에 복사
"/usr/assets": "../assets/" // "../assets" 디렉토리의 모든 것을 "<appimage>/usr/assets"에 복사
}
}
}
}
}
```
:::note
현재 대상 경로는 `/usr/`로 시작해야 한다는 점에 유의하십시오.
:::
## ARM 기반 장치용 AppImages
Tauri가 사용하는 AppImage 도구인 "`linuxdeploy`"는 현재 ARM AppImage와의 [크로스 컴파일을 지원하지 않습니다]. 즉, ARM AppImage는 ARM 장치 또는 에뮬레이터에서만 빌드할 수 있습니다.
앱을 빌드하기 위해 에뮬레이션 환경인 "QEMU"를 이용하는 워크플로 사례에 대해서는 [GitHub Action 설정 가이드](/ko/distribute/pipelines/github/#arm-runner-compilation) 장을 참조하십시오. 단, 이 처리는 매우 느리므로 Build Minutes(빌드 시간)가 무료인 공개 리포지토리에서만 권장됩니다. 비공개 리포지토리에서는 GitHub의 "ARM 러너"(위 링크)가 비용 효율적이며 설정도 훨씬 간단합니다.
<TranslationNote lang="ko">
**QEMU** 읽기 "큐에뮤". 오픈 소스 CPU/시스템 에뮬레이터. 자세한 내용은 [Wikipedia](https://ko.wikipedia.org/wiki/QEMU)를 참조하십시오.
</TranslationNote>
[크로스 컴파일을 지원하지 않습니다]: https://github.com/linuxdeploy/linuxdeploy/issues/258
[GStreamer]: https://ko.wikipedia.org/wiki/GStreamer
[GStreamer website]: https://gstreamer.freedesktop.org/documentation/frequently-asked-questions/licensing.html?gi-language=c
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,168 @@
---
title: AUR
sidebar:
order: 1
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
# Arch User Repository (AUR)에 게시하기
<TranslationNote lang="ko">
**AUR** = Arch User Repository: ArchLinux 커뮤니티가 운영하는 Arch 사용자를 위한 리포지토리의 명칭. ArchLinux Korea 사이트는 [여기](<https://wiki.archlinux.org/title/Arch_User_Repository_(한국어)>).
</TranslationNote>
## 설정
먼저 `https://aur.archlinux.org`에 접속하여 계정을 만드십시오. 반드시 적절한 "SSH 키"를 추가하십시오. 그런 다음 다음 명령을 사용하여 빈 Git 리포지토리를 복제하십시오.
```sh
git clone https://aur.archlinux.org/your-repo-name
```
위의 절차가 완료되면 `PKGBUILD`라는 이름의 파일을 만듭니다. 파일 생성이 완료되면 다음 단계로 진행합니다.
### PKGBUILD 파일 작성법
```ini title="PKGBUILD"
pkgname=<pkgname>
pkgver=1.0.0
pkgrel=1
pkgdesc="앱 설명(description)"
arch=('x86_64' 'aarch64')
url="https://github.com/<user>/<project>"
license=('MIT')
depends=('cairo' 'desktop-file-utils' 'gdk-pixbuf2' 'glib2' 'gtk3' 'hicolor-icon-theme' 'libsoup' 'pango' 'webkit2gtk-4.1')
options=('!strip' '!emptydirs')
install=${pkgname}.install
source_x86_64=("${url}/releases/download/v${pkgver}/appname_${pkgver}_amd64.deb")
source_aarch64=("${url}/releases/download/v${pkgver}/appname_${pkgver}_arm64.deb")
```
- 파일의 시작 부분에서 "패키지 이름"을 정의하고 변수 `pkgname`에 할당합니다.
- "`pkgver`" 변수를 설정합니다. 일반적으로 코드의 유지 관리성을 높이기 위해 이 변수를 소스 내의 변수에서 사용하는 것이 가장 좋습니다.
- "`pkgdesc`" 변수는 AUR 리포지토리 페이지의 변수로, 방문자에게 앱에서 무엇을 할 수 있는지 알려줍니다.
- "`arch`" 변수는 어떤 CPU 아키텍처에 패키지를 설치할 수 있는지 제시합니다.
- "`url`" 변수는 필수는 아니지만 패키지를 더 전문적으로 보이게 하는 데 도움이 됩니다.
- "`install`" 변수는 패키지가 설치, 제거 또는 업그레이드될 때 실행되는 ".install 스크립트"의 이름을 지정합니다.
- "`depends`" 변수에는 앱 실행에 필요한 라이브러리 등의 목록이 저장됩니다. Tauri 앱을 실행하려면 위에 표시된 모든 종속성을 포함해야 합니다.
- "`source`" 변수는 필수이며 업스트림 패키지의 위치를 정의합니다. 변수 이름 끝에 아키텍처를 추가하여 아키텍처별 `source`로 만들 수 있습니다.
### `.SRCINFO` 생성
리포지토리를 AUR에 푸시하려면 `.SRCINFO` 파일을 생성해야 합니다. 다음 명령으로 실행할 수 있습니다.
```sh
makepkg --printsrcinfo > .SRCINFO
```
### 테스트
앱 테스트는 매우 간단합니다. `PKGBUILD` 파일과 동일한 디렉토리 내에서 `makepkg`를 실행하고 작동하는지 확인하기만 하면 됩니다.
### 게시
마지막으로 테스트 단계가 끝나면 다음 명령을 사용하여 애플리케이션을 AUR(Arch User Repository)에 게시할 수 있습니다.
```sh
git add .
git commit -m "Initial Commit"
git push
```
모든 것이 잘되면 리포지토리가 AUR 웹 사이트에 표시될 것입니다.
## 실시 예
### Debian 패키지에서 추출
```ini title="PKGBUILD"
# Maintainer:
# Contributor:
pkgname=<pkgname>
pkgver=1.0.0
pkgrel=1
pkgdesc="Description of your app"
arch=('x86_64' 'aarch64')
url="https://github.com/<user>/<project>"
license=('MIT')
depends=('cairo' 'desktop-file-utils' 'gdk-pixbuf2' 'glib2' 'gtk3' 'hicolor-icon-theme' 'libsoup' 'pango' 'webkit2gtk-4.1')
options=('!strip' '!debug')
install=${pkgname}.install
source_x86_64=("${url}/releases/download/v${pkgver}/appname_${pkgver}_amd64.deb")
source_aarch64=("${url}/releases/download/v${pkgver}/appname_${pkgver}_arm64.deb")
sha256sums_x86_64=('ca85f11732765bed78f93f55397b4b4cbb76685088553dad612c5062e3ec651f')
sha256sums_aarch64=('ed2dc3169d34d91188fb55d39867713856dd02a2360ffe0661cb2e19bd701c3c')
package() {
# 패키지 데이터 추출
tar -xvf data.tar.gz -C "${pkgdir}"
}
```
```ini title="my-tauri-app.install"
post_install() {
gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
update-desktop-database -q
}
post_upgrade() {
post_install
}
post_remove() {
gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
update-desktop-database -q
}
```
### 소스에서 빌드
```ini title="PKGBUILD"
# Maintainer:
pkgname=<pkgname>-git
pkgver=<pkgver>
pkgrel=1
pkgdesc="Description of your app"
arch=('x86_64' 'aarch64')
url="https://github.com/<user>/<project>"
license=('MIT')
depends=('cairo' 'desktop-file-utils' 'gdk-pixbuf2' 'glib2' 'gtk3' 'hicolor-icon-theme' 'libsoup' 'pango' 'webkit2gtk-4.1')
makedepends=('git' 'openssl' 'appmenu-gtk-module' 'libappindicator-gtk3' 'librsvg' 'cargo' 'pnpm' 'nodejs')
provides=('<pkgname>')
conflicts=('<binname>' '<pkgname>')
source=("git+${url}.git")
sha256sums=('SKIP')
pkgver() {
cd <project>
( set -o pipefail
git describe --long --abbrev=7 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
)
}
prepare() {
cd <project>
pnpm install
}
build() {
cd <project>
pnpm tauri build -b deb
}
package() {
cp -a <project>/src-tauri/target/release/bundle/deb/<project>_${pkgver}_*/data/* "${pkgdir}"
}
```
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 29, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,31 @@
---
title: CrabNebula 클라우드로 배포하기
sidebar:
label: CrabNebula Cloud
order: 1
i18nReady: true
---
import TranslationNote from '@components/i18n/TranslationNote.astro';
[CrabNebula]는 Tauri 애플리케이션을 위한 서비스와 도구를 제공하는 공식 Tauri 파트너입니다.
[CrabNebula Cloud]는 Tauri 업데이터와 원활하게 통합된 애플리케이션 배포 플랫폼입니다.
이 "Cloud(클라우드)"는 애플리케이션의 설치 프로그램과 업데이트 프로그램을 전 세계에 배포할 수 있는 "콘텐츠 전송 네트워크(CDN)"를 제공하면서, 한편으로는 비용 효율적이며 다운로드 수 지표도 공개합니다.
CrabNebula Cloud 서비스를 이용하면 여러 릴리스 채널이나 자신의 애플리케이션 웹 사이트용 다운로드 버튼 등을 비롯하여 다양한 것을 쉽게 구현할 수 있습니다.
"Cloud"를 이용하기 위한 Tauri 앱 설정은 간단합니다: 해야 할 일은 "[Cloud 웹사이트]"에 GitHub 계정으로 로그인하고, "소속 조직"과 "애플리케이션"을 만들고, "릴리스 버전" 작성을 위해 CLI(명령줄 인터페이스)를 설치하고, Tauri 번들을 업로드하는 것뿐입니다.
또한 [GitHub Action]도 제공되어 GitHub 워크플로에서 CLI를 사용하는 프로세스가 간소화되었습니다.
자세한 내용은 [CrabNebula Cloud 문서](영어)를 참조하십시오.
[CrabNebula]: https://crabnebula.dev
[CrabNebula Cloud]: https://crabnebula.dev/cloud/
[GitHub Action]: https://github.com/crabnebula-dev/cloud-release/
[Cloud 웹사이트]: https://web.crabnebula.cloud/
[CrabNebula Cloud 문서]: https://docs.crabnebula.dev/cloud/
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,43 @@
---
title: Debian
sidebar:
order: 1
i18nReady: true
---
{/* Is this about building .deb files, creating PPAs, or adding something to the debian/ubuntu repos? */}
import TranslationNote from '@components/i18n/TranslationNote.astro';
## Debian(데비안)
Tauri 번들러에 의해 생성되는 일반적인 [Debian] 패키지에는 애플리케이션을 Debian 기반 Linux 배포판에 배포하는 데 필요한 모든 것이 포함되어 있습니다. 예를 들어, 애플리케이션 아이콘 정의, 데스크톱 파일 생성, `libwebkit2gtk-4.1-0` 및 `libgtk-3-0` 종속성 지정(애플리케이션이 시스템 트레이를 사용하는 경우 `libappindicator3-1` 종속성도 포함) 등입니다.
### 사용자 지정 파일
더 많은 조정이 필요한 경우를 대비하여 Tauri는 Debian 패키지 설정을 일부 공개합니다.
앱에 다른 시스템 종속성이 필요한 경우 `tauri.conf.json > bundle > linux > deb`에서 지정할 수 있습니다.
Debian 패키지에 사용자 지정 파일을 포함하려면 `tauri.conf.json > bundle > linux > deb > files`에 파일 또는 폴더 목록을 지정합니다. 설정 객체는 Debian 패키지 내의 경로를 파일 시스템상의 파일 경로로, `tauri.conf.json` 파일로부터의 상대 경로로 확장(매핑)합니다. 다음은 설정 예시입니다:
```json
{
"bundle": {
"linux": {
"deb": {
"files": {
"/usr/share/README.md": "../README.md", // "../README.md" 파일을 "/usr/share/README.md"에 복사
"/usr/share/assets": "../assets/" // "../assets" 디렉토리의 모든 것을 "/usr/assets"에 복사
}
}
}
}
}
```
[Debian]: https://www.debian.org/using/index.ko.html
<div style="text-align: right">
【※ 이 한국어판은, 「Feb 22, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,135 @@
---
title: DMG
sidebar:
order: 1
i18nReady: true
---
import CommandTabs from '@components/CommandTabs.astro';
import { Image } from 'astro:assets';
import StandardDmgLight from '@assets/distribute/dmg/standard-dmg-light.png';
import StandardDmgDark from '@assets/distribute/dmg/standard-dmg-dark.png';
import TranslationNote from '@components/i18n/TranslationNote.astro';
DMG(Apple 디스크 이미지 파일) 형식은 일반적인 macOS 설치 프로그램 파일로, [App Bundle][macOS Application Bundle 장]을 사용자 친화적인 "설치 창"으로 래핑(포함)합니다.
"설치 창"에는 "앱 아이콘"과 "애플리케이션 폴더 아이콘"이 포함되어 있으며, 사용자는 "앱 아이콘"을 "애플리케이션 폴더 아이콘" 위로 드래그하여 설치를 수행하게 됩니다.
이 방법은 App Store 이외에서 배포되는 macOS 애플리케이션의 가장 일반적인 설치 방법입니다.
이 장에서는 App Store와 다른 방법으로 DMG 형식을 사용하여 앱을 배포하는 방법에 대한 세부 정보만 설명합니다.
macOS 배포 옵션 및 설정에 대한 자세한 내용은 [macOS Application Bundle 장]을 참조하십시오.
macOS 앱을 App Store에서 배포하려면 [App Store 장]을 참조하십시오.
앱의 "Apple 디스크 이미지"를 만들려면 Tauri CLI를 사용하여 Mac 컴퓨터에서 `tauri build` 명령을 실행합니다:
<CommandTabs
npm="npm run tauri build -- --bundles dmg"
yarn="yarn tauri build --bundles dmg"
pnpm="pnpm tauri build --bundles dmg"
deno="deno task tauri build --bundles dmg"
bun="bun tauri build --bundles dmg"
cargo="cargo tauri build --bundles dmg"
/>
<Image
class="dark:sl-hidden"
src={StandardDmgLight}
alt="Standard DMG window"
/>
<Image
class="light:sl-hidden"
src={StandardDmgDark}
alt="Standard DMG window"
/>
## 창 배경
[`tauri.conf.json > bundle > macOS > dmg > background`] 설정 옵션을 사용하여 DMG 설치 창에 사용자 지정 배경 이미지를 설정할 수 있습니다.
```json title="tauri.conf.json" ins={4-6}
{
"bundle": {
"macOS": {
"dmg": {
"background": "./images/"
}
}
}
}
```
예를 들어, DMG 배경 이미지에 "화살표"를 표시하여 사용자에게 앱 아이콘을 애플리케이션 폴더 방향으로 드래그해야 함을 나타낼 수 있습니다.
## 창 크기 및 위치
기본 창 크기는 "660x400"입니다. 사용자 지정 배경 이미지에 맞게 다른 크기로 하려면 [`tauri.conf.json > bundle > macOS > dmg > windowSize`]에서 설정하십시오:
```json title="tauri.conf.json" ins={5-8}
{
"bundle": {
"macOS": {
"dmg": {
"windowSize": {
"width": 800,
"height": 600
}
}
}
}
}
```
또한 [`tauri.conf.json > bundle > macOS > dmg > windowPosition`] 설정으로 초기 창 위치를 지정할 수도 있습니다:
```json title="tauri.conf.json" ins={5-8}
{
"bundle": {
"macOS": {
"dmg": {
"windowPosition": {
"x": 400,
"y": 400
}
}
}
}
}
```
## 아이콘 위치
앱과 *애플리케이션 폴더*의 아이콘 위치는 각각 [appPosition] 및 [applicationFolderPosition] 설정 값으로 변경할 수 있습니다:
```json title="tauri.conf.json" ins={5-12}
{
"bundle": {
"macOS": {
"dmg": {
"appPosition": {
"x": 180,
"y": 220
},
"applicationFolderPosition": {
"x": 480,
"y": 220
}
}
}
}
}
```
:::caution
알려진 문제로 인해 CI/CD 플랫폼에서 DMG를 만든 경우 아이콘 크기와 위치가 적용되지 않습니다.
자세한 내용은 [tauri-apps/tauri#1731]을 참조하십시오.
:::
[macOS Application Bundle 장]: /ko/distribute/macos-application-bundle/
[App Store 장]: /ko/distribute/app-store/
[appPosition]: /reference/config/#appposition
[applicationFolderPosition]: /reference/config/#applicationfolderposition
[tauri-apps/tauri#1731]: https://github.com/tauri-apps/tauri/issues/1731
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 29, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,254 @@
---
title: 앱 배포
sidebar:
order: 0
label: 개요
i18nReady: true
---
import { CardGrid, LinkCard, LinkButton } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
import TranslationNote from '@components/i18n/TranslationNote.astro';
Tauri는 자신의 애플리케이션을 각 플랫폼의 앱 스토어를 향해, 또는 플랫폼별 설치 프로그램으로 배포하는 데 필요한 도구를 제공합니다.
## 빌드
Tauri는 CLI(명령줄 인터페이스)에서 `build`, `android build`, `ios build` 명령을 사용하여 직접 애플리케이션을 빌드할 수 있습니다.
<CommandTabs
npm="npm run tauri build"
yarn="yarn tauri build"
pnpm="pnpm tauri build"
deno="deno task tauri build"
bun="bun tauri build"
cargo="cargo tauri build"
/>
각 번들에서 사용할 수 있는 설정 옵션과 사용자에게 배포하는 방법에 대한 자세한 내용은 "[배포](#배포)" 항목을 참조하십시오.
:::note
대부분의 플랫폼에서는 "코드 서명"이 필요합니다. 자세한 내용은 "[서명](#서명)" 항목을 참조하십시오.
:::
### 번들
기본적으로 `build` 명령은 설정된 형식에 맞게 애플리케이션을 자동으로 번들링합니다.
플랫폼용 번들 생성 방법을 더 사용자 정의해야 하는 경우, "빌드"와 "번들" 절차를 분할할 수 있습니다.
<CommandTabs
npm="npm run tauri build -- --no-bundle
# macOS App Store 이외의 배포용 번들 생성
npm run tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
npm run tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
yarn="yarn tauri build --no-bundle
# macOS App Store 이외의 배포용 번들 생성
yarn tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
yarn tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
pnpm="pnpm tauri build --no-bundle
# macOS App Store 이외의 배포용 번들 생성
pnpm tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
pnpm tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
deno="deno task tauri build --no-bundle
# macOS App Store 이외의 배포용 번들 생성
deno task tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
deno task tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
bun="bun tauri build --no-bundle
# macOS App Store 이외의 배포용 번들 생성
bun tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
bun tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
cargo="cargo tauri build --no-bundle
# macOS App Store 이외의 배포용 번들 생성
cargo tauri bundle -- --bundles app,dmg
# App Store 배포용 번들 생성
cargo tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json"
/>
## 버전 관리
애플리케이션 버전은 [`tauri.conf.json > version`] 설정 옵션으로 정의할 수 있습니다. 이는 앱 버전을 관리하는 데 권장되는 방법입니다.
이 값이 설정되지 않은 경우 Tauri는 대신 `src-tauri/Cargo.toml` 파일의 `package > version` 값을 사용합니다.
:::note
일부 플랫폼에서는 "버전" 문자열에 대해 몇 가지 제한 사항이나 특례가 있습니다.
자세한 내용은 각 배포판의 설명서를 참조하십시오.
:::
## 서명
"코드 서명"은 애플리케이션의 실행 파일과 번들에 디지털 서명을 적용하여 애플리케이션 제공자의 "신원 증명서"를 검증함으로써 애플리케이션의 보안을 강화하는 것입니다.
대부분의 플랫폼에서는 서명이 필요합니다. 자세한 내용은 각 플랫폼의 설명서를 참조하십시오.
<CardGrid>
<LinkCard
title="macOS"
href="/ko/distribute/sign/macos/"
description="macOS 앱의 코드 서명 및 인증"
/>
<LinkCard
title="Windows"
href="/ko/distribute/sign/windows/"
description="Windows 설치 프로그램의 코드 서명"
/>
<LinkCard
title="Linux"
href="/ko/distribute/sign/linux/"
description="Linux 패키지의 코드 서명"
/>
<LinkCard
title="Android"
href="/ko/distribute/sign/android/"
description="Android의 코드 서명"
/>
<LinkCard
title="iOS"
href="/ko/distribute/sign/ios/"
description="iOS의 코드 서명"
/>
</CardGrid>
## 배포
각 플랫폼용 애플리케이션을 배포하는 방법을 배웁니다.
### Linux의 경우
Linux의 경우 Debian 패키지, Snap, AppImage, Flatpak, RPM 또는 Arch User Repository (AUR) 형식을 사용하여 앱을 배포할 수 있습니다.
<CardGrid>
<LinkCard
title="AppImage"
href="/ko/distribute/appimage/"
description="AppImage로 배포하기"
/>
<LinkCard
title="AUR"
href="/ko/distribute/aur/"
description="Arch User Repository에 게시하기"
/>
<LinkCard
title="Debian"
href="/ko/distribute/debian/"
description="Debian 패키지로 배포하기"
/>
{/* <LinkCard
title="Flathub"
href="/ko/distribute/flatpak/"
description="Flatpak으로 배포하기"
/> */}
<LinkCard
title="RPM"
href="/ko/distribute/rpm/"
description="RPM 패키지로 배포하기"
/>
<LinkCard
title="Snapcraft"
href="/ko/distribute/snapcraft/"
description="Snap 패키지로 배포하기"
/>
</CardGrid>
<LinkButton href="/ko/distribute/sign/linux/">코드 서명</LinkButton>
### macOS의 경우
macOS의 경우 애플리케이션을 App Store에서 직접 배포하는 방법과 직접 다운로드용으로 DMG 설치 프로그램을 배포하는 방법이 있습니다.
두 방법 모두 "코드 서명"이 필요하며, App Store 외부에서 배포하는 경우 "인증"도 필요합니다.
<TranslationNote lang="ko">
**인증** 원문은 notarization: "공증=사문서의 진실성을 증명"하는 것이 원래 의미이지만, 본고에서는 "인증 ≒ authorization"으로 번역했습니다.
</TranslationNote>
<CardGrid>
<LinkCard
title="App Bundle"
href="/ko/distribute/macos-application-bundle/"
description="macOS 앱을 App Bundle로 배포하기"
/>
<LinkCard
title="App Store"
href="/ko/distribute/app-store/"
description="iOS 및 macOS 앱을 App Store에 배포하기"
/>
<LinkCard
title="DMG"
href="/ko/distribute/dmg/"
description="macOS 앱을 Apple 디스크 이미지로 배포하기"
/>
</CardGrid>
<LinkButton href="/ko/distribute/sign/macos/">코드 서명 및 인증</LinkButton>
### Windows의 경우
Microsoft Store에서 배포하는 방법 또는 Windows 설치 프로그램을 설정하는 방법에 대해 설명합니다.
<CardGrid>
<LinkCard
title="Microsoft Store"
href="/ko/distribute/microsoft-store/"
description="Windows 앱을 Microsoft Store에 배포하기"
/>
<LinkCard
title="Windows Installer"
href="/ko/distribute/windows-installer/"
description="Windows용 설치 프로그램 배포하기"
/>
</CardGrid>
<LinkButton href="/ko/distribute/sign/windows/">코드 서명</LinkButton>
### Android의 경우
Android 애플리케이션을 Google Play에서 배포합니다.
<CardGrid>
<LinkCard
title="Google Play"
href="/ko/distribute/google-play/"
description="Android 앱을 Google Play에 배포하기"
/>
</CardGrid>
<LinkButton href="/ko/distribute/sign/android/">코드 서명</LinkButton>
### iOS의 경우
애플리케이션을 App Store에 업로드하는 방법을 배웁니다.
<CardGrid>
<LinkCard
title="App Store"
href="/ko/distribute/app-store/"
description="iOS와 macOS 앱을 App Store에 배포하기"
/>
</CardGrid>
<LinkButton href="/ko/distribute/sign/ios/">코드 서명</LinkButton>
### 클라우드 서비스 이용
애플리케이션을 전 세계에 배포하고 설정이 필요 없는 자동 업데이트를 지원하는 클라우드 서비스로 애플리케이션을 배포합니다.
<CardGrid>
<LinkCard
title="CrabNebula Cloud"
href="/ko/distribute/crabnebula-cloud/"
description="CrabNebula를 사용하여 앱 배포하기"
/>
</CardGrid>
[`tauri.conf.json > version`]: /reference/config/#version
<div style="text-align: right">
【※ 이 한국어판은, 「Mar 29, 2025 영문판」에 근거하고 있습니다】
</div>

View File

@@ -0,0 +1,68 @@
---
title: Tauri 2.0
description: 크로스 플랫폼 앱 구축 툴킷
i18nReady: true
editUrl: false
lastUpdated: false
template: splash
tableOfContents: false
prev: false
next: false
hero:
tagline: 가볍고 빠르고 안전한 크로스 플랫폼 애플리케이션 제작
image:
file: ../../../assets/logo-outline.svg
actions:
- text: 시작하기
link: /ko/start/
icon: right-arrow
variant: primary
- text: Tauri 1.0 문서
link: https://v1.tauri.app/ko/
icon: external
variant: minimal
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
import Cta from '@fragments/cta.mdx';
<div class="hero-bg">
<div class="bg-logo"></div>
<div class="bg-grad"></div>
<div class="bg-grad-red"></div>
</div>
<div class="lp-cta-card">
<Card title="프로젝트 시작" icon="rocket">
<Cta />
</Card>
</div>
<CardGrid>
<Card title="프론트엔드는 웹 기술" icon="rocket">
현재 웹 설정을 그대로 Tauri에서 사용하거나 꿈의 프로젝트를 새로 시작하세요.
Tauri는 어떤 프론트엔드 기술도 사용할 수 있으므로 현재 설정을 변경할 필요가
없습니다.
</Card>
<Card title="크로스 플랫폼 지원" icon="rocket">
하나의 코드로 Linux, macOS, Windows, Android, iOS용 앱을 모두 빌드할 수
있습니다.
</Card>
<Card title="프로세스 간 통신" icon="rocket">
프론트엔드 부분을 JavaScript로, 애플리케이션 로직을 Rust로 작성하고 시스템
깊숙한 곳에서 Swift와 Kotlin을 사용하여 통합합니다.
</Card>
<Card title="최대한의 안전성" icon="rocket">
최우선 순위와 최대 혁신을 추진하는 Tauri 팀의 "제1 원칙"입니다.
</Card>
<Card title="앱 경량화" icon="rocket">
OS 고유의 웹 렌더링 엔진을 사용하여 Tauri 앱의 프로그램 크기는 불과 "600KB"
정도가 될 수 있습니다.
</Card>
<Card title="Rust로 동작" icon="rocket">
"성능"과 "보안"을 핵심으로 하는 Rust는 차세대 앱을 위한 프로그래밍
언어입니다.
</Card>
</CardGrid>
<div style="text-align: right;">Doc-KO 2.00.00</div>

View File

@@ -0,0 +1,199 @@
---
title: 다양한 창과 플랫폼에서의 보안 수준
sidebar:
order: 11
i18nReady: true
---
import { Steps } from '@astrojs/starlight/components';
import ShowSolution from '@components/ShowSolution.astro';
import Cta from '@fragments/cta.mdx';
import TranslationNote from '@components/i18n/TranslationNote.astro';
이 장은 Tauri 앱의 보안 수준을 사용자 정의하는 방법에 대해 설명합니다.
## 이 장의 내용
- Tauri 앱에서 여러 창 만들기
- 창마다 다른 보안 수준 사용하기
- 플랫폼에 의존하는 보안 수준 사용하기
## 사전 준비
이 장의 연습 내용은 "[플러그인 접근 권한 사용](/ko/learn/security/using-plugin-permissions/)"을 읽은 후에 수행하는 것을 전제로 합니다.
## 절차
<Steps>
1. ### Tauri 앱에서 여러 창 만들기
이 연습에서는 `first`(첫 번째)와 `second`(두 번째)라는 레이블이 붙은 두 개의 창을 가진 앱을 만듭니다.
Tauri 애플리케이션에서 창을 만드는 방법은 여러 가지가 있습니다.
#### Tauri 설정 파일을 사용하여 창 만들기
Tauri 설정 파일(일반적으로 `tauri.conf.json`이라는 이름)에서는 다음과 같습니다:
<ShowSolution>
```javascript
"productName": "multiwindow",
...
"app": {
"windows": [
{
"label": "first",
"title": "First",
"width": 800,
"height": 600
},
{
"label": "second",
"title": "Second",
"width": 800,
"height": 600
}
],
},
...
}
```
</ShowSolution>
#### 프로그래밍 방식으로 창 만들기
Rust 코드 내에서 Tauri 앱을 만듭니다:
<ShowSolution>
```rust
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.setup(|app| {
let webview_url = tauri::WebviewUrl::App("index.html".into());
// First window(첫 번째 창)
tauri::WebviewWindowBuilder::new(app, "first", webview_url.clone())
.title("First")
.build()?;
// Second window(두 번째 창)
tauri::WebviewWindowBuilder::new(app, "second", webview_url)
.title("Second")
.build()?;
Ok(())
})
.run(context)
.expect("error while running tauri application");
```
</ShowSolution>
2. ### 다른 창에 다른 보안 수준 적용
Tauri 앱의 창에서는 Tauri 백엔드의 다양한 기능이나 플러그인을 사용할 수 있습니다.
보안을 더 강화하기 위해 각 창에 필요한 보안 기능만 부여하는 것이 좋습니다.
이 연습에서는 "첫 번째 `first`" 창에서 파일 시스템과 대화 상자 기능을 사용하고, "두 번째 `second`" 창에서는 대화 상자 기능만 필요로 하는 상황을 가정하고 진행합니다.
#### 카테고리별 개별 "보안 수준" 파일
활성화할 작업의 카테고리별로 "보안 수준" 파일을 분할하는 것이 좋습니다.
<ShowSolution>
`src-tauri/capabilities` 내의 JSON 파일은 "보안 수준" 시스템에 이미 대응되어 있습니다.
따라서 파일 시스템과 대화 상자 창과 관련된 보안 수준을 `filesystem.json`과 `dialog.json`으로 분할합니다.
_Tauri 프로젝트의 파일 트리:_
```
/src
/src-tauri
/capabilities
filesystem.json
dialog.json
tauri.conf.json
package.json
README.md
```
</ShowSolution>
#### "첫 번째 `first`" 창에 파일 시스템 보안 수준 부여
"`first`" 창에 `$HOME` 디렉토리 내용에 대한 읽기 접근 권한을 부여하도록 보안 수준을 설정합니다.
<ShowSolution>
하나 또는 여러 개의 창 레이블을 가진 "보안 기능 capability" 파일 내의 "`windows` 필드"를 사용합니다.
```json title="filesystem.json"
{
"identifier": "fs-read-home",
"description": "Allow access file access to home directory",
"local": true,
"windows": ["first"],
"permissions": ["fs:allow-home-read"]
}
```
<TranslationNote lang="ko">
"filesystem.json" 파일 내용 초역:
- identifier: 식별자 이름
- description: 보안 내용 설명(home 디렉토리에 대한 파일 접근 허용)
- local: true
- windows: 창 이름
- permissions: 접근 권한 설정
</TranslationNote>
</ShowSolution>
#### "첫 번째 `first`"와 "두 번째 `second`" 창에 대화 상자 기능 부여
"`first`"와 "`second`" 창에 "예/아니오" 대화 상자를 만드는 기능을 추가합니다.
<ShowSolution>
하나 또는 여러 개의 창 레이블을 가진 "보안 기능" 파일 내의 `windows` 필드를 사용합니다.
```json title="dialog.json"
{
"identifier": "dialog",
"description": "Allow to open a dialog",
"local": true,
"windows": ["first", "second"],
"permissions": ["dialog:allow-ask"]
}
```
</ShowSolution>
3. ### 보안 기능을 플랫폼에 따라 다르게 만들기
다음으로, 특정 플랫폼에서만 활성화되도록 보안 기능을 사용자 정의합니다.
아래 예에서는 파일 시스템 보안 기능을 `linux`와 `windows`에서만 활성화합니다.
<ShowSolution>
플랫폼별로 설정하려면 보안 기능 파일의 "`platforms` 필드"에서 대상 플랫폼을 지정합니다.
```json title="filesystem.json"
{
"identifier": "fs-read-home",
"description": "Allow access file access to home directory",
"local": true,
"windows": ["first"],
"permissions": ["fs:allow-home-read"],
"platforms": ["linux", "windows"]
}
```
현재 지정 가능한 플랫폼은 `linux`, `windows`, `macos`, `android`, `ios`입니다.
</ShowSolution>
</Steps>
## 본 장의 요약 및 참고 자료
Tauri 앱에서 여러 창을 만들고 각각에 별도의 보안 기능을 부여하는 방법을 배웠습니다. 또한 이러한 보안 기능은 특정 플랫폼에 맞게 사용자 정의할 수도 있습니다.
창 기능을 사용한 샘플 애플리케이션은 [Tauri Github 리포지토리](https://github.com/tauri-apps/tauri)의 [`api` 샘플](https://github.com/tauri-apps/tauri/tree/dev/examples/api) 내에 있습니다.
"보안 기능 파일 capability file"에서 사용할 수 있는 필드는 TAURI Doc의 "메뉴 Menu" 내에 있는 "Reference"의 [Capability](/reference/acl/capability/) 부분에 나열되어 있습니다.

View File

@@ -0,0 +1,321 @@
---
title: 플러그인 접근 권한 사용
sidebar:
order: 10
i18nReady: true
---
import { Steps } from '@astrojs/starlight/components';
import ShowSolution from '@components/ShowSolution.astro';
import Cta from '@fragments/cta.mdx';
import TranslationNote from '@components/i18n/TranslationNote.astro';
<TranslationNote lang="ko">
본 번역에서는 Permissions / Capabilities에 주로 다음 번역어를 사용합니다.
- Permissions: "접근 권한"(액세스 허가권)
- Capabilities: "보안 수준"(보안 정도를 나타내는 권한 수준)
</TranslationNote>
이 장의 목적은 플러그인 접근 권한이 어떻게 활성화 또는 비활성화되는지, 어디에 기술되어 있는지, 그리고 플러그인의 기본 접근 권한 사용 방법에 대해 더 깊이 이해하는 것입니다.
이 장을 다 읽을 때쯤이면 어떤 플러그인이든 그 접근 권한을 찾아 사용하고 기존 접근 권한을 사용자 정의하는 방법을 이해하게 될 것입니다.
아래에서 플러그인과 플러그인별 접근 권한을 사용하는 Tauri 애플리케이션의 예를 볼 수도 있습니다.
<Steps>
1. ### Tauri 애플리케이션 만들기
Tauri 애플리케이션을 만듭니다.
이 예에서는 [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app)을 실행합니다.
<Cta />
이 단계별 설명 절차에서는 `pnpm`을 사용하여 진행하지만, 다른 패키지 관리자도 선택할 수 있습니다. 선택한 패키지 관리자에 따라 명령을 바꿔주세요.
<ShowSolution>
```
pnpm create tauri-app
```
```
✔ Project name · plugin-permission-demo
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, bun)
✔ Choose your package manager · pnpm
✔ Choose your UI template · Vanilla
✔ Choose your UI flavor · TypeScript
Template created! To get started run:
cd plugin-permission-demo
pnpm install
pnpm tauri dev
```
<TranslationNote lang="ko">
※ 처리 내용 참고 번역:
✔ 프로젝트 이름 ...
✔ 프론트엔드에 사용할 언어 선택 ...
✔ 패키지 관리자 선택 ...
✔ UI 템플릿 선택 ...
✔ UI 맛 선택 ...
템플릿이 생성되었습니다! 시작하려면 다음을 실행하십시오:
cd (생성할 프로젝트 디렉토리 이름)
pnpm install
pnpm tauri dev
</TranslationNote>
</ShowSolution>
2. ### "파일 시스템" 플러그인을 애플리케이션에 추가
기존 플러그인을 검색하려면 여러 리소스를 사용할 수 있습니다.
가장 쉬운 방법은 플러그인이 이미 『Tauri Guides』 문서의 "[Plugins](/ko/plugin/)"에 있는지, 즉 Tauri가 관리하는 플러그인 세트 안에 존재하는지 확인하는 것입니다.
예를 들어, "파일 시스템(fs)" 플러그인은 **Tauri Plugins** 메뉴의 작업 공간(공유 영역)에 게시되어 있으며, 해당 링크의 [설정 절차](/ko/plugin/file-system/#setup)에 따라 자신의 프로젝트에 추가할 수 있습니다.
또한 플러그인이 Tauri 커뮤니티의 노력으로 이루어진 것이라면 [crates.io](https://crates.io/search?q=tauri-plugin-)에서 거의 확실하게 찾을 수 있습니다. "`tauri-plugin-<플러그인 이름>`"과 같이 검색해 보십시오:
<ShowSolution>
<TranslationNote lang="ko">
아래, "파일 시스템 fs" 플러그인을 예로 들어, ① 메뉴 "Plaugins" 부분에 나열된 경우와, ② "crates.io" 사이트에서 얻는 경우의 처리 절차가 표시됩니다.
</TranslationNote>
찾고 있는 플러그인이 "작업 공간(공유 영역)"에 있는 기존 플러그인이라면 자동화된 방법을 사용할 수 있습니다:
```
pnpm tauri add fs
```
해당 플러그인을 "[crates.io](https://crates.io/crates/tauri-plugin-fs)" 사이트에서 찾은 경우, 종속성을 수동으로 추가하고 플러그인을 초기화하기 위해 Tauri 빌더를 수정해야 합니다:
```sh
cargo add tauri-plugin-fs
```
플러그인 초기화를 위해 `lib.rs`를 수정합니다:
```rust title="src-tauri/src/lib.rs" ins={4}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
</ShowSolution>
3. ### "파일 시스템" 플러그인의 기본 접근 권한 확인
각 플러그인에는 "기본" 접근 권한 세트가 있으며, 여기에는 적절하고 최소한의 기능과 플러그인을 즉시 그대로 사용하기 위한 접근 권한과 범위가 모두 포함되어 있습니다.
공식적으로 유지 관리되는 플러그인의 경우, 문서에 제공된 설명이 기재되어 있습니다(예: [fs default](/plugin/file-system/#default-permission)).
커뮤니티 제작 플러그인에 대한 기본 접근 권한 설정을 알아보려면 해당 플러그인의 소스 코드를 자세히 살펴봐야 합니다.
그 내용은 `your-plugin/permissions/default.toml`에 정의되어 있어야 합니다.
<ShowSolution>
```
"$schema" = "schemas/schema.json"
[default]
description = """
# Tauri `fs` default permissions
This configuration file defines the default permissions granted to the filesystem.
### Granted Permissions
This default permission set enables all read-related commands and allows access to the `$APP` folder and sub directories created in it.
The location of the `$APP` folder depends on the operating system, where the application is run.
In general the `$APP` folder needs to be manually created
by the application at runtime, before accessing files or folders
in it is possible.
### Denied Permissions
This default permission set prevents access to critical components
of the Tauri application by default.
On Windows the webview data folder access is denied.
"""
permissions = ["read-all", "scope-app-recursive", "deny-default"]
```
<TranslationNote lang="ko">
[참고 번역]
# Tauri 'fs' 기본 접근 권한
이 설정 파일은 "파일 시스템 fs" 플러그인에 부여되는 기본 접근 권한을 정의합니다.
### 허가된 접근 권한
이 기본 접근 "허가" 권한 세트는 모든 읽기 관련 명령을 활성화하고, "`$APP`" 폴더와 그 안에 생성된 하위 디렉토리에 대한 접근을 허용합니다.
"`$APP`" 폴더의 위치는 애플리케이션이 실행되는 운영 체제에 따라 다릅니다.
일반적으로 "`$APP`" 폴더 내의 파일이나 폴더에 접근하려면, 애플리케이션이 런타임에 수동으로 "`$APP`" 폴더를 생성해야 합니다.
### 거부된 접근 권한
이 기본 접근 "거부" 권한 세트는 기본적으로 Tauri 애플리케이션의 중요한 구성 요소에 대한 접근을 방지합니다.
Windows에서는 Webview 데이터 폴더에 대한 접근이 거부됩니다.
</TranslationNote>
</ShowSolution>
4. ### 적절한 접근 권한 찾기
4단계에서는 시스템에 대한 최소한의 접근으로 명령을 프론트엔드에 공개하는 데 필요한 접근 권한을 찾는 방법을 설명합니다.
"`fs`" 플러그인에는 자동 생성된 접근 권한이 있으며, 개별 명령의 비활성화/활성화나 전역 범위의 허가/금지를 수행합니다.
접근 권한에 대한 자세한 내용은 [공식 문서](/plugin/file-system/#permission-table) 또는 플러그인의 소스 코드(`fs/permissions/autogenerated`)를 참조하십시오.
예를 들어, 사용자의 `$HOME` 폴더에 있는 텍스트 파일 "`test.txt`"에 대한 쓰기를 활성화하고 싶다고 가정합니다.
이를 위해 "자동 생성된 접근 권한" 중에서 `allow-write-text-file`과 같이 텍스트 파일에 대한 쓰기를 허용하는 권한을 검색하고, 그런 다음 `$HOME/test.txt` 파일에 대한 접근을 허용하는 범위를 검색합니다.
이러한 접근 권한을 `src-tauri/tauri.conf.json`의 "보안 수준 `capabilities`" 섹션 또는 "`src-tauri/capabilities/` 폴더 내의 파일"에 추가해야 합니다.
기본적으로 `src-tauri/capabilities/default.json` 안에는 이미 수정 가능한 "보안 기능"이 있습니다.
<ShowSolution>
```json title="src-tauri/capabilities/default.json" del={18} ins={19}
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"image:default",
"resources:default",
"menu:default",
"tray:default",
"shell:allow-open",
"fs:default",
"fs:allow-write-text-file"
]
}
```
</ShowSolution>
"`fs`" 플러그인에는 `$HOME` 폴더 전체에 접근하기 위한 자동 생성된 범위만 설정되어 있으므로, 자신에게 필요한 고유한 범위를 설정해야 합니다.
이 고유한 범위는 `write-text-file` 명령만 활성화하고 `test.txt` 파일만 공개되도록 해야 합니다.
<ShowSolution>
```json title="src-tauri/capabilities/default.json" del={18} ins={19-22}
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": [
"main"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"image:default",
"resources:default",
"menu:default",
"tray:default",
"shell:allow-open",
"fs:allow-write-text-file",
{
"identifier": "fs:allow-write-text-file",
"allow": [{ "path": "$HOME/test.txt" }]
},
]
}
```
</ShowSolution>
5. ### 접근 권한 실습 테스트
필요한 접근 권한을 추가한 후, 애플리케이션이 파일에 접근하여 그 내용을 쓸 수 있는지 확인합니다.
<ShowSolution>
애플리케이션에서 다음 스니펫을 사용하면 파일에 쓸 수 있습니다:
```ts title="src/main.ts"
import { writeTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
let greetInputEl: HTMLInputElement | null;
async function write(message: string) {
await writeTextFile('test.txt', message, { baseDir: BaseDirectory.Home });
}
window.addEventListener('DOMContentLoaded', () => {
greetInputEl = document.querySelector('#greet-input');
document.querySelector('#greet-form')?.addEventListener('submit', (e) => {
e.preventDefault();
if (!greetInputEl) return;
write(
greetInputEl.value == '' ? 'No input provided' : greetInputEl.value
);
});
});
```
`src/main.ts`를 이 스니펫으로 바꾸면, 기본(플레인) Vanilla+Typescript 앱을 사용하는 경우 기본 `index.html`을 변경할 필요가 없습니다.
실행 중인 앱의 입력 필드에 입력하면, 전송 시 파일에 쓰여집니다.
그럼 실제로 테스트해 봅시다:
```
pnpm run tauri dev
```
입력하고 "전송 Submit"을 클릭한 후, 터미널 에뮬레이터를 사용하거나 홈 폴더 내의 파일을 직접 열면 결과를 확인할 수 있습니다.
```
cat $HOME/test.txt
```
입력한 내용이 표시되어야 하며, 이제 Tauri 애플리케이션에서 플러그인의 접근 권한을 사용하는 방법에 대한 학습이 완료되었습니다.
🥳
다음 오류가 발생한 경우:
```sh
[Error] Unhandled Promise Rejection: fs.write_text_file not allowed. Permissions associated with this command: fs:allow-app-write, fs:allow-app-write-recursive, fs:allow-appcache-write, fs:allow-appcache-write-recursive, fs:allow-appconf...
(anonymous function) (main.ts:5)
```
<TranslationNote lang="ko">
[오류 내용 초역] 처리되지 않은 Promise 반환 "거부": fs.write_text_file이 허용되지 않습니다. 이 명령과 관련된 접근 권한은 fs:allow-app-write, fs:allow-app-write-recursive, ...입니다.
(익명 함수)(main,ts:5)
</TranslationNote>
이 경우, [위의 4단계](#적절한-접근-권한-찾기)를 올바르게 실행하지 않았을 가능성이 매우 높습니다.
</ShowSolution>
</Steps>

View File

@@ -0,0 +1,261 @@
---
title: 플러그인 접근 권한 작성
sidebar:
order: 11
i18nReady: true
---
import { Steps } from '@astrojs/starlight/components';
import ShowSolution from '@components/ShowSolution.astro';
import Cta from '@fragments/cta.mdx';
import TranslationNote from '@components/i18n/TranslationNote.astro';
이 장의 연습 목적은 자신만의 플러그인을 작성할 때 플러그인 접근 권한을 어떻게 만드는지 더 깊이 이해하는 것입니다.
연습이 끝나면 자신의 플러그인에 간단한 접근 권한을 설정할 수 있는 능력을 갖추게 될 것입니다.
접근 권한이 부분적으로 자동 생성되고 수동으로 생성되는 Tauri 플러그인의 예를 보여줍니다.
<Steps>
1. ### Tauri 플러그인 만들기
이 예에서는 Tauri [`cli`](/reference/cli/)[영어 사이트]를 이용하여 Tauri 플러그인의 소스 코드 구조체를 부트스트랩(시작)합니다.
모든 [필수 사항](/ko/start/prerequisites/)이 설치되었는지 확인하고, `cargo tauri info`를 실행하여 Tauri CLI가 올바른 버전인지 확인하십시오.
출력 결과에는 `tauri-cli`의 버전이 "`2.x`"임이 표시되어야 합니다.
이 단계별 설명 절차에서는 `pnpm`을 사용하여 진행하지만, 다른 패키지 관리자도 선택할 수 있습니다. 선택한 패키지 관리자에 따라 명령을 바꿔주세요.
최신 버전이 설치되어 있다면, Tauri CLI를 사용하여 플러그인 생성을 시작할 수 있습니다.
{/* prettier-ignore */}
<ShowSolution>
```sh
mkdir -p tauri-learning
cd tauri-learning
cargo tauri plugin new test
cd tauri-plugin-test
pnpm install
pnpm build
cargo build
```
</ShowSolution>
2. ### 새로운 명령 만들기
실용적이고 간단한 예를 보여주기 위해, 명령이 사용자 입력을 임시 폴더 내의 파일에 쓰고 해당 파일에 사용자 지정 헤더를 추가하는 처리를 가정해 보겠습니다.
이 명령에 "`write_custom_file`"이라는 이름을 붙이고, "`src/commands.rs`"에 구현하고, 플러그인 빌더에 추가하여 프론트엔드에 공개합니다.
Tauri의 코어 유틸리티는 이 명령의 `allow`(허용) 및 `deny`(거부) 권한을 자동으로 생성하므로 이 접근 권한에 대해 고려할 필요가 없습니다.
<ShowSolution>
명령 구현: (아래 마지막 부분이 "`write_custome_file`" 명령을 추가하는 부분)
```rust title="src/commands.rs" ins={15-22} ins=", Manager"
use tauri::{AppHandle, command, Runtime};
use crate::models::*;
use crate::Result;
use crate::TestExt;
#[command]
pub(crate) async fn ping<R: Runtime>(
app: AppHandle<R>,
payload: PingRequest,
) -> Result<PingResponse> {
app.test1().ping(payload)
}
#[command]
pub(crate) async fn write_custom_file<R: Runtime>(
user_input: String,
app: AppHandle<R>,
) -> Result<String> {
std::fs::write(app.path().temp_dir().unwrap(), user_input)?;
Ok("success".to_string())
}
```
새로운 명령에 내장된 접근 권한을 자동 생성합니다:
```rust title="src/build.rs" ins=""write_custom_file""
const COMMANDS: &[&str] = &["ping", "write_custom_file"];
```
이러한 내장 접근 권한은 Tauri 빌드 시스템에 의해 자동으로 생성되며, `permissions/autogenerated/commands` 폴더에 표시됩니다.
기본적으로 `enable-<command>`( 허용) 및 `deny-<command>`( 거부) 접근 권한이 생성됩니다.
</ShowSolution>
3. ### 새로운 명령 공개
"2단계"는 실제 명령 구현을 작성하기 위한 것이었습니다.
이어서 해당 명령을 프론트엔드에 공개하여 사용할 수 있도록 합니다.
<ShowSolution>
새로 구현한 명령에 프론트엔드 IPC 요청을 전달하기 위한 "호출 핸들러"를 생성하도록 Tauri 빌더를 설정합니다:
```rust title="src/lib.rs" ins="commands::write_custom_file,"
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("test")
.invoke_handler(tauri::generate_handler![
commands::ping,
commands::write_custom_file,
])
.setup(|app, api| {
#[cfg(mobile)]
let test = mobile::init(app, api)?;
#[cfg(desktop)]
let test = desktop::init(app, api)?;
app.manage(test);
// 명령에서 접근할 수 있도록 "상태"를 관리(manage)
app.manage(MyState::default());
Ok(())
})
.build()
}
```
프론트엔드 모듈에 새로운 명령을 공개합니다.
이 단계는 이 샘플 애플리케이션이 프론트엔드 모듈을 정상적으로 가져오기 위해 필수적입니다.
이 처리는 편의를 위한 것이며 보안에 영향을 미치지 않습니다. 왜냐하면 명령 핸들러가 이미 생성되어 있고 명령을 프론트엔드에서 수동으로 호출할 수 있기 때문입니다.
```ts title="guest-js/index.ts" ins={11-13}
import { invoke } from '@tauri-apps/api/core';
export async function ping(value: string): Promise<string | null> {
return await invoke<{ value?: string }>('plugin:test|ping', {
payload: {
value,
},
}).then((r) => (r.value ? r.value : null));
}
export async function writeCustomFile(user_input: string): Promise<string> {
return await invoke('plugin:test|write_custom_file', {
userInput: user_input,
});
}
```
:::tip
호출 매개변수는 "카멜 케이스 CamelCase"(결합하는 단어의 첫 글자를 대문자)로 작성해야 합니다. 이 예에서는 "`user_input`"이 아니라 "`userInput`"이라는 표기법이 됩니다.
:::
자신의 패키지가 빌드되는지 확인합니다:
```
pnpm build
```
</ShowSolution>
4. ### 기본 플러그인 접근 권한 정의
이 플러그인 예에서는 기본적으로 `write_custom_file` 명령을 공개해야 하므로 이 명령을 `default.toml`의 접근 권한(permissions)에 추가해야 합니다.
<ShowSolution>
방금 공개한 새로운 명령을 허용하기 위해 이 명령을 기본 접근 권한 세트에 추가합니다.
```toml title="permissions/default.toml" ins=", "allow-write-custom-file""
"$schema" = "schemas/schema.json"
[default]
description = "Default permissions for the plugin"
permissions = ["allow-ping", "allow-write-custom-file"]
```
</ShowSolution>
5. ### 샘플 애플리케이션에서 테스트 명령 호출
생성된 플러그인 디렉토리 구조에는 `examples/tauri-app` 폴더가 있으며, 여기에는 플러그인을 테스트하기 위해 즉시 사용할 수 있는 Tauri 애플리케이션이 포함되어 있습니다.
새로운 명령을 추가했으므로 해당 새로운 명령을 호출하도록 프론트엔드를 약간 변경해야 합니다.
<ShowSolution>
```svelte title="src/App.svelte" del={11-13,42-45} ins={14-16,45-49}
<script>
import Greet from './lib/Greet.svelte'
import { ping, writeCustomFile } from 'tauri-plugin-test-api'
let response = ''
function updateResponse(returnValue) {
response += `[${new Date().toLocaleTimeString()}]` + (typeof returnValue === 'string' ? returnValue : JSON.stringify(returnValue)) + '<br>'
}
function _ping() {
ping("Pong!").then(updateResponse).catch(updateResponse)
}
function _writeCustomFile() {
writeCustomFile("HELLO FROM TAURI PLUGIN").then(updateResponse).catch(updateResponse)
}
</script>
<main class="container">
<h1>Welcome to Tauri!</h1>
<div class="row">
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo vite" alt="Vite Logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" />
</a>
<a href="https://svelte.dev" target="_blank">
<img src="/svelte.svg" class="logo svelte" alt="Svelte Logo" />
</a>
</div>
<p>
Click on the Tauri, Vite, and Svelte logos to learn more.
</p>
<div class="row">
<Greet />
</div>
<div>
<button on:click="{_ping}">Ping</button>
<div>{@html response}</div>
</div>
<div>
<button on:click="{_writeCustomFile}">Write</button>
<div>{@html response}</div>
</div>
</main>
<style>
.logo.vite:hover {
filter: drop-shadow(0 0 2em #747bff);
}
.logo.svelte:hover {
filter: drop-shadow(0 0 2em #ff3e00);
}
</style>
```
이를 실행하고 "쓰기" 버튼을 누르면 다음과 같은 화면이 표시되어야 합니다:
```
success (성공)
```
임시 폴더에는 새로 구현된 플러그인 명령의 메시지가 포함된 `test.txt` 파일이 있어야 합니다.
🥳
</ShowSolution>
</Steps>

View File

@@ -0,0 +1,27 @@
---
title: Tauri RSS 피드
i18nReady: true
topic: guides # 이 페이지를 볼 때 이 사이드바가 활성화됩니다
---
import { LinkCard } from '@astrojs/starlight/components';
<LinkCard
title="모든 업데이트 정보"
description="사이트 전체 업데이트 알림을 받습니다."
href="/feed.xml"
/>
<LinkCard
title="블로그 업데이트 정보"
description="최신 블로그 게시물과 기사를 확인합니다."
href="/blog/rss.xml"
/>
<LinkCard
title="페이지 업데이트 정보"
description="메인 사이트 업데이트 정보를 받습니다."
href="/pages.xml"
/>
<div style="text-align: right;">Doc-KO 2.00.00</div>

View File

@@ -0,0 +1,203 @@
---
title: 보안 수준 Capabilities
sidebar:
order: 4
i18nReady: true
---
Tauri는 애플리케이션 및 플러그인 개발자에게 "보안 수준" 시스템을 제공하여 시스템 WebView에서 실행되는 애플리케이션 프론트엔드에 대한 코어 부분의 공개에 대해 세분화된 활성화/비활성화 제한을 설정합니다.
> > > 《번역 주》 **보안 수준** 원문은 "capabilities system"(능력 시스템). 정보 공개 수준 결정 능력을 나타내므로 본고에서는 "보안 수준"으로 번역했습니다.
"보안 수준"(Capabilities)은 부여된 레이블에 따라 애플리케이션 창과 Webview에 할당되는 [접근 권한(Permissions)](/ko/security/permissions/)의 집합입니다. "보안 수준"은 여러 창과 Webview의 처리에 관여하며, 복합적인 보안 설정 내에서 참조될 수 있습니다.
:::tip[Security Tip(팁)]
여러 보안 수준의 대상인 창과 WebView는 관련된 모든 보안 수준의 "접근 권한"과 "보안 경계"를 효과적으로 통합합니다.
:::
보안 수준을 기술하는 파일(Capability files)은 JSON 또는 TOML 파일로 `src-tauri/capabilities` 디렉토리 내에서 정의됩니다.
각 파일을 사용하여 `tauri.conf.json` 내에서 "식별자"로만 참조하는 것이 일반적인 방법이지만, 이 두 가지를 `capabilities` 필드에서 직접 정의할 수도 있습니다.
`capabilities` 디렉토리 내의 모든 보안 수준 기능은 기본적으로 자동으로 활성화됩니다. 일단 `tauri.conf.json`에서 보안 수준 기능이 명시적으로 활성화되면, 애플리케이션 빌드에서는 해당 기능만 사용됩니다.
체계적인 설정 항목에 대한 자세한 내용은 [참고 정보](/ko/reference/config/) 항목을 참조하십시오.
다음 JSON 예제는 코어 플러그인과 `window.setTitle` API에 대한 기본 기능을 활성화하는 보안 수준 설정을 정의합니다.
```json title="src-tauri/capabilities/default.json"
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:path:default",
"core:event:default",
"core:window:default",
"core:app:default",
"core:resources:default",
"core:menu:default",
"core:tray:default",
"core:window:allow-set-title"
]
}
```
이 스니펫(발췌 내용)은 [Tauri Configuration](/ko/develop/configuration-files/#tauri-설정) 파일의 일부입니다.
이것이 아마도 가장 일반적인 설정 방법으로, 개별 보안 수준을 행 내에 포함(인라인화)하고 접근 권한만 "식별자"로 참조합니다.
이를 위해서는 적절하게 정의된 기능 파일이 `capabilities` 디렉토리 내에 필요합니다.
```json title=src-tauri/tauri.conf.json
{
"app": {
"security": {
"capabilities": ["my-capability", "main-capability"]
}
}
}
```
인라인화된 "보안 수준" 설정은 사전에 정의된 "보안 수준" 설정과 함께 사용할 수도 있습니다.
```json title=src-tauri/tauri.conf.json
{
"app": {
"security": {
"capabilities": [
{
"identifier": "my-capability",
"description": "My application capability used for all windows",
"windows": ["*"],
"permissions": ["fs:default", "allow-home-read-extended"]
},
"my-second-capability"
]
}
}
}
```
## 대상 플랫폼
"보안 수준"은 "`platforms` 배열"을 정의하여 각 플랫폼별로 설정할 수 있습니다.
기본적으로 "보안 수준" 설정은 모든 대상에 적용되지만, `linux`, `macOS`, `windows`, `iOS`, `android`의 각 대상 OS를 하위 집합으로 선택할 수 있습니다.
다음 예는 데스크톱 운영 체제용 "보안 수준" 설정입니다.
이 설정에서는 데스크톱에서만 사용할 수 있는 플러그인의 접근 권한을 활성화하는 것에 주목하십시오:
```json title="src-tauri/capabilities/desktop.json"
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-capability",
"windows": ["main"],
"platforms": ["linux", "macOS", "windows"],
"permissions": ["global-shortcut:allow-register"]
}
```
모바일 기기용 "보안 수준" 설정 사례는 다음과 같습니다.
이 설정에서는 모바일 OS에서만 사용할 수 있는 플러그인의 접근 권한을 활성화하는 것에 주목하십시오:
```json title="src-tauri/capabilities/mobile.json"
{
"$schema": "../gen/schemas/mobile-schema.json",
"identifier": "mobile-capability",
"windows": ["main"],
"platforms": ["iOS", "android"],
"permissions": [
"nfc:allow-scan",
"biometric:allow-authenticate",
"barcode-scanner:allow-scan"
]
}
```
## 원격 API 액세스
기본적으로 API는 Tauri 앱에 번들된 코드에만 액세스할 수 있습니다.
원격 소스가 특정 Tauri 명령에 액세스할 수 있도록 하려면 보안 수준 설정 파일에서 정의해야 합니다.
다음 예에서는 NFC 태그를 스캔하고 `tauri.app`의 모든 하위 도메인에서 바코드 스캐너를 사용할 수 있도록 합니다.
```json title="src-tauri/capabilities/remote-tags.json"
{
"$schema": "../gen/schemas/remote-schema.json",
"identifier": "remote-tag-capability",
"windows": ["main"],
"remote": {
"urls": ["https://*.tauri.app"]
},
"platforms": ["iOS", "android"],
"permissions": ["nfc:allow-scan", "barcode-scanner:allow-scan"]
}
```
:::caution[(경고)]
Linux 및 Android에서는 Tauri가 내장된 `<iframe>` 태그로부터의 요청과 창 자체로부터의 요청을 구별할 수 없습니다.
이 "원격 API 액세스" 기능의 변경에 대해서는 충분히 주의하고, 이 기능에 관한 "참고 정보 References" 섹션에서 대상 운영 체제별 보안상의 영향에 대해 자세히 이해한 후 수행하십시오.
:::
## 보안 경계 Security Boundaries
_어떤 것으로부터 보호받을 수 있을까요?_
"접근 권한"과 "보안 수준"에 따라 다음이 가능해집니다:
- 프론트엔드에서의 "보안 침해" 영향을 최소화합니다
- 로컬 시스템 인터페이스와 데이터의 (우발적인) "유출"을 방지하거나 완화합니다
- 프론트엔드에서 백엔드/시스템으로의 "권한 상승"을 방지하거나 완화합니다
_어떤 것으로부터는 보호받지 **못할까요**?_
- 악의적이거나 안전하지 않은 "Rust 코드"
- 너무 느슨한 "범위(적용 범위)"와 "설정 내용"
- 명령 구현에서의 부정확한 "범위 검사"
- Rust 코드로부터의 "의도적인 이탈"
- 기본적으로 앱의 Rust Core에 작성된 "모든 것"
- 시스템 WebView 내의 "제로데이 공격" 또는 패치 미적용 "원데이 공격"
- "공급망 공격" 또는 "부정 침입된 개발자 시스템"
:::tip[Security Tip(팁)]
보안 경계는 "창 레이블"(**"제목"이 아님**)에 의존합니다.
창 생성 기능은 더 높은 권한을 가진 창에 대해서만 적용 가능하도록 권장합니다.
:::
## 스키마 파일
Tauri는 애플리케이션에서 사용 가능한 모든 접근 권한을 가진 "JSON 스키마"를 생성하므로, 사용하는 IDE(통합 개발 환경)에서 자동 완성을 수행할 수 있습니다.
스키마를 사용하려면 "설정" 내의 `$schema` 속성을 `gen/schemas` 디렉토리에 있는 플랫폼별 스키마 중 하나로 설정합니다.
일반적으로 `../gen/schemas/desktop-schema.json` 또는 `../gen/schemas/mobile-schema.json`으로 설정하지만, 특정 대상 플랫폼용 보안 수준을 정의할 수도 있습니다.
## 설정 파일
Tauri 애플리케이션의 디렉토리 구조 예(간략판):
```sh
tauri-app
├── index.html
├── package.json
├── src
├── src-tauri
│ ├── Cargo.toml
│ ├── capabilities
│ └── <identifier>.json/toml
│ ├── src
│ ├── tauri.conf.json
```
모든 항목을 `tauri.conf.json`에 인라인화할 수 있지만, 약간 고급 설정을 하면 이 파일이 비대해집니다.
이 방식의 목표는 접근 권한을 가능한 한 단순화하고 이해하기 쉽게 만드는 것입니다.
## 코어 접근 권한
모든 코어 접근 권한 목록은 "참고 정보 References"의 [코어 접근 권한](/ko/reference/acl/core-permissions/) 페이지에 있습니다.

View File

@@ -0,0 +1,40 @@
---
title: 콘텐츠 보안 정책(CSP)
sidebar:
order: 6
i18nReady: true
---
Tauri는 HTML 페이지의 [콘텐츠 보안 정책](CSP)을 제한합니다.
이를 사용하면 크로스 사이트 스크립팅(XSS)과 같은 일반적인 웹 기반 취약점의 영향을 완화하거나 방지할 수 있습니다.
로컬 스크립트는 해시 처리되고, 스타일과 외부 스크립트는 "일회용 암호화 난수 데이터(nonce)"를 사용하여 참조되므로 허가되지 않은 콘텐츠가 로드되는 것을 방지할 수 있습니다.
:::caution[(경고)]
CDN(콘텐츠 전송 네트워크)을 통해 제공되는 스크립트와 같은 원격 콘텐츠는 "공격 벡터"(진입 경로)를 가져올 수 있으므로 로드를 피해야 합니다.
일반적으로 신뢰할 수 없는 파일은 모두 새로운 교묘한 공격 벡터의 침입을 허용할 수 있습니다.
:::
CSP(콘텐츠 보안 정책)에 의한 보호는 Tauri 설정 파일에 등록된 경우에만 유효합니다.
따라서 가능한 한 대상을 좁혀 Webview가 신뢰할 수 있는 호스트(가급적이면 자신이 소유한 호스트)의 자산만 로드하도록 해야 합니다.
컴파일 시 Tauri는 번들된 코드와 자산에 대해 관련 CSP 속성에 nonce 값과 해시 값을 자동으로 추가하므로, 직접 고려해야 할 것은 애플리케이션에 고유한 것뿐입니다.
다음 CSP 설정 예는 Tauri의 [`api`](https://github.com/tauri-apps/tauri/blob/dev/examples/api/src-tauri/tauri.conf.json#L22) 예제에서 발췌한 것입니다.
애플리케이션 개발자는 이 내용을 각자의 애플리케이션 요구에 맞게 조정해야 합니다.
```json title="tauri/examples/api/src-tauri/tauri.conf.json"
"csp": {
"default-src": "'self' customprotocol: asset:",
"connect-src": "ipc: http://ipc.localhost",
"font-src": ["https://fonts.gstatic.com"],
"img-src": "'self' asset: http://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com"
},
```
이 CSP(콘텐츠 보안 정책)에 의한 보호 방식에 대한 자세한 내용은 [`script-src`], [`style-src`] 및 [CSP Sources]를 참조하십시오.
[콘텐츠 보안 정책]: https://developer.mozilla.org/ko/docs/Web/HTTP/CSP
[`script-src`]: https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
[`style-src`]: https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
[CSP Sources]: https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Security-Policy/Sources#sources

View File

@@ -0,0 +1,39 @@
---
title: Tauri 생태계 보안
sidebar:
order: 8
i18nReady: true
---
Tauri의 조직 "생태계"(활동 협력 체제)는 GitHub에서 호스팅되며, 소스 코드나 릴리스 버전을 대상으로 하는 외부의 적으로부터 리포지토리의 내성을 높이기 위한 몇 가지 기능을 갖추고 있습니다.
위험을 줄이고 일반적으로 채택되는 모범 사례(최우수 사례)를 따르기 위해 다음과 같은 방법을 도입했습니다.
### 빌드 파이프라인(빌드 검증 자동화)
소스 코드 결과물을 릴리스하는 프로세스는 GitHub 액션을 사용한 GitHub 빌드 파이프라인으로 고도로 자동화되어 있지만, 실제 사람에 의한 시작(작업 시작)과 검토(심사)를 의무화하고 있습니다.
### 서명된 커밋
Tauri의 핵심 리포지토리에서는 "스푸핑(위장)" 위험을 줄이고, 보안 침해 가능성을 탐지했을 때 그 원인으로 생각되는 커밋을 식별할 수 있도록 서명된 커밋이 필요합니다.
### 코드 검토
Tauri의 리포지토리에 병합되는 모든 "풀 리퀘스트(PR)"에는 해당 프로젝트(대부분의 경우 워킹 그룹이지만)의 최소 한 명의 유지 관리자로부터 승인이 필요합니다.
코드는 일반적으로 PR에서 검토되며, 기본 보안 워크플로와 검사가 실행되어 코드가 공통 표준을 준수하는지 확인합니다.
### 릴리스 프로세스
Tauri의 워킹 그룹은 코드 변경 내용을 검토하고, PR에 범위(적용 범위) 태그를 지정하고, 모든 것이 최신 상태로 유지되는지 확인합니다.
또한 마이너 릴리스와 메이저 릴리스를 공개하기 전에 보안과 관련된 모든 PR을 내부적으로 감사하도록 노력하고 있습니다.
새 버전을 공개할 시기가 되면, 유지 관리자 중 한 명이 새 릴리스에 "dev(개발 버전)" 태그를 지정하고 다음 절차가 실행됩니다:
- 코어 검증
- 평가 시험 실시
- 크레이트 및 npm 보안 감사
- 변경 로그 작성
- 결과물(아티팩트) 생성
- 초안 버전 작성
그런 다음 유지 관리자가 릴리스 노트를 확인하고 필요에 따라 편집한 후 새 릴리스가 완성됩니다.

View File

@@ -0,0 +1,62 @@
---
title: 앞으로의 과제
sidebar:
order: 10
i18nReady: true
---
이 섹션에서는 Tauri 앱을 더욱 안전하게 만들기 위해 시작한 프로젝트나 앞으로 다루고 싶은 내용에 대해 설명합니다.
이러한 프로젝트에 관심이 있거나 어떤 지식이 있는 경우, GitHub나 Discord와 같은 다른 커뮤니티 플랫폼을 통해 연락 주시기 바랍니다. 새로운 기여자나 새로운 조언은 언제나 환영합니다.
### 바이너리 분석
침투 테스트 담당자, 감사 담당자, 자동 보안 검사가 제대로 역할을 수행하려면 컴파일된 바이너리에서도 통찰력을 얻는 것이 매우 중요합니다. 모든 기업이 오픈 소스인 것은 아니며, 감사, 레드팀, 기타 보안 테스트용 소스 코드를 제공하는 것도 아닙니다.
> > > 《번역 주》
> > > ・침투 테스트 담당자: pentester = penetration tester
> > > ・레드팀: red team(보안 취약점을 검증하는 사내 전담팀)
간과하기 쉬운 또 다른 점은 Tauri 고유의 메타데이터를 제공함으로써 해당 애플리케이션의 사용자들이 평생과 노력을 알려진 취약점 해결에 바치지 않고도 자신의 시스템을 알려진 취약점에 대해 더 큰 규모로 감사할 수 있게 된다는 것입니다.
> > > 《번역 주》 **Tauri 고유의 메타데이터** 원문은 "inbuilt metadata". inbuilt는 "본래 갖추어진", "고유한", "본질적인"의 의미인 것 같지만, "내장", "내장된"(= built-in)의 의미도 함축하고 있을 수 있습니다. 본고에서는 "Tauri 고유/특유의"로 해석했습니다.
사용하는 "위협 모델"이 "은폐에 의한 보안"에 의존하고 있다면, 아래에 도구나 포인트를 몇 가지 제안하므로 위협 모델을 재검토해 주시기 바랍니다.
> > > 《번역 주》 **은폐에 의한 보안** 설계나 구현을 비공개로 함으로써 보안을 확보하는 방법. 이 방법은 비공개 정보가 유출되었을 때의 방어 수단이 존재하지 않으므로 권장되지 않습니다. Security Through Obscurity (STO)라고도 표기합니다.
Rust에는 [SBOM/소프트웨어 부품 명세서](https://ko.wikipedia.org/wiki/소프트웨어_공급망)를 만들기 위한 `cargo-auditable`이 있으며, 재현 가능한 빌드를 손상시키지 않고 바이너리의 정확한 크레이트 버전과 종속성 정보를 제공합니다.
프론트엔드 스택에 대해서는 비슷한 방법을 모르므로, 바이너리에서 프론트엔드 자산을 추출하는 것은 간단명료한 프로세스여야 합니다.
그런 다음 `npm Audit`과 같은 도구를 사용할 수 있게 될 것입니다.
이 추출 프로세스에 대한 [블로그 게시물](https://infosecwriteups.com/reverse-engineering-a-native-desktop-application-tauri-app-5a2d92772da5)은 이미 있지만, 간편한 도구는 없습니다.
Tauri에서는 특정 기능을 갖춘 Tauri 앱을 컴파일할 때 그러한 도구를 제공하거나 자산 추출을 용이하게 할 계획입니다.
[Burpsuite](https://portswigger.net/burp), [Zap](https://www.zaproxy.org/) 또는 [Caido](https://caido.io/)와 같은 "침투 테스트(pentesting)" 도구를 이용하려면, Webview로부터의 트래픽을 가로채고 테스트 프록시를 통과시켜야 합니다.
현재 Tauri에는 이를 실행하기 위한 Tauri 고유의 메서드는 없지만, 이 프로세스를 쉽게 수행하기 위한 작업이 진행 중입니다.
이러한 도구는 모두 소스 코드에 액세스하지 않고도 Tauri 애플리케이션을 적절하게 테스트하고 검사할 수 있으므로, Tauri 애플리케이션을 빌드할 때 고려해야 할 사항입니다.
Tauri는 앞으로도 관련 기능의 추가 지원과 구현을 계획하고 있습니다.
### WebView 강화
Tauri의 현재 "위협 모델"이나 Tauri가 참조하는 "영역 경계" 내에서는 WebView 자체에 추가적인 보안 제약을 추가할 수 없습니다. 또한 WebView는 메모리 안전성이 없는 언어로 작성된 스택(임시 저장 영역)의 가장 큰 부분이므로, WebView 프로세스를 더욱 샌드박스화하고 격리하는 방법을 조사하고 검토할 예정입니다.
> > > 《번역 주》 **영역 경계** 원문 "boundaries" 구체적으로 "무엇의" 경계인지는 불분명하지만, 여기서는 Tauri가 다룰 수 있는 범위의 경계로 해석했습니다. **메모리 불안전 언어** 원문 "an memory unsafe language" 메모리 액세스 시 프로그래밍 오류 방지 기능이나 제약이 결여된 프로그래밍 언어. 《참고》 위 내용에 대한 기본 정보는 Wikipedia의 "[메모리 안전성](https://ko.wikipedia.org/wiki/메모리_안전성)" 항목을 참조하십시오.
보안 공격의 영향을 완화하고 시스템 액세스용 IPC 브리지(프로세스 간 연결)를 강화하기 위해, Tauri 고유 및 외부의 샌드박스 방식을 평가할 예정입니다.
스택의 이 부분이 약점이라고 생각하지만, 현 세대의 WebView에서는 보안 강화와 익스플로잇 내성(보안 취약점 공격에 대한 내성)이 향상되었습니다.
### 퍼징(Fuzzing)
> > > 《번역 주》 **퍼징** 퍼즈 테스트. 컴퓨터 프로그램 검증 프로세스 중 하나. 유효하지 않거나, 예기치 않거나, 무작위 데이터(fuzz라고 함)를 입력하여 의도적으로 예외 상태를 발생시켜 시스템을 검증하는 방법. 자세한 내용은 Wikipedia의 "[퍼징](https://ko.wikipedia.org/wiki/퍼징)" 등을 참조하십시오.
Tauri 애플리케이션의 퍼징 프로세스를 더 효율적이고 간소화하기 위해, "모의 런타임"이나 기타 도구를 추가로 구현하여 개별 Tauri 애플리케이션의 설정이나 빌드를 용이하게 하는 것을 목표로 하고 있습니다.
Tauri는 다수의 운영 체제와 CPU 아키텍처를 지원하며, 일반적으로 앱에는 메모리 안전성이 없는 코드가 포함될 가능성이 거의 없거나 전혀 없습니다.
기존의 퍼징 도구나 라이브러리에서는 이러한 드문 퍼징의 "사용 사례"에 대응하지 않으므로, Tauri 퍼징 프레임워크를 구축하려면 이를 구현하고 [libAFL](https://github.com/AFLplusplus/LibAFL)과 같은 기존 라이브러리를 지원해야 합니다.
> > > 《번역 주》 **사용 사례**(use case) 사용자가 시스템을 이용하여 달성하는 구체적인 목표나 일련의 조작을 기술하고, 시스템에 필요한 기능 요구 사항을 명확히 한 것. 자세한 내용은 Wikipedia의 "사용 사례"(https://ko.wikipedia.org/wiki/유스_케이스) 등을 참조하십시오.
목표는 퍼징을 Tauri 애플리케이션 개발자에게 접근하기 쉽고 효율적으로 만드는 것입니다.

View File

@@ -0,0 +1,316 @@
---
title: HTTP 헤더
author: 39zde <git@39zde>
sidebar:
order: 7
badge:
text: New
variant: tip
i18nReady: true
---
import SinceVersion from '@components/SinceVersion.astro';
<SinceVersion version="2.1.0" />
"설정" 내에 정의된 헤더는 Webview에 대한 응답과 함께 전송됩니다.
여기에는 "IPC(프로세스 간 통신)" 메시지와 "오류 응답"은 포함되지 않습니다.
더 구체적으로 말하면,
<a
href="https://github.com/tauri-apps/tauri/blob/8e8312bb8201ccc609e4bbc1a990bdc314daa00f/crates/tauri/src/protocol/tauri.rs#L103"
target="\_blank"
>
{' '}
crates/tauri/src/protocol/tauri.rs ↗
</a>
의 `get_response`
함수를 통해 전송되는 모든 응답에 이 헤더가 포함됩니다.
### 헤더 이름
"헤더 이름"은 다음과 같이 제한됩니다:
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials"
target="_blank"
>
Access-Control-Allow-Credentials ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Allow-Headers"
target="_blank"
>
Access-Control-Allow-Headers ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Allow-Methods"
target="_blank"
>
Access-Control-Allow-Methods ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Expose-Headers"
target="_blank"
>
Access-Control-Expose-Headers ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Access-Control-Max-Age"
target="_blank"
>
Access-Control-Max-Age ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy"
target="_blank"
>
Cross-Origin-Embedder-Policy ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy"
target="_blank"
>
Cross-Origin-Opener-Policy ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy"
target="_blank"
>
Cross-Origin-Resource-Policy ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Permissions-Policy"
target="_blank"
>
Permissions-Policy ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Timing-Allow-Origin"
target="_blank"
>
Timing-Allow-Origin ↗
</a>
- <a
href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Content-Type-Options"
target="_blank"
>
X-Content-Type-Options ↗
</a>
- Tauri-Custom-Header
:::note[(참고)]
`Tauri-Custom-Header`는 프로덕션 환경에서 사용하기 위한 것이 아닙니다.
:::
:::note[(참고)]
<a href="../ko/csp/">콘텐츠 보안 정책(CSP)</a>
은 여기에서 정의되지 않습니다.
:::
### 헤더 설정 방법
- 문자열로
- 문자열 배열로
- 객체/키-값으로 (값은 문자열이어야 합니다)
- null 값으로
실제 응답에서는 헤더 값이 항상 문자열로 변환됩니다. 설정 파일의 내용에 따라 헤더 값 중 일부를 만들어야 할 수도 있습니다.
이 복합 값이 어떻게 만들어지는지에 대한 규칙은 다음과 같습니다:
- `string`: "문자열"의 경우, 생성된 헤더 값도 동일한 내용입니다.
- `Array`: "배열"의 경우, 생성된 헤더 값에서는 각 항목(요소)이 `, `로 연결됩니다.
- `key-value`: "키-값"에서는 각 항목이 "키 + 공백 + 값"으로 만들어진 후, 생성된 헤더 값에서는 각 항목이 `; `로 연결됩니다.
- `null`: "null 값"의 경우, 헤더는 무시됩니다.
### 설정 예
```javascript title="src-tauri/tauri.conf.json"
{
//...
"app":{
//...
"security": {
//...
"headers": {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
"Timing-Allow-Origin": [
"https://developer.mozilla.org",
"https://example.com",
],
"X-Content-Type-Options": null, // gets ignored
"Access-Control-Expose-Headers": "Tauri-Custom-Header",
"Tauri-Custom-Header": {
"key1": "'value1' 'value2'",
"key2": "'value3'"
}
},
// CSP가 헤더 항목 내에 정의되지 않았음에 유의하십시오.
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost",
}
}
}
```
:::note[(참고)]
`Tauri-Custom-Header`는 프로덕션 환경에서 사용하기 위한 것이 아닙니다.
테스트에서는 `Access-Control-Expose-Headers`를 적절하게 설정하는 것을 잊지 마십시오.
:::
이 예에서는 `Cross-Origin-Opener-Policy`와 `Cross-Origin-Embedder-Policy`가 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer" target="_blank">`SharedArrayBuffer ↗`</a>의 사용을 허용하도록 설정되어 있습니다.
`Timing-Allow-Origin`은 목록에 기재된 웹 사이트에서 로드된 스크립트가 <a href="https://developer.mozilla.org/ko/docs/Web/API/Performance_API/Resource_timing" target="_blank">Resource Timing API(리소스 타이밍) ↗</a>를 통해 상세한 네트워크 타이밍 데이터에 액세스하는 것을 허용합니다.
"helloworld" 예제에서는 설정이 다음과 같이 됩니다:
```http
access-control-allow-origin: http://tauri.localhost
access-control-expose-headers: Tauri-Custom-Header
content-security-policy: default-src 'self'; connect-src ipc: http://ipc.localhost; script-src 'self' 'sha256-Wjjrs6qinmnr+tOry8x8PPwI77eGpUFR3EEGZktjJNs='
content-type: text/html
cross-origin-embedder-policy: require-corp
cross-origin-opener-policy: same-origin
tauri-custom-header: key1 'value1' 'value2'; key2 'value3'
timing-allow-origin: https://developer.mozilla.org, https://example.com
```
### 프레임워크
일부 개발 환경에서는 운영 환경을 에뮬레이트하기 위한 추가 설정이 필요합니다.
#### JavaScript/TypeScript
빌드 도구 "**Vite**"(**Qwik, React, Solid, Svelte, Vue** 포함)를 실행하는 설정 도구에는 필요한 헤더를 `vite.config.ts`에 추가합니다.
```typescript title=vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
// ...
server: {
// ...
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
'Timing-Allow-Origin':
'https://developer.mozilla.org, https://example.com',
'Access-Control-Expose-Headers': 'Tauri-Custom-Header',
'Tauri-Custom-Header': "key1 'value1' 'value2'; key2 'value3'",
},
},
});
```
경우에 따라 `vite.config.ts`가 프레임워크 설정 파일에 통합되어 있을 수 있지만, 설정 내용은 동일합니다.
프론트엔드 프레임워크가 **Angular**인 경우, 필요한 헤더를 `angular.json`에 추가합니다.
```json title=angular.json
{
//...
"projects": {
//...
"insert-project-name": {
//...
"architect": {
//...
"serve": {
//...
"options": {
//...
"headers": {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
"Timing-Allow-Origin": "https://developer.mozilla.org, https://example.com",
"Access-Control-Expose-Headers": "Tauri-Custom-Header",
"Tauri-Custom-Header": "key1 'value1' 'value2'; key2 'value3'"
}
}
}
}
}
}
}
```
마찬가지로, **Nuxt**의 경우 `nuxt.config.ts`에 추가합니다.
```typescript title=nuxt.config.ts
export default defineNuxtConfig({
//...
vite: {
//...
server: {
//...
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
'Timing-Allow-Origin':
'https://developer.mozilla.org, https://example.com',
'Access-Control-Expose-Headers': 'Tauri-Custom-Header',
'Tauri-Custom-Header': "key1 'value1' 'value2'; key2 'value3'",
},
},
},
});
```
**Next.js**는 Vite를 사용하지 않으므로 접근 방식이 다릅니다.
자세한 내용은 <a href="https://nextjs.org/docs/pages/api-reference/next-config-js/headers" target="_blank">여기 ↗</a> (영어)를 참조하십시오.
헤더는 `next.config.js`에서 정의합니다.
```javascript title=next.config.js
module.exports = {
//...
async headers() {
return [
{
source: '/*',
headers: [
{
key: 'Cross-Origin-Opener-Policy',
value: 'same-origin',
},
{
key: 'Cross-Origin-Embedder-Policy',
value: 'require-corp',
},
{
key: 'Timing-Allow-Origin',
value: 'https://developer.mozilla.org, https://example.com',
},
{
key: 'Access-Control-Expose-Headers',
value: 'Tauri-Custom-Header',
},
{
key: 'Tauri-Custom-Header',
value: "key1 'value1' 'value2'; key2 'value3'",
},
],
},
];
},
};
```
#### Rust
**Yew**와 **Leptos**에서는 헤더를 `Trunk.toml`에 추가하십시오:
```toml title=Trunk.toml
#...
[serve]
#...
headers = {
"Cross-Origin-Opener-Policy" = "same-origin",
"Cross-Origin-Embedder-Policy" = "require-corp",
"Timing-Allow-Origin" = "https://developer.mozilla.org, https://example.com",
"Access-Control-Expose-Headers" = "Tauri-Custom-Header",
"Tauri-Custom-Header" = "key1 'value1' 'value2'; key2 'value3'"
}
```

View File

@@ -0,0 +1,116 @@
---
title: 보안
sidebar:
order: 1
label: Overview
i18nReady: true
---
import { CardGrid, LinkCard } from '@astrojs/starlight/components';
이 섹션에서는 Tauri의 설계와 생태계의 핵심을 이루는 고수준의 개념과 보안 기능을 설명하는 것을 목적으로 합니다. 이 개념과 보안 기능은 개발자인 여러분 자신, 만드는 애플리케이션, 그리고 그 사용자의 보안을 기본적으로 강화합니다.
또한, "모범 사례"(최고의 실천 모델)에 대한 조언, 취약점을 Tauri 팀에 보고하는 방법, 그리고 상세한 개념 설명에 대한 참고 정보도 언급되어 있습니다.
:::note
Tauri 애플리케이션의 보안은 Tauri 자체의 전반적인 보안, Rust 및 npm의 모든 종속성, 여러분 자신의 코드, 그리고 최종 애플리케이션을 실행하는 장치, 이 모든 것의 보안의 총합이라는 것을 기억하는 것이 중요합니다.
Tauri 팀은 팀으로서의 역할에 최선을 다하고, 보안 커뮤니티도 그 역할을 다하므로, 여러분 자신도 몇 가지 중요한 "모범 사례"의 방식을 따라해 보십시오.
:::
## 신뢰 경계 Trust Boundaries
> "신뢰 경계/트러스트 바운더리"는 컴퓨터 과학 및 보안 분야에서 사용되는 용어로, 프로그램 데이터 또는 실행 프로그램의 "신뢰" 수준이 바뀌는 경계선, 또는 다른 보안 수준<sup>※</sup>을 가진 두 개의 동작 주체("보안 주체")가 데이터나 명령을 주고받을 때의 신뢰 수준 한계선을 말합니다.
> [^wikipedia-trust-boundary](영어)
[^wikipedia-trust-boundary]: [https://en.wikipedia.org/wiki/Trust_boundary](https://en.wikipedia.org/wiki/Trust_boundary).
> > > 《번역 주》 **보안 수준** 원문 different **capabilities**(다른 **기능**)의 번역. 구체적인 의미 내용이 불분명하여 Wikipedia 중국어판의 표기 "**신뢰 수준**이 다른 두 시스템이..."(Google 번역에 따름)에 근거하여 "보안 수준"으로 번역했습니다. [보안 수준](/ko/security/capabilities/)을 참조하십시오.
Tauri의 보안 모델은 애플리케이션의 코어용으로 작성된 "Rust 코드" 부분과, 시스템 WebView가 이해할 수 있는 모든 프레임워크 또는 언어로 작성된 "프론트엔드 코드" 부분으로 나뉩니다.
경계 간에 주고받는 모든 데이터를 검사하고 엄격하게 정의하는 것은 "신뢰 경계 침해"(violation)를 방지하기 위해 매우 중요합니다. 만약 데이터가 "접근 제어 없이" 경계선을 넘나들면, 공격자에게는 권한을 상승시켜 악용하기가 쉬워집니다.
[IPC 레이어](/ko/concept/inter-process-communication/) (프로세스 간 통신)는 이 두 신뢰 그룹 간의 통신 다리 역할을 하여 경계가 깨지지 않도록 합니다.
![IPC Diagram](@assets/security/tauri-trust-boundaries.svg)
> > > 《번역 주》 그림 속 용어
> > > **System WebView** 시스템 웹뷰
> > > ・ Application Frontend 애플리케이션 프론트엔드
> > > ・ Remote Sources & Assets 원격 소스 및 자산
> > > **IPC** 프로세스 간 통신
> > > **Application Core** 애플리케이션 코어
> > > ・ Tarui Core 타우리 코어부
> > > ・ Backend 백엔드
> > > ・ Plugins 플러그인
> > > ・ Local System 로컬 시스템
플러그인 또는 애플리케이션 코어에 의해 실행되는 코드는 사용 가능한 모든 시스템 리소스에 완전히 액세스할 수 있으며 제약이 없습니다.
WebView에서 실행되는 코드는 공개된 시스템 리소스에만 명확하게 정의된 IPC 레이어를 통해 액세스할 수 있습니다.
코어 애플리케이션 명령에 대한 액세스는 애플리케이션 설정에 정의된 보안 수준에 따라 설정 및 제한됩니다.
개별 명령 구현은 이 또한 "보안 수준 설정"에서도 정의된 임의 설정의 세분화된 액세스 수준을 적용합니다.
각 구성 요소와 경계 적용에 대한 자세한 내용은 다음을 참조하십시오:
<CardGrid>
<LinkCard title="접근 권한" href="/ko/security/permissions/" />
<LinkCard title="범위" href="/ko/security/scope/" />
<LinkCard title="보안 수준" href="/ko/security/capabilities/" />
<LinkCard title="런타임 통제" href="/ko/security/runtime-authority/" />
</CardGrid>
Tauri에서는 개발자가 고유한 프론트엔드 스택과 프레임워크를 선택할 수 있습니다.
이는 Tauri가 선택된 개별 프론트엔드 스택에 대한 보안 강화 가이드를 제공할 수 없다는 것을 의미하는 것이 아니라, Tauri가 공격 대상 영역을 제어하고 봉쇄하기 위한 포괄적인 기능을 제공한다는 것을 의미합니다.
<CardGrid>
<LinkCard title="콘텐츠 보안 정책(CSP)" href="/ko/security/csp/" />
<LinkCard
title="격리형"
href="/ko/concept/inter-process-communication/isolation/"
/>
</CardGrid>
## WebViews 번들링 "없음"
Tauri의 접근 방식은 운영 체제에 포함된 WebView에 의존하고 WebView를 애플리케이션 바이너리에 번들링하지 않는 것입니다.
여기에는 여러 가지 이유가 있지만, 보안 관점에서 가장 중요한 이유는 WebView의 보안 패치가 공개된 후 애플리케이션의 최종 사용자에게 배포되기까지 걸리는 평균 시간입니다.
![IPC Diagram](@assets/security/tauri-update-lag.svg)
> > > 《번역 주》 그림: WebView 번들 유무에 따른 보안 업데이트 시간 차이
관찰한 바에 따르면, WebView 패킷 유지 관리자와 운영 체제 패킷 유지 관리자는 WebView를 애플리케이션에 직접 번들링하는 애플리케이션 개발자보다 보안 패치를 적용하고 Webview 릴리스를 배포하는 속도가 평균적으로 훨씬 빠릅니다.
이 관찰에는 예외가 있으며, 이론적으로는 두 방법 모두 비슷한 시간 내에 실행할 수 있지만, 그러려면 각 애플리케이션에 대해 부수적인 비용이 더 큰 인프라가 필요합니다.
Tauri 애플리케이션 개발자의 경험상, 번들링에는 나쁜 면이 있습니다. 그것이 본질적으로 안전하지 않다고 생각하는 것은 아니지만, 현재의 설계 사양은 현실의 알려진 취약점을 대폭 줄이기 위한 트레이드오프(타협점)입니다.
## 생태계
Tauri의 조직은 단순히 Tauri 리포지토리만 제공하고 유지 관리하는 것이 아니라, 합리적이고 안전한 멀티플랫폼 애플리케이션 프레임워크를 확실히 제공하기 위해 더 나아가 노력하고 있습니다.
개발 프로세스의 보안 확보 방법, 적용 및 구현할 수 있는 내용, 애플리케이션이 직면할 수 있는 알려진 위협, 향후 개선 및 강화 계획 등에 대해 자세히 알고 싶다면 다음 문서를 참조하십시오:
<CardGrid>
<LinkCard title="생태계 보안" href="/ko/security/ecosystem/" />
<LinkCard
title="애플리케이션 라이프사이클에서의 위협"
href="/ko/security/lifecycle/"
/>
<LinkCard title="앞으로의 과제" href="/ko/security/future/" />
</CardGrid>
## 협력적 정보 공개
Tauri 또는 기타 리포지토리에 보안상의 우려나 문제가 있다고 생각되는 경우, **발견한 사항에 대해 공개적으로 언급하지 마십시오**. 대신 직접 Tauri의 보안팀에 연락하십시오.
권장되는 보고 방법은 영향을 받는 리포지토리의 [Github Vulnerability Disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) (Github 취약점 보고)를 통하는 것입니다.
Tauli의 대부분의 리포지토리에서는 이 연락 기능이 활성화되어 있지만, 잘 모르는 경우에는 [Tauri 리포지토리](https://github.com/tauri-apps/tauri/security/advisories/new)에서 보내주십시오.
또는 [security@tauri.app](mailto:security@tauri.app)으로 이메일을 보내실 수도 있습니다.
현재 보안 포상금 예산은 없지만, 경우에 따라 제한된 리소스 내에서 협력적인 정보 공개에 보상을 주는 것도 검토합니다.

View File

@@ -0,0 +1,152 @@
---
title: 애플리케이션 라이프사이클에서의 위협
sidebar:
order: 9
i18nReady: true
---
Tauri 애플리케이션은 애플리케이션 라이프사이클(제품 수명)의 다양한 시점에서 만들어진 수많은 부분으로 구성되어 있습니다.
여기서는 기존의 위협과 그에 대해 **어떻게 대처해야 하는지**에 대해 설명합니다.
그 개별적인 처리 절차를 모두 아래 각 섹션별로 설명합니다.
![Threat Stages During Development](@assets/concept/application-flow-simple.svg)
> > > Upstream: [상류 공정에서의 위협](#상류-공정에서의-위협)
> > > Development: [개발 시의 위협](#개발-시의-위협)
> > > Building: [빌드 시의 위협](#빌드-시의-위협)
> > > Distribution: [배포 시의 위협](#배포-시의-위협)
> > > Runtime: [실행 시의 위협](#실행-시의-위협)
:::note[(참고)]
애플리케이션 라이프사이클에서 가장 약한 연결 고리가 기본적으로 보안 내용을 결정하는 곳이 됩니다.
각 단계에서의 처리가 그 이후의 모든 단계의 전제와 정합성을 해칠 수 있으므로, 항상 전체 그림을 파악하는 것이 중요합니다.
:::
## 상류 공정에서의 위협
Tauri는 여러분의 프로젝트의 직접적인 의존 대상이며, 커밋, 검토, 풀 리퀘스트, 릴리스의 엄격한 작성자 관리를 수행하고 있으며,
종속성을 최신 상태로 유지하고 업데이트 또는 포크 수정을 수행하기 위한 조치를 취하는 데 최선을 다하고 있습니다. Tauri 이외에서 만드는 프로젝트에서는 그렇게 적절하게 관리되지 않고 감사도 한 번도 이루어지지 않았을 수 있습니다.
다른 프로젝트를 통합할 때는 그 건전성을 고려하십시오. 그렇지 않으면 모르는 사이에 아키텍처 유래의 "부채"를 떠안게 될 수 있습니다.
### 자신의 애플리케이션을 최신 상태로 유지하기
앱을 "야생에" 릴리스하는 경우, Tauri가 포함된 번들도 배송하게 됩니다.
Tauri에 영향을 미치는 취약점이 있다면 애플리케이션의 보안에도 영향을 미칠 수 있습니다.
Tauri를 최신 버전으로 업데이트하면 이미 중대한 취약점에 패치가 적용되어 애플리케이션에서 악용되지 않게 됩니다.
또한 컴파일러(`rustc`)와 트랜스파일러(`nodejs`)도 최신 상태로 유지하십시오. 보안 문제가 해결되는 경우가 많기 때문입니다.
이는 개발 시스템 전반에도 해당됩니다.
### 종속성 평가
NPM(Node Package Manager)과 Crates.io는 많은 유용한 패키지를 제공하지만,
신뢰할 수 있는 타사 라이브러리를 선택하는 것은 여러분의 책임입니다. 또는 Rust로 전부 다시 작성하십시오.
알려진 취약점의 영향을 받거나 유지 관리되지 않는 오래된 라이브러리를 사용하면 애플리케이션의 보안과 편안한 하룻밤의 잠이 위험에 처하게 될 수 있습니다.
이 프로세스를 자동화하기 위해 [`npm Audit`](https://docs.npmjs.com/cli/v10/commands/npm-audit)나 [`cargo Audit`](https://crates.io/crates/cargo-audit)과 같은 도구를 이용하고, 보안 커뮤니티의 중요한 노력에 의존하십시오.
[`cargo-vet`](https://github.com/mozilla/cargo-vet)이나 [`cargo crev`](https://github.com/crev-dev/cargo-crev)와 같은 Rust 생태계의 최근 경향은 공급망 공격의 가능성을 더욱 줄이는 데 도움이 될 것입니다.
자신이 누구의 어깨 위에 서 있는지, 즉 어떤 선구자의 지식을 이용하고 있는지 알기 위해서는 [`cargo supply chain`](https://github.com/rust-secure-code/cargo-supply-chain) 도구를 사용하십시오.
우리가 강력히 권장하는 방법은, 최선책으로 "리비전 해시 값(hash revisions)"을, 차선책으로 "이름 있는 태그(named tags)"를 사용하여 git에서 중요한 종속성만 사용하는 것입니다.
이는 Rust뿐만 아니라 Node 생태계에도 적용됩니다.
## 개발 시의 위협
개발자인 여러분은 개발 환경에 신경을 쓰고 있을 것입니다.
사용하는 운영 체제, 빌드 툴체인 및 관련 종속성이 최신 상태로 유지되고 적절하게 보호되는지 확인하는 것은 사용자인 여러분의 책임입니다.
우리 모두가 직면하고 있는 진정한 위험은 "공급망 공격"이라고 불리는 것으로, 이는 일반적으로 여러분의 프로젝트의 직접적인 종속성에 대한 공격으로 간주됩니다.
그러나 개발 머신을 직접 대상으로 하는 공격이巷에서 증가하고 있으므로, 이 문제에 정면으로 대처하고 대비합시다.
### 개발 서버
Tauri 애플리케이션의 프론트엔드는 다양한 웹 프레임워크를 사용하여 개발할 수 있습니다.
이러한 프레임워크는 모두 일반적으로 자체 개발 서버를 제공하며, 프론트엔드 자산은 열린 포트를 통해 로컬 시스템이나 네트워크에 공개됩니다.
이를 통해 프론트엔드를 Webview 또는 브라우저 내에서 "핫 리로드"(앱 실행 중 코드 변경 적용)하여 디버깅할 수 있습니다.
실제로 이 연결은 기본적으로 대부분 암호화되거나 인증되지 않습니다.
이는 내장된 Tauri 개발 서버에도 해당되며, 여러분의 프론트엔드와 자산이 로컬 네트워크에 공개됩니다. 또한 이를 통해 공격자는 공격자와 동일한 네트워크 내의 개발 장치에 공격자 자신의 프론트엔드 코드를 푸시할 수 있습니다.
어떤 기능, 내용이 공개되는지에 따라 다르지만, 최악의 경우 장치의 보안 침해로 이어질 수 있습니다.
개발 장치를 안전하게 공개할 수 있는 신뢰할 수 있는 네트워크에서만 개발을 수행해야 합니다.
그것이 불가능한 경우, 개발 서버가 개발 장치와의 연결에 **상호** 인증과 암호화(mTLS 등)를 사용하는지 **절대적으로** 확인하십시오.
> > > 《번역 주》mTLS = mutual Transport Layer Security: 상호 TLS 인증.
:::note[(참고)]
내장된 Tauri 개발 서버는 현재 "상호 인증"과 "전송 암호화"를 지원하지 않으므로 신뢰할 수 없는 네트워크에서는 사용하지 마십시오.
:::
### 개발 머신 강화
자신의 개발 시스템을 강화하는 것에 대해서는 다양한 요인과 개인의 위협 모델에 따라 다르지만, 일반적인 조언으로 다음과 같은 것을 권장합니다:
- 코딩과 같은 일상적인 작업에 관리자 계정을 사용하지 않기
- 개발 머신에서 프로덕션 환경의 비밀 정보를 사용하지 않기
- 비밀 정보를 소스 코드 버전 관리에서 검증하지 않기
- 보안 하드웨어 토큰 등을 사용하여 보안 침해된 시스템의 영향을 완화하기
- 자신의 시스템을 최신 상태로 유지하기
- 설치하는 애플리케이션을 최소한으로 줄이기
더 실용적인 방법에 대한 다양한 정보는 [훌륭한 보안 강화 컬렉션](https://github.com/decalage2/awesome-security-hardening) (영어 사이트)에서 볼 수 있습니다.
물론 자신의 개발 환경을 가상화하여 공격자를 막을 수도 있지만, 그것만으로는 개발 머신만을 대상으로 한 것이 아니라 프로젝트 자체를 대상으로 하는 공격에는 대처할 수 없습니다.
### 소스 관리 인증 및 승인 확실히 시행
대다수의 개발자와 작업하는 경우와 마찬가지로, 소스 코드 버전 관리 도구와 서비스 제공업체를 이용하는 것은 개발 중 필수적인 절차입니다.
소스 코드가 권한 없는 자에 의해 변경되지 않도록 하려면, 소스 코드 버전 관리 시스템의 접근 제어를 이해하고 올바르게 설정하는 것이 중요합니다.
또한 악의적인 커밋이 보안 침해를 받지 않았거나 악의가 없는 기여자에 의한 것으로 오인되는 상황을 방지하기 위해, 모든 (평소의) 기여자에게 커밋에 서명하도록 요청하는 것을 고려하십시오.
## 빌드 시의 위협
현대 시스템 개발에서는 바이너리 결과물을 만들기 위해 "CI/CD"(지속적 통합/지속적 배포)라는 애플리케이션 개발 자동화 프로세스를 사용합니다.
이러한 원격 시스템(및 타사 소유 시스템)에서는 소스 코드나 시크릿에 접근할 수 있고, 생성된 바이너리가 자신의 로컬 코드와 동일한지 검증할 수 있는 형태로 증명할 수 없는 형태로 빌드를 변경할 수 있으므로, 이러한 시스템을 완전히 신뢰할 수 있어야 합니다.
즉, 신뢰할 수 있는 제공업체에 의존하거나, 자신의 관리된 하드웨어에서 이러한 시스템을 호스팅해야 합니다.
Tauri에서는 여러 플랫폼에서 앱을 구축하기 위한 GitHub 워크플로를 제공합니다.
만약 직접 CI/CD를 구축하고 타사 도구에 의존하는 경우, 버전을 명시적으로 고정하지 않은 작업에는 주의하십시오.
배포 대상 플랫폼에 맞게 만든 앱의 바이너리에 서명해야 합니다.
이 방법은 설정이 복잡하고 다소 비용이 들 수 있지만, 최종 사용자는 앱이 공식적으로 여러분으로부터 발행된 것임을 증명하는 증거를 원합니다.
암호화 비밀이 하드웨어 토큰에 적절하게 저장된 경우, 보안 침해된 빌드 시스템에서는 관련 서명 키를 유출할 수 없지만, 악의적인 릴리스 서명에 사용될 수는 있습니다.
### 재현 가능한 빌드
빌드 시 "백도어 주입"(백도어형 공격)에 대항하려면 빌드를 재현 가능하게 만들어야 합니다. 그렇게 하면 자신의 PC에서 빌드했을 때나 다른 독립적인 제공업체에서 빌드했을 때나 빌드 자산이 완전히 동일하다는 것을 검증할 수 있습니다.
첫 번째 문제는 Rust가 완전히 **신뢰할 수 있는** 재현 가능한 빌드를 기본적으로 생성하지 않는다는 것입니다. 이론적으로는 이를 지원하지만, 아직 버그가 있고 최근 릴리스에서는 중단되었습니다.
현재 상황은 Rust 프로젝트의 [공개 버그 트래커](https://github.com/rust-lang/rust/labels/A-reproducibility)에서 추적할 수 있습니다.
다음에 마주칠 문제는 많은 일반적인 프론트엔드 번들러도 재현 가능한 출력을 생성하지 않아, 번들된 자산이 재현 가능한 빌드를 손상시킬 수 있다는 것입니다.
즉, 기본적으로 재현 가능한 빌드에 완전히 의존할 수는 없으며, 안타깝게도 자신의 빌드 시스템을 전적으로 신뢰할 수밖에 없습니다.
## 배포 시의 위협
우리는 앱에 대한 핫 업데이트(재시작 불필요한 업데이트)를 가능한 한 쉽고 안전하게 제공할 수 있도록 최선을 다했습니다.
그러나 매니페스트 서버, 빌드 서버 또는 바이너리 호스팅 서비스의 관리가 불가능하면 모든 것이 무용지물이 됩니다.
직접 시스템을 구축하는 경우, 전문 OPS 아키텍트와 상담하여 적절하게 구축하십시오.
> > > 《번역 주》 OPS = Official Production System(프로덕션 시스템 기술 언어)?
만약 Tauri 앱의 신뢰할 수 있는 배포 서비스를 찾고 있다면, Tauri의 파트너인 CrabNebula가 클라우드 서비스를 제공합니다: [https://crabnebula.dev/cloud](https://crabnebula.dev/cloud)
## 실행 시의 위협
우리는 Webview가 안전하지 않다고 생각하며, 신뢰할 수 없는 사용자 영역 콘텐츠를 로드한다는 관점에서 Webview에서 시스템 API에 대한 접근에 대해 몇 가지 보호 기능을 Tauri에 구현하기로 결정했습니다.
> > > 《번역 주》 **사용자 영역** 운영 체제의 핵심(커널) 이외의 부분. 일반 사용자의 권한으로 조작할 수 있는 영역.
[콘텐츠 보안 정책](/ko/security/csp/)을 사용하면 Webview가 실행할 수 있는 통신 유형을 차단합니다.
또한 [보안 수준](/ko/security/capabilities/) 설정을 통해 신뢰할 수 없는 콘텐츠나 스크립트가 Webview 내의 API에 액세스하는 것을 방지할 수 있습니다.
또한 [Tauri에 정보 제공](/ko/security/#협력적-정보-공개)과 유사한, 취약점을 보고하기 위한 쉽고 안전한 방법을 설정하는 것도 권장합니다.

View File

@@ -0,0 +1,163 @@
---
title: 접근 권한 permissions
sidebar:
order: 2
i18nReady: true
---
"접근 권한"(Permissions)은 명시된 명령 특권의 내용 설명입니다.
```toml
[[permission]]
identifier = "my-identifier"
description = "This describes the impact and more."
commands.allow = [
"read_file"
]
[[scope.allow]]
my-scope = "$HOME/*"
[[scope.deny]]
my-scope = "$HOME/secret"
```
이를 통해 Tauri 애플리케이션의 프론트엔드에서 명령에 액세스할 수 있습니다.
또한 "적용 범위"(스코프)를 명령에 할당하여 어떤 명령이 활성화되는지 지정할 수 있습니다.
"접근 권한"에서는 특정 명령을 활성화 또는 비활성화하거나, "적용 범위"를 정의하거나, 또는 그 둘을 조합할 수 있습니다.
"접근 권한"은 새로운 "식별자" 아래에 한 세트로 그룹화할 수 있습니다.
이는 "접근 권한 세트"라고 불리며, 이를 통해 "적용 범위" 관련 접근 권한을 "명령" 관련 접근 권한과 결합할 수 있습니다. 또한 "작업"별 접근 권한을 더 사용하기 쉬운 세트로 그룹화하거나 번들링할 수도 있습니다.
플러그인 개발자라면 공개된 모든 명령에 대해 여러 개의 정의되고 적절한 이름이 부여된 접근 권한을 배포할 수 있습니다.
애플리케이션 개발자의 경우, 기존 플러그인 접근 권한을 확장하거나 개인 설정 명령용으로 정의할 수 있습니다. 이는 나중에 재사용하거나 기본 설정 파일을 간소화하기 위해 한 세트로 그룹화하거나 확장할 수 있습니다.
## 접근 권한 식별자
"접근 권한 식별자"는 접근 권한을 재사용하고 고유한 이름을 갖도록 보장하는 데 사용됩니다.
:::tip
"**이름**"을 사용하여 `tauri-plugin-`이라는 접두사 없이 플러그인 크레이트 이름을 참조합니다. 이는 "이름"이 충돌할 가능성을 줄이기 위한 "네임스페이스"로 의도되었습니다. 애플리케이션 자체의 접근 권한을 참조하는 경우에는 필요하지 않습니다.
:::
- `<name>:default`: 이는 접근 권한이 플러그인 또는 애플리케이션의 기본값임을 나타냅니다.
- `<name>:<command-name>`: 이는 접근 권한이 개별 명령용임을 나타냅니다.
플러그인의 접두사 `tauri-plugin-`은 컴파일 시 플러그인 식별자의 맨 앞에 자동으로 추가되므로 수동으로 지정할 필요가 없습니다.
식별자는 ASCII 문자의 알파벳 소문자 `[a-z]`로 제한되며, 식별자의 최대 길이(문자 수)는 아래 상수에 의해 현재 `116`으로 제한됩니다.
```rust
const IDENTIFIER_SEPARATOR: u8 = b':';
const PLUGIN_PREFIX: &str = "tauri-plugin-";
// https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field
const MAX_LEN_PREFIX: usize = 64 - PLUGIN_PREFIX.len();
const MAX_LEN_BASE: usize = 64;
const MAX_LEN_IDENTIFIER: usize = MAX_LEN_PREFIX + 1 + MAX_LEN_BASE;
```
## 설정 파일
Tauri **플러그인** 디렉토리 구조의 간략화된 예:
```sh
tauri-plugin
├── README.md
├── src
│ └── lib.rs
├── build.rs
├── Cargo.toml
├── permissions
│ └── <identifier>.json/toml
│ └── default.json/toml
```
기본 접근 권한은 특별한 방법으로 처리됩니다. Tauri CLI를 사용하여 Tauri 애플리케이션에 플러그인을 추가하는 한, 애플리케이션 설정에 자동으로 추가되기 때문입니다.
**애플리케이션** 개발자의 경우도 구조는 유사합니다:
```sh
tauri-app
├── index.html
├── package.json
├── src
├── src-tauri
│ ├── Cargo.toml
│ ├── permissions
│ └── <identifier>.toml
| ├── capabilities
│ └── <identifier>.json/.toml
│ ├── src
│ ├── tauri.conf.json
```
:::note[(참고)]
애플리케이션 개발자인 경우, 설정 파일은 `json` / `json5` 또는 `toml`로 작성할 수 있지만, "접근 권한"은 `toml` 내에서만 정의할 수 있습니다.
:::
## 실시 예
`File System` 플러그인의 "접근 권한" 설정 예:
```toml title="plugins/fs/permissions/autogenerated/base-directories/home.toml"
[[permission]]
identifier = "scope-home"
description = """This scope permits access to all files and
list content of top level directories in the `$HOME`folder."""
[[scope.allow]]
path = "$HOME/*"
```
> > > 《번역 주》 위 description의 내용: 이 적용 범위는 `$HOME` 폴더 내의 모든 파일과 목록 내용에 대한 액세스를 허용합니다.
```toml title="plugins/fs/permissions/read-files.toml"
[[permission]]
identifier = "read-files"
description = """This enables all file read related
commands without any pre-configured accessible paths."""
commands.allow = [
"read_file",
"read",
"open",
"read_text_file",
"read_text_file_lines",
"read_text_file_lines_next"
]
```
> > > 《번역 주》 위 description의 내용: 이를 통해 사전 구성된 액세스 가능한 경로 없이 모든 파일 읽기 관련 명령이 활성화됩니다.
```toml title="plugins/fs/permissions/autogenerated/commands/mkdir.toml"
[[permission]]
identifier = "allow-mkdir"
description = "This enables the mkdir command."
commands.allow = [
"mkdir"
]
```
> > > 《번역 주》 위 description의 내용: 이를 통해 "mkdir" 명령이 활성화됩니다.
앱에서 위의 플러그인 접근 권한을 확장하는 구현 예:
```toml title="my-app/src-tauri/permissions/home-read-extends.toml"
[[set]]
identifier = "allow-home-read-extended"
description = """ This allows non-recursive read access to files and to create directories
in the `$HOME` folder.
"""
permissions = [
"fs:read-files",
"fs:scope-home",
"fs:allow-mkdir"
]
```
> > > 《번역 주》 위 description의 내용: 이를 통해 파일에 대한 비재귀적 읽기 액세스가 가능해지고, `$HOME` 폴더 내에 디렉토리를 만들 수 있게 됩니다.

View File

@@ -0,0 +1,32 @@
---
title: 런타임 통제 Runtime Authority
i18nReady: true
---
"런타임 통제" 권한은 Tauri Core의 일부입니다.
어떤 창이 어떤 명령에 액세스할 수 있는지 제어하기 위해, 실행 시 모든 "접근 권한", "보안 수준 설정", "범위"(적용 범위) 정보를 확보하고, 명령에 범위 정보를 전달합니다.
> > > 《번역 주》 **런타임 통제** 원문은 Runtime Authority. 실행 시(런타임) 처리に対する "지배권(Authority)/권한"으로 해석되지만, "권한"으로 번역하면 permissions/capabilities와 같은 유사한 용어와 번역상 구별이 어려워지므로, 본고에서는 "통제(권)"로 표기합니다.
> > > 마찬가지로, permissions(허가하는 권한)는 "접근 권한", capabilities(실행하는 능력/기능)는 "보안 수준(설정)"으로 문맥에 따라 번역합니다.
Webview에서 Tauri 명령이 호출될 때마다, "런타임 통제" 권한은 (1) "호출 요청"을 받고, (2) 요청된 명령을 호출자(오리진)가 실제로 사용할 수 있는지 확인하고, (3)> 오리진이 보안 수준 설정의 대상 내에 있는지, 범위가 해당 명령에 대해 정의되어 적용 가능한지 확인하고, (4) 그런 다음 "호출 요청"에 필요한 정보가 삽입되면, (5) 마침내 "호출 요청"은 적절한 Tauri 명령에 전달됩니다.
오리진에 명령 호출이 허용되지 않은 경우, "런타임 통제" 권한에 의해 "호출 요청"이 거부되고, Tauri 명령은 결코 호출되지 않습니다.
![IPC Diagram](@assets/concept/runtime-authority.svg)
> > > 《번역 주》 도표 내 용어
> > > Main Window 주 창
> > > ・ invoke (message) 호출(메시지)
> > > Command 명령
> > > ・ invoke (message+scopes) 호출(메시지+범위)
> > > **Runtime Authority** 런타임 통제
> > > ・ IPC Handler 프로세스 간 통신 핸들러
> > > ・ calling window and capability 호출 창과 보안 수준 확인
> > > **capability1** 보안 수준 설정 1
> > > ・ Commands 명령류
> > > ・ Scopes 범위 설정(fs::writeFile의 적용 범위)
> > > ・ Scopes 범위 설정(shell::execute의 적용 범위)
> > > ・ Windows 각종 창
> > > ・ Main Windows 주 창
> > > ・ Splashscreen 스플래시 스크린(시작 시 표시 화면)

View File

@@ -0,0 +1,128 @@
---
title: 명령 범위 Command Scopes
sidebar:
order: 3
i18nReady: true
---
"범위"(적용 범위)는 Tauri 명령에 허용되는 동작(또는 허용되지 않는 동작)을 세밀하게 정의하는 방법입니다.
"범위"는 "허용 `allow` 범위"와 "거부 `deny` 범위"로 분류되며, "거부 범위"는 항상 "허용 범위"보다 우선합니다.
이 "범위의 유형"은 [`serde`](https://docs.rs/serde/latest/serde/)의 직렬화 가능한 유형(타입) 중 하나여야 합니다.
이러한 유형은 일반적으로 플러그인별로 다릅니다. Tauri 애플리케이션에 구현된 범위 지정 명령의 경우, 범위의 유형은 애플리케이션에서 정의하고 명령 구현에서 적용해야 합니다.
예를 들어, [`Fs`](https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/fs) 플러그인에서는 범위를 사용하여 특정 디렉토리와 파일을 "허용" 또는 "거부"할 수 있으며, [`http`](https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/http) 플러그인에서는 범위를 사용하여 액세스가 "허용"되는 URL을 필터링할 수 있습니다.
"범위"는 명령에 전달되며, 처리 및 적절한 집행은 명령 자체가 구현합니다.
:::caution
명령 개발자는 범위 회피가 불가능하다는 것을 확실히 해야 합니다. 범위 검증 구현은 그 정확성을 담보하기 위해 감사해야 합니다.
:::
## 실시 예
다음 예는 [`Fs`](https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/fs) 플러그인의 "접근 권한"을 기반으로 합니다:
모든 명령에 대한 이 플러그인의 "범위의 유형"은 문자열이며, 여기에는 [`glob`](https://docs.rs/glob/latest/glob/) 호환 경로가 포함됩니다.
```toml title="plugins/fs/permissions/autogenerated/base-directories/applocaldata.toml"
[[permission]]
identifier = "scope-applocaldata-recursive"
description = '''
This scope recursive access to the complete `$APPLOCALDATA` folder,
including sub directories and files.
'''
[[permission.scope.allow]]
path = "$APPLOCALDATA/**"
```
> > > 《번역 주》 위 description의 내용: 이 범위는 하위 디렉토리와 파일을 포함한 전체 `$APPLOCALDATA` 폴더에 대한 재귀적 액세스입니다.
```toml title="plugins/fs/permissions/deny-webview-data.toml"
[[permission]]
identifier = "deny-webview-data-linux"
description = '''
This denies read access to the
`$APPLOCALDATA` folder on linux as the webview data and
configuration values are stored here.
Allowing access can lead to sensitive information disclosure and
should be well considered.
'''
platforms = ["linux"]
[[scope.deny]]
path = "$APPLOCALDATA/**"
[[permission]]
identifier = "deny-webview-data-windows"
description = '''
This denies read access to the
`$APPLOCALDATA/EBWebView` folder on windows as the webview data and
configuration values are stored here.
Allowing access can lead to sensitive information disclosure and
should be well considered.
'''
platforms = ["windows"]
[[scope.deny]]
path = "$APPLOCALDATA/EBWebView/**"
```
> > > 《번역 주》 위 description의 내용(Linux용과 Windows용 설명으로 나뉩니다. 내용은 거의 동일): 이 접근 권한 설정으로 인해 WebView 데이터와 설정 값이 여기에 저장되므로 Linux에서Windows에서 `$APPLOCALDATA`$APPLOCALDATA/EBWebView/ 폴더에 대한 읽기 액세스가 "거부"됩니다. 액세스를 "허용"하면 민감한 정보 유출로 이어질 수 있으므로 충분히 고려해야 합니다.
위의 두 범위를 사용하면 민감한 WebView 데이터가 포함된 Windows의 `EBWebView` 하위 폴더에 대한 액세스를 방지하면서 `APPLOCALDATA` 폴더에 대한 액세스를 허용할 수 있습니다.
이를 하나의 세트로 통합하면 중복된 구성이 줄어들고 애플리케이션 설정을 살펴보는 사람이 이해하기 쉬워집니다.
먼저, "거부" 범위가 `deny-default`에 병합됩니다:
```toml title="plugins/fs/permissions/deny-default.toml"
[[set]]
identifier = "deny-default"
description = '''
This denies access to dangerous Tauri relevant files and
folders by default.
'''
permissions = ["deny-webview-data-linux", "deny-webview-data-windows"]
```
> > > 《번역 주》 위 description의 내용: 이를 통해 위험한 Tauri 관련 파일 및 폴더에 대한 액세스가 기본적으로 "거부"됩니다.
그런 다음 "거부" 범위와 "허용" 범위가 병합됩니다:
```toml
[[set]]
identifier = "scope-applocaldata-reasonable"
description = '''
This scope set allows access to the `APPLOCALDATA` folder and
subfolders except for linux,
while it denies access to dangerous Tauri relevant files and
folders by default on windows.
'''
permissions = ["scope-applocaldata-recursive", "deny-default"]
```
> > > 《번역 주》 위 description의 내용: 이 범위 세트는 Linux를 제외하고 `APPLOCALDATA` 폴더와 하위 폴더에 대한 액세스를 "허용"하지만, Windows에서는 기본적으로 위험한 Tauri 관련 파일과 폴더에 대한 액세스를 "거부"합니다.
이러한 "범위"는 플러그인의 전역 범위를 확장하여 모든 명령에 사용하거나, 접근 권한 내에서 유효한 명령과 함께 사용하는 경우 선택한 명령에만 사용할 수 있습니다.
`APPLOCALDATA` 내의 파일에 대한 적절한 읽기 전용 파일 액세스 설정은 다음과 같습니다:
```toml
[[set]]
identifier = "read-files-applocaldata"
description = '''
This set allows file read access to the `APPLOCALDATA` folder and
subfolders except for linux,
while it denies access to dangerous Tauri relevant files and
folders by default on windows.'''
permissions = ["scope-applocaldata-reasonable", "allow-read-file"]
```
> > > 《번역 주》 위 description의 내용: 이 세트는 Linux를 제외한 `APPLOCALDATA` 폴더와 하위 폴더에 대한 파일 읽기 액세스를 "허용"하지만, Windows에서는 기본적으로 위험한 Tauri 관련 파일과 폴더에 대한 액세스를 "거부"합니다.
위의 각 예는 "범위"의 기능 자체를 강조하기 위한 것입니다. 플러그인 또는 애플리케이션의 각 개발자는 사용 사례(사용자 기능 요구)에 따라 적절한 범위의 조합을 검토해야 합니다.

View File

@@ -0,0 +1,220 @@
---
title: 프로젝트 만들기
sidebar:
order: 3
---
import { Card, Steps } from '@astrojs/starlight/components';
import Cta from '@fragments/cta.mdx';
Tauri가 매우 유연한 이유 중 하나는 사실상 어떤 프론트엔드 기술(프레임워크)과도 연동할 수 있다는 것입니다. 새로운 Tauri 프로젝트를 만드는 데 도움이 되도록 공식적으로 유지 관리되는 "유틸리티 [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app)"이 있으며, 각 프론트엔드 기술용 템플릿이 몇 가지 준비되어 있습니다.
`create-tauri-app`에는 현재 다음과 같은 템플릿이 있습니다: "vanilla"(HTML, CSS 및 JavaScript/프레임워크 없음), "[Vue.js](https://vuejs.org)", "[Svelte](https://svelte.dev)", "[React](https://reactjs.org/)", "[SolidJS](https://www.solidjs.com/)", "[Angular](https://angular.io/)", "[Preact](https://preactjs.com/)", "[Yew](https://yew.rs/)", "[Leptos](https://github.com/leptos-rs/leptos)" 및 "[Sycamore](https://sycamore-rs.netlify.app/)"입니다. [Awesome Tauri repo](https://github.com/tauri-apps/awesome-tauri)에서 찾을 수 있는 커뮤니티 제작 템플릿이나 프레임워크도 추가로 사용할 수 있습니다.
{/* TODO: redirect to integrate to existing front-end project specific docs */}
또는 아래의 "[수동 설정](#수동-설정)"을 실행하여 Tauri를 현재 작업 중인 프로젝트에 추가함으로써 현재 코드를 Tauri 앱으로 변경할 수 있습니다.
## `create-tauri-app` 이용하기
`create-tauri-app`을 이용하여 프로젝트를 시작하려면 프로젝트를 시작할 폴더에서 다음 명령 중 하나를 실행합니다. 어떤 명령을 사용해야 할지 모르는 경우 Linux 및 macOS에서는 "Bash" 명령, Windows에서는 "PowerShell" 명령을 사용하는 것이 좋습니다.
<Cta />
화면의 프롬프트 표시에 따라 "프로젝트 이름", "프론트엔드 언어", "패키지 관리자", "프론트엔드 프레임워크" 및 (해당하는 경우) 프론트엔드 프레임워크 옵션을 선택합니다.
:::tip[어떤 것을 선택해야 할지 모르겠나요?]
{/* TODO: redirect to integrate to existing front-end project specific docs */}
처음이라면 "vanilla" 템플릿(HTML, CSS 및 JavaScript/프레임워크 없음)을 이용하여 프로젝트를 시작하는 것이 좋습니다. 언제든지 나중에 [프론트엔드 프레임워크를 통합](/ko/start/create-project/)할 수 있습니다.
- 프론트엔드에 사용할 언어 선택: `TypeScript / JavaScript`
- 패키지 관리자 선택: `pnpm`
- 사용자 인터페이스(UI) 템플릿 선택: `Vanilla`
- 사용자 인터페이스(UI) 맛 선택: `TypeScript`
:::
#### 새로운 프로젝트 준비하기
<Steps>
1. 프로젝트 이름과 번들 식별자(앱의 고유 ID)를 선택하십시오:
```
? Project name (tauri-app) 《프로젝트 이름 (tauri-app)》
? Identifier (com.tauri-app.app) 《식별자 (com.tauri-app.app)》
```
2. 프론트엔드 언어를 선택하십시오:
```
? Choose which language to use for your frontend
《? 프론트엔드에 어떤 언어를 사용하시겠습니까: 아래에서 선택》
Rust (cargo)
TypeScript / JavaScript (pnpm, yarn, npm, bun)
.NET (dotnet)
```
3. 패키지 관리자를 선택합니다(선택지가 여러 개 있는 경우):
**TypeScript / JavaScript**의 경우 선택지:
```
? Choose your package manager 《패키지 관리자를 선택하십시오》
pnpm
yarn
npm
bun
```
4. UI 템플릿과 맛을 선택하십시오(선택지가 여러 개 있는 경우):
**Rust**의 경우 선택지:
```
? Choose your UI template 《UI 템플릿을 선택하십시오》
Vanilla
Yew
Leptos
Sycamore
```
**TypeScript / JavaScript**의 경우 선택지:
```
? Choose your UI template 《UI 템플릿을 선택하십시오》
Vanilla
Vue
Svelte
React
Solid
Angular
Preact
? Choose your UI flavor 《UI 맛을 선택하십시오》
TypeScript
JavaScript
```
**.NET**의 경우 선택지:
```
? Choose your UI template 《UI 템플릿을 선택하십시오》
Blazor (https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor/)
```
</Steps>
설정이 완료되면 템플릿이 생성되고 설정 후 패키지 관리자를 사용한 해당 템플릿의 실행 방법이 표시됩니다. 만약 패키지 관리자가 시스템 내의 종속성 부족을 감지하면 패키지 목록이 출력되어 부족한 패키지 설치를 촉구합니다.
{/* TODO: Can CTA offer to install the deps? */}
#### 개발 서버 시작
`create-tauri-app`으로 설정 후, 프로젝트 폴더로 이동하여 종속성을 설치한 다음 [Tauri CLI](/ko/reference/cli/) (명령줄 인터페이스)를 사용하여 개발 서버를 시작합니다.
import CommandTabs from '@components/CommandTabs.astro';
<CommandTabs
npm="cd tauri-app
npm install
npm run tauri dev"
yarn="cd tauri-app
yarn install
yarn tauri dev"
pnpm="cd tauri-app
pnpm install
pnpm tauri dev"
deno="cd tauri-app
deno install
deno task tauri dev"
cargo="cd tauri-app
cargo tauri dev"
/>
이제 새 창이 열리고 앱이 실행됩니다.
**축하합니다!** Tauri 앱이 완성되었습니다! 🚀
## 수동 설정
이미 프론트엔드가 완성되었거나 직접 설정을 하고 싶은 경우, "Tauri CLI"를 이용하여 해당 프로젝트의 백엔드를 개별적으로 초기화할 수 있습니다.
:::note
다음 예에서는 새 프로젝트를 시작한다고 가정합니다. 애플리케이션의 프론트엔드를 이미 초기화한 경우 첫 번째 단계를 생략할 수 있습니다.
:::
<Steps>
1. 프로젝트용 새 디렉토리를 만들고 프론트엔드를 초기화합니다. 일반적인 HTML, CSS, JavaScript나 Next.js, Nuxt, Svelte, Yew, Leptos와 같은 원하는 프레임워크를 사용할 수 있습니다. 필요한 것은 브라우저에 앱을 제공하는 방법뿐입니다. 간단한 예로, 다음은 간단한 Vite 프론트엔드 빌드 도구를 설정하는 방법입니다:
<CommandTabs
npm="mkdir tauri-app
cd tauri-app
npm create vite@latest ."
yarn="mkdir tauri-app
cd tauri-app
yarn create vite ."
pnpm="mkdir tauri-app
cd tauri-app
pnpm create vite ."
deno="mkdir tauri-app
cd tauri-app
deno run -A npm:create-vite ."
/>
2. 다음으로, 위에서 도입한 패키지 관리자를 사용하여 Tauri의 CLI 도구를 설치합니다. `cargo`를 사용하여 Tauri CLI를 설치하는 경우 "전역 설치"해야 합니다:
<CommandTabs
npm="npm install -D @tauri-apps/cli@latest"
yarn="yarn add -D @tauri-apps/cli@latest"
pnpm="pnpm add -D @tauri-apps/cli@latest"
deno="deno add -D npm:@tauri-apps/cli@latest"
cargo='cargo install tauri-cli --version "^2.0.0" --locked'
/>
3. 프론트엔드 개발 서버의 URL을 결정합니다. 이는 Tauri가 콘텐츠를 로드하는 데 사용할 URL입니다. 예를 들어, Vite를 사용하는 경우 기본 URL은 `http://localhost:5173`입니다.
4. 프로젝트 디렉토리로 돌아가 Tauri를 초기화합니다:
<CommandTabs
npm="npx tauri init"
yarn="yarn tauri init"
pnpm="pnpm tauri init"
deno="deno task tauri init"
cargo="cargo tauri init"
/>
위의 명령을 실행하면 다양한 질문 항목에 대한 프롬프트가 표시됩니다:
```sh frame=none
✔ What is your app name? tauri-app 《앱 이름은 무엇입니까?》
✔ What should the window title be? tauri-app 《창 제목은 무엇으로 하시겠습니까?》
✔ Where are your web assets located? .. 《웹 관련 데이터는 어디에 있습니까?》
✔ What is the url of your dev server? http://localhost:5173 《개발 서버의 URL은 무엇입니까?》
✔ What is your frontend dev command? pnpm run dev 《프론트엔드 개발 명령은 무엇입니까?》
✔ What is your frontend build command? pnpm run build 《프론트엔드 빌드
명령은 무엇입니까?》
```
이렇게 하면 필요한 Tauri 환경 설정 파일을 포함하는 `src-tauri` 디렉토리가 프로젝트에 생성됩니다.
5. Tauri 앱이 작동하는지 확인하기 위해 개발 서버를 실행합니다:
<CommandTabs
npm="npx tauri dev"
yarn="yarn tauri dev"
pnpm="pnpm tauri dev"
deno="deno task tauri dev"
cargo="cargo tauri dev"
/>
이 명령은 Rust 코드를 컴파일하고 만든 웹 콘텐츠 창을 표시합니다.
</Steps>
**축하합니다!** Tauri CLI를 사용하여 새로운 Tauri 프로젝트가 완성되었습니다! 🚀
## 다음 단계는...
- [프론트엔드 설정에 대해](/ko/start/frontend/)
- [Tauri 명령줄 인터페이스에 대해](/ko/reference/cli/)
- [Tauri 앱 만드는 방법에 대해](/ko/develop/)
- [Tauri 확장을 위한 추가 기능에 대해](ko/plugin/)

View File

@@ -0,0 +1,56 @@
---
title: 프론트엔드 설정
i18nReady: true
sidebar:
label: Overview
order: 10
---
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
Tauri는 프론트엔드에 의존하지 않으며, 대부분의 프론트엔드 프레임워크를 즉시 사용할 수 있습니다. 그러나 프레임워크에 따라 Tauri와 통합하여 작동시키기 위해 약간의 추가 설정이 필요한 경우가 있습니다. 아래 목록에 있는 프레임워크에는 권장되는 설정 값이 있습니다.
이 목록에 기재되지 않은 프레임워크에는 추가 설정 없이 Tauri에서 작동하는 것과 아직 정보가 없어 목록에 포함되지 않은 것이 있습니다. 추가 설정이 필요한 프레임워크가 있다면 Tauri 커뮤니티에 알려주시기 바랍니다.
## 설정 체크리스트
개념적으로 Tauri는 정적 웹 호스트로 기능합니다. 따라서 Tauri의 웹 뷰에서 사용되는 HTML, CSS, Javascript 및 경우에 따라 WASM 파일을 포함하는 폴더를 Tauri에 전달해야 합니다.
다음은 프론트엔드를 Tauri와 통합하는 데 필요한 일반적인 시나리오의 체크리스트입니다.
{/* TODO: Link to core concept of SSG/SSR, etc. */}
{/* TODO: Link to mobile development server guide */}
{/* TODO: Concept of how to do a client-server relationship? */}
- "정적 사이트 생성(SSG)", "싱글 페이지 애플리케이션(SPA)" 또는 구식 "멀티 페이지 애플리케이션(MPA)"을 사용합니다. Tauri는 "서버 사이드 렌더링(SSR)"과 같은 서버 기반 대체 방식에는 대응하지 않습니다.
- 모바일 앱 개발에서는 자신의 내부 IP에 프론트엔드를 호스팅할 수 있는 개발 서버가 필요합니다.
- 앱과 API 사이에는 적절한 클라이언트/서버 관계를 사용합니다(SSR을 병용한 하이브리드 솔루션은 사용하지 마십시오).
## JavaScript
{/* TODO: Help me with the wording here lol */}
대부분의 프로젝트에서는 React, Vue, Svelte, Solid와 같은 SPA 프레임워크뿐만 아니라 일반적인 JavaScript 또는 TypeScript 프로젝트에도 [Vite](https://vitejs.dev/)를 권장합니다. 여기에 기재된 다른 가이드의 대부분에는 메타 프레임워크 사용 방법이 나와 있습니다. 메타 프레임워크는 일반적으로 SSR용으로 설계되었기 때문에 특별한 설정이 필요합니다.
<CardGrid>
<LinkCard title="Next.js" href="/start/frontend/nextjs/" />
<LinkCard title="Nuxt" href="/start/frontend/nuxt/" />
<LinkCard title="Qwik" href="/start/frontend/qwik/" />
<LinkCard title="SvelteKit" href="/start/frontend/sveltekit/" />
<LinkCard title="Vite(권장)" href="/start/frontend/vite/" />
</CardGrid>
## Rust
<CardGrid>
<LinkCard title="Leptos" href="/start/frontend/leptos/" />
<LinkCard title="Trunk" href="/start/frontend/trunk/" />
</CardGrid>
<br />
:::tip[목록에 프레임워크가 없나요?]
원하는 프레임워크가 목록에 없나요? 추가 설정 없이 Tauri에서 작동하는 프레임워크일 수 있습니다. 일반적인 설정에 대해서는 [설정 체크리스트](/ko/start/frontend/#설정-체크리스트) 항목을 참조하십시오.
:::

View File

@@ -0,0 +1,57 @@
---
title: Leptos
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
Leptos(렙토스)는 Rust 기반의 웹 프레임워크입니다. Leptos에 대한 자세한 설명은 [공식 웹사이트[영어]](https://leptos.dev/)를 참조하십시오. 아래 설명은 "Leptos 버전 0.6"을 기준으로 합니다.
## 체크 항목
- "SSG(정적 사이트 생성)"를 사용하십시오. Tauri는 공식적으로 서버 기반 방식을 지원하지 않습니다.
- `serve.ws_protocol = "ws"`를 사용하십시오. 모바일 개발에서 핫 리로드를 위한 WebSocket이 제대로 연결되도록 합니다.
- `withGlobalTauri`를 활성화하십시오. Tauri API가 `window.__TAURI__` 변수 내에서 사용 가능해지며, `wasm-bindgen`을 사용하여 가져올 수 있습니다.
## 설정 예
<Steps>
1. ##### Tauri 설정 업데이트
```json
// src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "trunk serve",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "trunk build",
"frontendDist": "../dist"
},
"app": {
"withGlobalTauri": true
}
}
```
2. ##### Trunk 설정 업데이트
```toml
// Trunk.toml
[build]
target = "./index.html"
[watch]
ignore = ["./src-tauri"]
[serve]
port = 1420
open = false
ws_protocol = "ws"
```
</Steps>

View File

@@ -0,0 +1,131 @@
---
title: Next.js
i18nReady: true
tableOfContents:
collapseLevel: 1
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
Next.js(넥스트.js)는 React용 메타 프레임워크입니다. Next.js에 대한 자세한 내용은 https://nextjs.org 를 참조하십시오. 아래 설명은 "Next.js 14.2.3 버전"을 기준으로 합니다.
## 체크 항목
- `output: 'export'`를 설정하여 "정적 내보내기"를 사용하십시오. Tauri는 서버 기반 방식을 지원하지 않습니다.
- `tauri.conf.json`의 `frontendDist`에 "`out`" 디렉토리를 사용하십시오.
## 설정 예
<Steps>
1. ##### Tauri 설정 업데이트
<Tabs>
<TabItem label="npm">
```json
// src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"devUrl": "http://localhost:3000",
"frontendDist": "../out"
}
}
```
</TabItem>
<TabItem label="yarn">
```json
// src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn build",
"devUrl": "http://localhost:3000",
"frontendDist": "../out"
}
}
```
</TabItem>
<TabItem label="pnpm">
```json
// src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devUrl": "http://localhost:3000",
"frontendDist": "../out"
}
}
```
</TabItem>
<TabItem label="deno">
```json
// src-tauri/tauri.conf.json
{
"build": {
"beforeDevCommand": "deno task dev",
"beforeBuildCommand": "deno task build",
"devUrl": "http://localhost:3000",
"frontendDist": "../out"
}
}
```
</TabItem>
</Tabs>
2. ##### Next.js 설정 업데이트
```ts
// next.conf.mjs
const isProd = process.env.NODE_ENV === 'production';
const internalHost = process.env.TAURI_DEV_HOST || 'localhost';
/** @type {import('next').NextConfig} */
const nextConfig = {
// Next.js가 "SSR(서버 사이드 렌더링)"이 아닌 "SSG(정적 사이트 생성)"을 사용하도록 합니다.
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
output: 'export',
// 참고: 이 기능은 SSG 모드에서 Next.js 이미지 컴포넌트를 사용하기 위해 필요합니다.
// 다른 해결 방법은 https://nextjs.org/docs/messages/export-image-api 를 참조하십시오.
images: {
unoptimized: true,
},
// assetPrefix를 설정하십시오. 그렇지 않으면 서버가 자산을 제대로 확인할 수 없습니다.
assetPrefix: isProd ? undefined : `http://${internalHost}:3000`,
};
export default nextConfig;
```
3. ##### package.json 설정 업데이트
```json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"tauri": "tauri"
}
```
</Steps>

View File

@@ -0,0 +1,117 @@
---
title: Nuxt
i18nReady: true
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
Nuxt(넉스트)는 Vue용 메타 프레임워크입니다. Nuxt에 대한 자세한 내용은 https://nuxt.com 을 참조하십시오. 아래 설명은 "Nuxt 3.11. 버전"을 기준으로 합니다.
## 체크 항목
- `ssr: false`를 설정하여 SSG를 사용하십시오. Tauri는 서버 기반 방식을 지원하지 않습니다.
- iOS 물리적 장치에서 실행되도록 설정된 경우, 개발 서버의 호스트 IP에 `process.env.TAURI_DEV_HOST`를 사용하십시오.
- `tauri.conf.json`에서는 `frontendDist`로 `dist/`를 지정합니다.
- `nuxi generate`를 사용하여 컴파일합니다.
- (선택 사항) `nuxt.config.ts`에서 `telemetry: false`로 설정하여 원격 측정을 비활성화합니다.
## 설정 예
<Steps>
1. ##### Tauri 설정 업데이트
<Tabs>
<TabItem label="npm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run generate",
"devUrl": "http://localhost:3000",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="yarn">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn generate",
"devUrl": "http://localhost:3000",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="pnpm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm generate",
"devUrl": "http://localhost:3000",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="deno">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "deno task dev",
"beforeBuildCommand": "deno task generate",
"devUrl": "http://localhost:3000",
"frontendDist": "../dist"
}
}
```
</TabItem>
</Tabs>
2. ##### Nuxt 설정 업데이트
```ts
export default defineNuxtConfig({
//(선택 사항) "Nuxt devtools"를 활성화합니다
devtools: { enabled: true },
//"SSG"를 활성화합니다
ssr: false,
// iOS 물리적 장치에서 실행 중일 때 다른 장치에서 개발 서버를 검색할 수 있도록 합니다
devServer: { host: process.env.TAURI_DEV_HOST || 'localhost' },
vite: {
// Tauri CLI 출력 지원 강화
clearScreen: false,
// 환경 변수 활성화
// 추가 환경 변수는 다음 사이트에서 볼 수 있습니다
// https://v2.tauri.app/reference/environment-variables/
envPrefix: ['VITE_', 'TAURI_'],
server: {
// Tauri는 일관된 포트가 필요합니다
strictPort: true,
},
},
});
```
</Steps>

View File

@@ -0,0 +1,142 @@
---
title: Qwik
i18nReady: true
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Steps, TabItem, Tabs } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
여기서는 "Qwik(퀵) 웹 프레임워크"를 사용한 Tauri 앱 만들기를 순서대로 설명합니다. Qwik에 대한 자세한 내용은 공식 사이트 https://qwik.dev 를 참조하십시오.
## 체크 항목
- [SSG](https://qwik.dev/docs/guides/static-site-generation/)를 사용하십시오. Tauri는 서버 기반 방식을 지원하지 않습니다.
- `tauri.conf.json`에서는 `frontendDist`로 `dist/`를 지정합니다.
## 설정 예
<Steps>
1. ##### 새로운 Qwik 앱 시작하기
<CommandTabs
npm={`npm create qwik@latest
cd <PROJECT>`}
yarn={`yarn create qwik@latest
cd <PROJECT>`}
pnpm={`pnpm create qwik@latest
cd <PROJECT>`}
deno={`deno run -A npm:create-qwik@latest
cd <PROJECT>`}
/>
2. ##### `static adapter` 설치하기
<CommandTabs
npm="npm run qwik add static"
yarn="yarn qwik add static"
pnpm="pnpm qwik add static"
deno="deno task qwik add static"
/>
3. ##### "Tauri CLI"를 프로젝트에 추가하기
<CommandTabs
npm="npm install -D @tauri-apps/cli@latest"
yarn="yarn add -D @tauri-apps/cli@latest"
pnpm="pnpm add -D @tauri-apps/cli@latest"
deno="deno add -D npm:@tauri-apps/cli@latest"
/>
4. ##### 새로운 Tauri 프로젝트 초기화하기
<CommandTabs
npm="npm run tauri init"
yarn="yarn tauri init"
pnpm="pnpm tauri init"
deno="deno task tauri init"
/>
5. ##### Tauri 설정
<Tabs>
<TabItem label="npm">
```json
// tauri.conf.json
{
"build": {
"devUrl": "http://localhost:5173"
"frontendDist": "../dist",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build"
}
}
```
</TabItem>
<TabItem label="yarn">
```json
// tauri.conf.json
{
"build": {
"devUrl": "http://localhost:5173"
"frontendDist": "../dist",
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn build"
}
}
```
</TabItem>
<TabItem label="pnpm">
```json
// tauri.conf.json
{
"build": {
"devUrl": "http://localhost:5173"
"frontendDist": "../dist",
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build"
}
}
```
</TabItem>
<TabItem label="deno">
```json
// tauri.conf.json
{
"build": {
"devUrl": "http://localhost:5173"
"frontendDist": "../dist",
"beforeDevCommand": "deno task dev",
"beforeBuildCommand": "deno task build"
}
}
```
</TabItem>
</Tabs>
6. ##### `tauri` 앱 시작하기
<CommandTabs
npm="npm run tauri dev"
yarn="yarn tauri dev"
pnpm="pnpm tauri dev"
deno="deno task tauri dev"
/>
</Steps>

View File

@@ -0,0 +1,136 @@
---
title: SvelteKit
i18nReady: true
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
SvelteKit(스벨트킷)은 Svelte(스벨트)용 메타 프레임워크입니다. SvelteKit에 대한 자세한 내용은 "공식 사이트 https://svelte.dev/"를 참조하십시오. 아래 설명은 "SvelteKit 2.5.7 / Svelte 4.2.15"를 기준으로 합니다.
## 체크 항목
- `static-adapter`를 통해 [SSG](https://svelte.dev/docs/kit/adapter-static) 및/또는 [SPA](https://svelte.dev/docs/kit/single-page-apps)를 사용하십시오. Tauri는 서버 기반 방식을 지원하지 않습니다.
- `tauri.conf.json`에서는 `frontendDist`로 `dist/`를 지정합니다.
## 설정 예
<Steps>
1. ##### `@sveltejs/adapter-static` 설치
<CommandTabs
npm="npm install --save-dev @sveltejs/adapter-static"
yarn="yarn add -D @sveltejs/adapter-static"
pnpm="pnpm add -D @sveltejs/adapter-static"
deno="deno add -D npm:@sveltejs/adapter-static"
/>
2. ##### Tauri 설정 업데이트
<Tabs>
<TabItem label="npm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"devUrl": "http://localhost:5173",
"frontendDist": "../build"
}
}
```
</TabItem>
<TabItem label="yarn">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn build",
"devUrl": "http://localhost:5173",
"frontendDist": "../build"
}
}
```
</TabItem>
<TabItem label="pnpm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devUrl": "http://localhost:5173",
"frontendDist": "../build"
}
}
```
</TabItem>
<TabItem label="deno">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "deno task dev",
"beforeBuildCommand": "deno task build",
"devUrl": "http://localhost:5173",
"frontendDist": "../build"
}
}
```
</TabItem>
</Tabs>
3. ##### SvelteKit 설정 업데이트
```js title="svelte.config.js" {1}
import adapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// 전처리기 상세 정보는 공식 사이트
// https://svelte.dev/docs/kit/integrations#preprocessors 를 참조하십시오
preprocess: vitePreprocess(),
kit: {
adapter: adapter(),
},
};
export default config;
```
4. ##### "SSR" 비활성화
마지막으로, "SSR"(서버 사이드 렌더링)을 비활성화하고, 다음 내용을 포함하는 "루트 `+layout.ts` 파일"(TypeScript를 사용하지 않는 경우 `+layout.js`)을 추가하여 사전 렌더링을 활성화해야 합니다:
```ts
// src/routes/+layout.ts
export const prerender = true;
export const ssr = false;
```
`static-adapter`는 앱 전체에 대해 "SSR 비활성화"를 요구하지는 않지만, 그렇게 함으로써 (Tauri의 API와 같은) 전역 창 객체에 의존하는 API를 [클라이언트 측 검사](https://svelte.dev/docs/kit/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-a-client-side-only-library-that-depends-on-document-or-window) 없이 사용할 수 있게 됩니다. 《링크는 Svelte 공식 사이트의 FQA 페이지(영어)입니다》
또한, "SSG"(정적 사이트 생성)보다 "싱글 페이지 애플리케이션(SPA)" 모드를 선호하는 경우, [어댑터 관련 문서](https://svelte.dev/docs/kit/single-page-apps) 《영어 페이지》에 따라 어댑터 설정과 `+layout.ts`를 변경할 수 있습니다.
</Steps>

View File

@@ -0,0 +1,51 @@
---
title: Trunk
i18nReady: true
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
Trunk(트렁크)는 Rust용 WASM(웹 어셈블리) 웹 앱 번들러입니다. 자세한 설명은 공식 사이트 https://trunkrs.dev 를 참조하십시오. 아래 설명은 "Trunk 버전 0.17.5"를 기준으로 합니다.
## 체크 항목
- "SSG(정적 사이트 생성)"를 사용하십시오. Tauri는 공식적으로 서버 기반 방식을 지원하지 않습니다.
- `serve.ws_protocol = "ws"`를 사용하십시오. 모바일 개발에서 핫 리로드를 위한 WebSocket이 제대로 연결되도록 합니다.
- `withGlobalTauri`를 활성화하십시오. Tauri API가 `window.__TAURI__` 변수 내에서 사용 가능해지며, `wasm-bindgen`을 사용하여 가져올 수 있습니다.
## 설정 예
<Steps>
1. ##### Tauri 설정 업데이트
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "trunk serve",
"beforeBuildCommand": "trunk build",
"devUrl": "http://localhost:8080",
"frontendDist": "../dist"
},
"app": {
"withGlobalTauri": true
}
}
```
2. ##### Trunk 설정 업데이트
```toml
# Trunk.toml
[watch]
ignore = ["./src-tauri"]
[serve]
ws_protocol = "ws"
```
</Steps>

View File

@@ -0,0 +1,137 @@
---
title: Vite
tableOfContents:
minHeadingLevel: 2
maxHeadingLevel: 5
---
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
Vite(비트)는 최신 웹 프로젝트에서 더 빠르고 간결한 개발 경험을 제공하는 것을 목표로 하는 빌드 도구입니다. 아래 설명은 "Vite 버전 5.4.8"을 기준으로 합니다.
## 체크 항목
- `tauri.conf.json`에서는 `frontendDist`로 `dist/`를 지정합니다.
- iOS 물리적 장치에서 실행되도록 설정된 경우, 개발 서버의 호스트 IP에 `process.env.TAURI_DEV_HOST`를 사용하십시오.
## 설정 예
<Steps>
1. ##### Tauri 설정 업데이트
`package.json` 안에 다음 `dev` 및 `build` 스크립트 설정이 있다고 가정합니다:
```json
{
"scripts": {
"dev": "vite dev",
"build": "vite build"
}
}
```
Vite 개발 서버와 dist 폴더를 후크 기능(함수)과 함께 사용하여 Vite 스크립트를 자동으로 실행하도록 Tauri CLI를 설정할 수 있습니다.
<Tabs>
<TabItem label="npm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="yarn">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "yarn build",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="pnpm">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
}
}
```
</TabItem>
<TabItem label="deno">
```json
// tauri.conf.json
{
"build": {
"beforeDevCommand": "deno task dev",
"beforeBuildCommand": "deno task build",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
}
}
```
</TabItem>
</Tabs>
2. ##### Vite 설정 업데이트
```js title="vite.config.js"
import { defineConfig } from 'vite';
const host = process.env.TAURI_DEV_HOST;
export default defineConfig({
// Vite가 Rust 오류를 불분명하게 만드는 것을 방지합니다
clearScreen: false,
server: {
// Tauri는 고정 포트에서 작동하므로 해당 포트를 찾을 수 없으면 작동하지 않습니다
strictPort: true,
// Tauri가 요청하는 호스트가 설정된 경우 이를 사용합니다
host: host || false,
port: 5173,
},
// `envPrefix` 항목으로 시작하는 환경 변수는 `import.meta.env`를 통해 Tauri의 소스 코드에서 참조할 수 있습니다
envPrefix: ['VITE_', 'TAURI_ENV_*'],
build: {
// Tauri는 Windows에서는 Chromium을, macOS와 Linux에서는 WebKit을 사용합니다
target:
process.env.TAURI_ENV_PLATFORM == 'windows'
? 'chrome105'
: 'safari13',
// 디버그 빌드에서는 "파일 경량화(미니파이)"를 시키지 않습니다
minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false,
// 디버그 빌드에서 "SourceMap"을 만듭니다
sourcemap: !!process.env.TAURI_ENV_DEBUG,
},
});
```
</Steps>

View File

@@ -0,0 +1,50 @@
---
title: Tauri란?
i18nReady: true
sidebar:
order: 0
---
Tauri는 주요 데스크톱 및 모바일 플랫폼 모두에서 가볍고 빠른 바이너리 파일을 빌드할 수 있는 프레임워크(구조)입니다. 프론트엔드에는 HTML, JavaScript, CSS로 컴파일되는 프레임워크를 이용하여 사용자 경험(UX)을 구축하고, 백엔드 처리 로직에는 필요에 따라 Rust, Swift, Kotlin 등의 언어를 활용할 수 있습니다.
아래 셸 명령(Bash, PowerShell, …) 중 하나를 사용하여 "Tauri 앱 만들기" [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app)을 시작할 준비를 하십시오. 먼저 "필수 사항 가이드" [prerequisites guide](/ko/start/prerequisites/)에 따라 Tauri에 필요한 모든 "종속성"을 설치하고, 다음으로 권장되는 프론트엔드 구성에 대한 "프론트엔드 구성 가이드" [Frontend Configuration guides](/ko/start/frontend/)를 참조하십시오.
import Cta from '@fragments/cta.mdx';
<Cta />
첫 번째 앱을 만든 후, "기능 및 사용 예시 목록" [List of Features & Recipes](/ko/plugin/) 장에서 Tauri의 다른 기능과 사용법을 알아볼 수 있습니다.
## Tauri의 이점
Tauri에는 프로그램 개발자가 의지할 수 있는 세 가지 큰 이점이 있습니다:
- 앱 구축을 위한 안전한 프로그램 기반
- 시스템 본체의 웹 뷰를 사용하여 번들 크기 경량화
- 모든 프론트엔드 기술 사용 및 여러 컴퓨터 언어 통합 가능 유연성
Tauri의 근본 사상에 대해서는 "Tauri 1.0 블로그 [Tauri 1.0 blog post](/ko/blog/tauri-1-0/)"를 참조하십시오.
### 안전한 프로그램 기반
Tauri는 "Rust"를 사용하여 구축되었으므로, Rust가 제공하는 "메모리", "스레드", "데이터 타입"의 안전성이라는 혜택을 받습니다. Tauri로 만든 앱은 Rust 전문가가 아니더라도 이러한 이점을 자동으로 누릴 수 있습니다.
또한, Tauri는 메이저 릴리스와 마이너 릴리스 모두에서 안전성 감사를 실시합니다. 이 감사에는 Tauri 조직 내의 코드뿐만 아니라 Tauri가 의존하는 상위 종속성도 포함됩니다. 물론, 이것으로 모든 위험이 완화되는 것은 아니지만, 그럼에도 불구하고 프로그램 개발의 기반이 되는 견고한 기반이 됩니다.
자세한 내용은 "Tauri 안전성 방침 [Tauri security policy](https://github.com/tauri-apps/tauri/security/policy)" 및 "Tauri 2.0 감사 보고서 [Tauri 2.0 audit report](https://github.com/tauri-apps/tauri/blob/dev/audits/Radically_Open_Security-v2-report.pdf)"를 참조하십시오.
### 파일 크기 경량화
Tauri 앱은 이미 사용자 시스템에 탑재된 웹 뷰를 이용합니다. 따라서 모든 Tauri 앱은 해당 앱에 필요한 코드와 데이터 자산만 포함하며, 앱 내에 브라우저 엔진을 동봉할 필요가 없습니다. 이는 즉, 최소 Tauri 앱은 600KB 이하의 크기가 될 수 있음을 의미합니다.
최적화된 앱 제작 방법에 대해서는 "앱 크기 개념 [App Size concept](/ko/concept/size/)"을 참조하십시오.
### 유연한 기본 사양
Tauri는 웹 기술을 이용하므로, 사실상 모든 프론트엔드 기술이 Tauri와 호환됩니다. "프론트엔드 구성 가이드 [Frontend Configuration guide](/ko/start/frontend/)"에서는 자주 사용되는 프론트엔드 기술의 일반적인 구성 예를 기재하고 있습니다.
JavaScript 부분과 Rust 부분 간의 결합에는 JavaScript의 "`invoke`(호출)" 함수가, Swift나 Kotlin과의 결합에는 "[Tauri Plugins](/ko/develop/plugins/)(Tauri 플러그인)"이 이용됩니다.
[TAO](https://github.com/tauri-apps/tao)는 Tauri의 창 생성을, [WRY](https://github.com/tauri-apps/wry)는 웹 표시 렌더링을 수행하는 플러그인입니다. 이러한 플러그인은 Tauri가 관리하는 라이브러리로, Tauri가 대응할 수 있는 것 이상의 고급 시스템 통합이 필요한 경우 직접 사용할 수 있습니다.
또한, Tauri에는 Tauri 본체가 대응할 수 있는 기능을 확장하는 많은 플러그인도 있습니다. 이러한 플러그인은 커뮤니티에서 제공하는 플러그인과 함께 "플러그인 [Plugins section](/ko/plugin/)" 섹션에서 찾을 수 있습니다.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
---
title: Tauri 2.0 베타 버전에서 업그레이드
i18nReady: false
sidebar:
order: 16
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';
여기서는 Tauri 2.0 베타 버전 애플리케이션을 Tauri 2.0 릴리스 후보 버전으로 업그레이드하는 절차를 설명합니다.
## 자동 마이그레이션
Tauri v2 CLI에는 마이그레이션 작업의 대부분을 자동화하는 `migrate` 명령이 포함되어 있어 마이그레이션 완료에 도움이 됩니다.
<CommandTabs
npm="npm install @tauri-apps/cli@latest
npm run tauri migrate"
yarn="yarn upgrade @tauri-apps/cli@latest
yarn tauri migrate"
pnpm="pnpm update @tauri-apps/cli@latest
pnpm tauri migrate"
cargo='cargo install tauri-cli --version "^2.0.0" --locked
cargo tauri migrate'
/>
`migrate` 명령에 대한 자세한 내용은 [명령줄 인터페이스 참조](/ko/reference/cli/#migrate)를 참조하십시오.
## 이전 버전과 호환되지 않는 변경 사항(Breaking Changes)
베타 버전에서 릴리스 후보 버전으로 마이그레이션할 때 몇 가지 호환되지 않는 변경 사항을 적용했습니다. 이러한 변경 사항은 자동 마이그레이션(위 참조)하거나 수동으로 실행할 수 있습니다.
### Tauri 코어 플러그인
Tauri 내장 플러그인이 기능 내에서 처리되는 방식을 변경했습니다 [PR #10390](https://github.com/tauri-apps/tauri/pull/10390).
베타 최신 버전에서 마이그레이션하려면 기능 내의 모든 코어 허가 식별자 앞에 `core:`를 추가하거나 `core:default` 허가로 전환하여 이전 코어 플러그인 식별자를 제거해야 합니다.
```json
...
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"image:default",
"resources:default",
"menu:default",
"tray:default",
]
...
```
```json
...
"permissions": [
"core:path:default",
"core:event:default",
"core:window:default",
"core:app:default",
"core:image:default",
"core:resources:default",
"core:menu:default",
"core:tray:default",
]
...
```
또한 새로운 특별한 `core:default` 허가 세트도 추가했습니다. 여기에는 모든 코어 플러그인에 대한 기본 허가가 모두 포함되어 있습니다. 이를 통해 기능 설정에서 허가의 상용구를 간소화할 수 있습니다.
```json
...
"permissions": [
"core:default"
]
...
```
### 내장 개발 서버
내장 개발 서버의 네트워크 공개에 변경 사항을 도입했습니다([PR #10437](https://github.com/tauri-apps/tauri/pull/10437) 및 [PR #10456](https://github.com/tauri-apps/tauri/pull/10456)).
내장 모바일 개발 서버는 네트워크 전체에 공개하지 않고 트래픽을 로컬 컴퓨터에서 장치로 직접 터널링합니다.
현재 이 개선 사항은 iOS 장치에서 (직접 또는 Xcode에서) 실행하는 경우 자동으로 적용되지 않습니다.
따라서 기본적으로 개발 서버에 공용 네트워크 주소가 사용되지만,
이를 피하려면 Xcode를 열어 macOS 컴퓨터와 연결된 iOS 장치 간의 연결을 자동으로 시작하도록 하는 방법이 있습니다.
그런 다음 `tauri ios dev --force-ip-prompt`를 실행하여 iOS 장치의 TUN 주소(**::2**로 끝나는)를 선택합니다.
물리적 iOS 장치에서 실행하는 경우 개발 서버 설정을 이 변경 사항에 맞게 조정해야 합니다.
이전에는 `TAURI_ENV_PLATFORM` 환경 변수가 `android` 또는 `ios` 중 하나와 일치하는지 확인하는 것을 권장했지만,
이제는 iOS 장치를 사용하지 않는 경우 로컬 호스트에 연결할 수 있게 되었으므로 대신 `TAURI_DEV_HOST` 환경 변수를 확인하십시오.
다음은 Vite(비트)에서의 마이그레이션 설정 예입니다.
- 2.0.0-베타 버전:
```js
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { internalIpV4Sync } from 'internal-ip';
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM);
export default defineConfig({
plugins: [svelte()],
clearScreen: false,
server: {
host: mobile ? '0.0.0.0' : false,
port: 1420,
strictPort: true,
hmr: mobile
? {
protocol: 'ws',
host: internalIpV4Sync(),
port: 1421,
}
: undefined,
},
});
```
- 2.0.0:
```js
import { defineConfig } from 'vite';
import Unocss from 'unocss/vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
const host = process.env.TAURI_DEV_HOST;
export default defineConfig({
plugins: [svelte()],
clearScreen: false,
server: {
host: host || false,
port: 1420,
strictPort: true,
hmr: host
? {
protocol: 'ws',
host: host,
port: 1430,
}
: undefined,
},
});
```
:::note
NPM 패키지 `internal-ip`는 더 이상 필요하지 않습니다. 대신 TAURI_DEV_HOST 값을 직접 사용할 수 있습니다.
:::

View File

@@ -0,0 +1,23 @@
---
title: 업그레이드 및 마이그레이션
sidebar:
label: Overview
order: 10
---
Tauri 1.0에서 업그레이드하거나 다른 프레임워크에서 마이그레이션하기 위한 일반적인 시나리오와 절차에 대해 설명합니다.
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
<CardGrid>
<LinkCard
title="Tauri 1.0에서 업그레이드"
href="/ko/start/migrate/from-tauri-1/"
description="버전 1.0 프로젝트를 버전 2.0으로 업그레이드하는 데 필요한 업데이트에 대해"
/>
<LinkCard
title="Tauri 2.0 베타 버전에서 마이그레이션"
href="/ko/start/migrate/from-tauri-2-beta/"
description="2.0 베타 버전 프로젝트를 2.0 정식 버전으로 업그레이드하는 데 필요한 업데이트에 대해"
/>
</CardGrid>

View File

@@ -0,0 +1,387 @@
---
title: 필요 사항
i18nReady: true
sidebar:
order: 0
---
import { Tabs, TabItem, Card } from '@astrojs/starlight/components';
Tauri에서 프로젝트를 시작하려면 먼저 몇 가지 종속성을 설치해야 합니다.
1. [OS별 종속성 설치](#os별-종속성-설치)
2. [Rust 설치](#rust-설치)
3. [모바일 관련 설정](#모바일-관련-설정) (모바일 앱을 개발하는 경우에만 필요)
## OS별 종속성 설치
앱 개발에 사용하는 운영 체제(OS)에 따라 각 링크를 따르십시오.
- [Linux](#linux) (특정 배포판에 대해서는 아래 참조)
- [macOS Catalina (10.15) 이상](#macos)
- [Windows 7 이상](#windows)
### Linux
Tauri는 Linux에서 개발하는 데 다양한 시스템 종속성을 필요로 합니다. 시스템 종속성은 배포판에 따라 다를 수 있지만, 설정에 도움이 되도록 아래에 몇 가지 일반적인 배포판을 기재했습니다.
<Tabs syncKey="distro">
<TabItem label="Debian">
```sh
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
```
</TabItem>
<TabItem label="Arch">
```sh
sudo pacman -Syu
sudo pacman -S --needed \
webkit2gtk-4.1 \
base-devel \
curl \
wget \
file \
openssl \
appmenu-gtk-module \
libappindicator-gtk3 \
librsvg \
xdotool
```
</TabItem>
<TabItem label="Fedora">
```sh
sudo dnf check-update
sudo dnf install webkit2gtk4.1-devel \
openssl-devel \
curl \
wget \
file \
libappindicator-gtk3-devel \
librsvg2-devel \
libxdo-devel
sudo dnf group install "c-development"
```
</TabItem>
<TabItem label="Gentoo">
```sh
sudo emerge --ask \
net-libs/webkit-gtk:4.1 \
dev-libs/libappindicator \
net-misc/curl \
net-misc/wget \
sys-apps/file
```
</TabItem>
<TabItem label="openSUSE">
```sh
sudo zypper up
sudo zypper in webkit2gtk3-devel \
libopenssl-devel \
curl \
wget \
file \
libappindicator3-1 \
librsvg-devel
sudo zypper in -t pattern devel_basis
```
</TabItem>
<TabItem label="Alpine">
```sh
sudo apk add \
build-base \
webkit2gtk \
curl \
wget \
file \
openssl \
libayatana-appindicator-dev \
librsvg
```
</TabItem>
<TabItem label="NixOS">
:::note
Nix/NixOS 사용 방법에 대해서는 [NixOS Wiki](https://wiki.nixos.org/wiki/Tauri)를 참조하십시오.
:::
</TabItem>
</Tabs>
사용하는 배포판이 위에 포함되어 있지 않은 경우, [GitHub의 Awesome Tauri](https://github.com/tauri-apps/awesome-tauri#guides) 페이지를 참조하여 가이드 매뉴얼이 작성되었는지 확인해 보십시오.
다음 단계: [Rust 설치](#rust-설치)
### macOS
Tauri는 [Xcode](https://developer.apple.com/xcode/resources/)와 다양한 macOS 및 iOS 개발 관련 종속성을 이용합니다.
다음 사이트 중 하나에서 Xcode를 다운로드하여 설치합니다.
- [Mac App Store](https://apps.apple.com/gb/app/xcode/id497799835?mt=12)
- [Apple Developer website](https://developer.apple.com/xcode/resources/).
설치 후에는 반드시 Xcode를 시작하여 설정을 완료하십시오.
<details>
<summary>데스크톱 앱만 개발하는 경우 여기를 클릭</summary>
데스크톱 앱만 개발할 예정이고 iOS용 앱을 만들지 않는다면, 위의 "Xcode" 대신 "Xcode 명령줄 도구"를 설치할 수도 있습니다.
```sh
xcode-select --install
```
</details>
다음 단계: [Rust 설치](#rust-설치)
### Windows
Windows에서 개발하려면 Tauri는 Microsoft의 C++ Build Tools와 Microsoft Edge WebView2가 모두 필요합니다.
다음 작업 단계를 따라 필요한 종속성을 설치하십시오.
#### Microsoft C++ Build Tools
1. [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) 설치 프로그램을 다운로드하여 열고 설치를 시작합니다.
2. 설치 시 "Desktop development with C++" 옵션에 체크하십시오.
![Visual Studio C++ Build Tools installer screenshot](@assets/start/prerequisites/visual-studio-build-tools-installer.png)
다음 단계: [WebView2 설치](#webview2-설치).
#### WebView2 설치
:::tip
Windows 10(버전 1803) 이상의 Windows에서는 WebView 2가 이미 설치되어 있습니다. 개발에 사용하는 시스템 버전이 이들이라면 이 단계를 건너뛰고 직접 [Rust 설치](#rust-설치)로 진행하십시오.
:::
Tauri는 Windows에서 콘텐츠를 렌더링하기 위해 Microsoft Edge WebView2를 사용합니다.
Microsoft의 Webview2 다운로드 사이트 [Download the WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section) 섹션에서 "Evergreen Boostrapper" 파일을 다운로드하여 설치하십시오.
다음 단계: [Rust 설치](#rust-설치)
## Rust 설치
Tauri는 [Rust](https://www.rust-lang.org)로 만들어졌으며 개발에도 Rust가 필요합니다. Rust 설치에는 다음 방법 중 하나를 사용합니다. 다른 설치 방법에 대해서는 https://www.rust-lang.org/tools/install 을 참조하십시오.
<Tabs syncKey="OS">
<TabItem label="Linux 및 macOS" class="content">
다음 명령을 사용하여 Rust 버전 관리 도구인 [`rustup`](https://github.com/rust-lang/rustup)을 통해 설치합니다:
```sh
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
```
:::tip[안전을 위한 팁]
이 bash 스크립트는 확인되었으며 의도한 대로 작동합니다. 그러나 스크립트를 맹목적으로 "curl-bash" 명령으로 실행하는 것보다 항상 스크립트 내용을 사용하기 전에 확인하는 것이 현명합니다.
스크립트의 일반 텍스트 파일은 다음과 같습니다: [rustup.sh](https://sh.rustup.rs/)
:::
</TabItem>
<TabItem label="Windows">
`rustup`을 설치하려면 Rust 사이트 https://www.rust-lang.org/ko/tools/install 을 참조하십시오.
또는 PowerShell에서 다음과 같이 명령을 입력하여 `winget`을 사용하여 rustup을 설치할 수도 있습니다:
```powershell
winget install --id Rustlang.Rustup
```
:::caution[MSVC 툴체인이 기본값]
Tauri와 [`trunk`](https://trunkrs.dev/)와 같은 도구를 완전히 이용하려면 설치 프로그램 대화 상자에서 "MSVC Rust 툴체인"으로 `default host triple`이 선택되었는지 확인하십시오. 사용하는 컴퓨터 시스템에 따라 `x86_64-pc-windows-msvc`, `i686-pc-windows-msvc` 또는 `aarch64-pc-windows-msvc` 중 하나가 됩니다.
이미 Rust를 설치한 경우 다음 명령을 실행하여 올바른 "툴체인"이 설치되었는지 확인하십시오:
```powershell
rustup default stable-msvc
```
:::
</TabItem>
</Tabs>
**변경 사항을 적용하려면 반드시 터미널(경우에 따라 시스템 본체)을 다시 시작하십시오.**
다음 단계: Android 및 iOS용 개발을 수행하는 경우 [모바일 관련 설정](#모바일-관련-설정)을, 또는 JavaScript를 사용하는 경우 [Node 설치](#nodejs)를 실행하십시오. 그렇지 않으면 다음 장 [프로젝트 만들기](/ko/start/create-project/)로 진행하십시오.
## Node.js
:::note[JavaScript ecosystem]
JavaScript를 프론트엔드에 사용하는 경우에만 필요한 준비 처리입니다.
:::
1. [Node.js website](https://nodejs.org)를 열고 LTS 버전(장기 지원 버전)을 다운로드하여 설치하십시오.
2. 다음 명령을 실행하여 Node가 정상적으로 설치되었는지 확인합니다.
```sh
node -v
# v20.10.0
npm -v
# 10.2.3
```
터미널을 다시 시작하여 새로 설치한 프로그램이 인식되는지 확인하십시오. 경우에 따라 컴퓨터를 다시 시작해야 할 수도 있습니다.
"npm"은 Node.js의 기본 패키지 관리자이지만, "pnpm"이나 "yarn"과 같은 다른 패키지 관리자를 사용할 수도 있습니다. 이러한 패키지 관리자를 활성화하려면 터미널에서 `corepack enable`을 실행하십시오. 이 처리 단계는 "npm" 이외의 패키지 관리자를 사용하려는 경우에만 필요한 선택 사항입니다.
다음 단계: [모바일 관련 설정](#모바일-관련-설정) 또는 [프로젝트 만들기](/ko/start/create-project/)입니다.
## 모바일 관련 설정
Android나 iOS용 앱 개발을 수행하는 경우 설치해야 할 추가 종속성 모듈이 몇 가지 있습니다:
- [Android](#android)
- [iOS](#ios)
### Android
1. Android Developers website에서 [Android Studio](https://developer.android.com/studio)를 다운로드하여 설치합니다.
2. `JAVA_HOME` 환경 변수를 설정합니다:
{/* TODO: Can this be done in the 4th step? */}
<Tabs syncKey="prereqs">
<TabItem label="Linux">
```sh
export JAVA_HOME=/opt/android-studio/jbr
```
</TabItem>
<TabItem label="macOS">
```sh
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
```
</TabItem>
<TabItem label="Windows">
```ps
[System.Environment]::SetEnvironmentVariable("JAVA_HOME", "C:\Program Files\Android\Android Studio\jbr", "User")
```
</TabItem>
</Tabs>
3. "Android Studio"의 "SDK Manager"를 사용하여 다음을 설치합니다:
- Android SDK Platform
- Android SDK Platform-Tools
- NDK (Side by side)
- Android SDK Build-Tools
- Android SDK Command-line Tools
SDK 관리자에서 "패키지 세부 정보 표시"를 선택하면 이전 버전의 패키지를 설치할 수 있습니다. 이전 버전은 **필요한 경우에만** 설치하십시오. 호환성 문제나 보안 위험이 발생할 수 있습니다.
4. `ANDROID_HOME` 및 `NDK_HOME` 환경 변수를 설정합니다.
<Tabs syncKey="prereqs">
<TabItem label="Linux">
```sh
export ANDROID_HOME="$HOME/Android/Sdk"
export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)"
```
</TabItem>
<TabItem label="macOS">
```sh
export ANDROID_HOME="$HOME/Library/Android/sdk"
export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)"
```
</TabItem>
<TabItem label="Windows">
```ps
[System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "$env:LocalAppData\Android\Sdk", "User")
$VERSION = Get-ChildItem -Name "$env:LocalAppData\Android\Sdk\ndk"
[System.Environment]::SetEnvironmentVariable("NDK_HOME", "$env:LocalAppData\Android\Sdk\ndk\$VERSION", "User")
```
:::tip
PowerShell은 다시 시작하거나 로그아웃할 때까지 새 환경 변수 설정이 적용되지 않지만,
현재 세션을 업데이트할 수 있습니다:
```ps
[System.Environment]::GetEnvironmentVariables("User").GetEnumerator() | % { Set-Item -Path "Env:\$($_.key)" -Value $_.value }
```
:::
</TabItem>
</Tabs>
5. `rustup`으로 Android를 "대상"에 추가합니다:
```sh
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
```
다음 단계: [iOS용 설정](#ios) 또는 [프로젝트 만들기](/ko/start/create-project/).
### iOS
:::caution[macOS만]
iOS 개발 종속성에는 Xcode가 필요하며 macOS에서만 사용할 수 있습니다. 위 [macOS 관련 종속성 설정 설명](#macos) 부분에 있는 대로 "Xcode 명령줄 도구"가 아닌 "Xcode" 자체가 설치되어 있는지 확인하십시오.
:::
1. 터미널에서 `rustup`을 사용하여 iOS를 "대상"에 추가합니다:
```sh
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
```
2. macOS용 패키지 관리자 [Homebrew](https://brew.sh)를 설치합니다:
```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
3. Homebrew를 사용하여 iOS용 라이브러리 관리 도구 [Cocoapods](https://cocoapods.org)를 설치합니다:
```sh
brew install cocoapods
```
다음 단계: [프로젝트 만들기](/ko/start/create-project/).
## 문제가 발생하면
설치 중에 문제가 발생하면 "[문제 해결 관련 항목](/ko/develop/debug/)"을 참조하거나 "[Tauri 커뮤니티](https://discord.com/invite/tauri)"에 문의해 보십시오.
<Card title="Next Steps" icon="rocket">
모든 필요 사항을 설치했으므로 이제 [첫 Tauri 프로그램 만들기](/ko/start/create-project/) 준비가 되었습니다!
</Card>

View File

@@ -0,0 +1,58 @@
---
title: 프로젝트 구조
i18nReady: true
---
Tauri 프로젝트는 일반적으로 "Rust 프로젝트"와 "JavaScript 프로젝트"(선택 사항) 두 부분으로 구성되며,
일반적인 설정 구성은 다음과 같습니다:
```
.
├── package.json
├── index.html
├── src/
│ ├── main.js
├── src-tauri/
│ ├── Cargo.toml
│ ├── Cargo.lock
│ ├── build.rs
│ ├── tauri.conf.json
│ ├── src/
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── icons/
│ │ ├── icon.png
│ │ ├── icon.icns
│ │ └── icon.ico
│ └── capabilities/
│ └── default.json
```
위의 경우, "JavaScript 프로젝트"가 최상위에 있고, "Rust 프로젝트"는 `src-tauri/` 내에 있습니다.
"Rust 프로젝트"는 몇 가지 파일이 추가된 일반적인 [Cargo 프로젝트](https://doc.rust-lang.org/cargo/guide/project-layout.html)입니다:
- `tauri.conf.json`은 Tauri의 기본 설정 파일로, 애플리케이션 식별자부터 개발 서버 URL까지 모든 것을 포함합니다.
이 파일은 [Tauri CLI](/reference/cli/)가 Rust 프로젝트를 찾는 마커이기도 합니다.
자세한 내용은 [Tauri Config](/ko/develop/configuration-files/#tauri-설정)를 참조하십시오.
- `capabilities/` 디렉토리는 Tauri가 [보안 수준 파일](/ko/security/capabilities/)을 읽는 기본 폴더입니다(즉, JavaScript 코드에서 이 파일을 사용하려면 이 폴더에 대한 명령 접근을 허용해야 합니다).
자세한 내용은 [보안](/ko/security/)을 참조하십시오.
- `icons/` 디렉토리는 [`tauri icon`](/reference/cli/#icon) 명령의 기본 출력 디렉토리이며, 일반적으로 `tauri.conf.json > bundle > icon`에서 참조되어 앱 아이콘으로 사용됩니다.
- `build.rs`에는 tauri의 빌드 시스템에 사용되는 `tauri_build::build()`가 포함되어 있습니다.
- `src/lib.rs`에는 "Rust 코드"와 "모바일 진입점"(`#[cfg_attr(mobile, tauri::mobile_entry_point)]`으로 표시된 함수)이 포함되어 있습니다.
`main.rs` 내에 직접 작성하지 않는 이유는 앱을 각 모바일 빌드의 라이브러리를 사용하여 컴파일하고 각 플랫폼 프레임워크를 통해 로드하기 때문입니다.
- `src/main.rs`는 데스크톱의 "메인 진입점"이며, 모바일과 동일한 진입점을 사용하기 위해 `main` 내에서 `tauri_app_lib::run()`을 실행합니다.
따라서 처리를 간단하게 하기 위해 이 파일은 변경하지 말고 대신 `lib.rs`를 변경하십시오.
Tauri는 "정적 웹 호스트"와 유사하게 작동합니다. 빌드 방법은 먼저 "JavaScript 프로젝트"를 정적 파일(들)로 컴파일한 다음,
해당 정적 파일을 번들링하는 "Rust 프로젝트"를 컴파일합니다.
이 때문에 "JavaScript 프로젝트"의 구성은 마치 정적 웹사이트를 구축한 것처럼 기본적으로 동일합니다.
자세한 내용은 [프론트엔드 설정](/ko/start/frontend/)을 참조하십시오.
Rust 코드로만 프로젝트를 구성하려면 `src-tauri/` 폴더 이외의 모든 것을 삭제하고 `src-tauri/` 폴더를 최상위 프로젝트로 또는 Rust 작업 공간의 멤버로 사용하기만 하면 됩니다.
## 다음 단계는...
- [프론트엔드 설정](/ko/start/frontend/)
- [Tauri 명령줄 인터페이스](/reference/cli/)(영어)
- [Tauri 앱 개발 방법](/ko/develop/)
- [Tauri 확장을 위한 추가 기능](ko/plugin/)

View File

@@ -52,8 +52,8 @@ The header values are always converted to strings for the actual response. Depen
Those are the rules on how a composite gets created: Those are the rules on how a composite gets created:
- `string`: stays the same for the resulting header value - `string`: stays the same for the resulting header value
- `array`: items are joined by `, `  for the resulting header value - `array`: items are joined by `, ` for the resulting header value
- `key-value`: items are composed from: key + space + value. Items are then joined by `; `  for the resulting header value - `key-value`: items are composed from: key + space + value. Items are then joined by `; ` for the resulting header value
- `null`: header will be ignored - `null`: header will be ignored
### Example ### Example