├── 0000-template.md ├── README.md └── texts ├── 0001-webview_bindings.md ├── 0003-code-teams.md ├── 0004-wry-raw-window-handle.md └── 0005-tauri-config-restructure.md /0000-template.md: -------------------------------------------------------------------------------- 1 | - Feature Name: (fill me in with a unique ident, `my_awesome_feature`) 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [tauri-apps/rfcs#0000](https://github.com/tauri-apps/rfcs/pull/0000) 4 | - Tracking Issue: [tauri-apps/tauri#0000](https://github.com/tauri-apps/tauri/issues/0000) 5 | 6 | # Summary 7 | 8 | One paragraph explanation of the feature. 9 | 10 | # Motivation 11 | 12 | Why are we doing this? What use cases does it support? What will developers, end-users and core-devs gain from this? What is the expected outcome? 13 | 14 | # Guide-level explanation 15 | 16 | - Explaining the feature largely in terms of examples. 17 | - If applicable, provide sample error messages, deprecation warnings, or migration guidance. 18 | - If applicable, describe how this feature can be taught to existing and new Tauri developers. 19 | 20 | # Reference-level explanation 21 | 22 | The technical portion of the RFC. Please explain in detail: 23 | 24 | - How the feature interacts with other features. 25 | - That it is reasonably clear how the feature would be implemented. 26 | - Any corner cases should be covered by examples. 27 | - Does this require stale dependencies to be forked? What is the long-term impact on core-developers? Does this introduce additional maintenance load? 28 | 29 | The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. 30 | 31 | ## Platform Considerations 32 | 33 | Tauri works across a wide variety of platforms (Operating Systems, Architectures, Hardware Configurations). Please explain: 34 | - If applicable, how this feature interacts with different platforms and whether some platforms introduce special behavior. 35 | - If this feature can only be supported on a subset of platforms, explain why. 36 | 37 | ## Security Considerations 38 | 39 | Tauri is a very security conscious project. Please explain in detail: 40 | - How does this feature impacts the security of Tauri apps. 41 | - If applicable, what design decisions you have taken to increase the security of this feature and Tauri apps at large. 42 | - If it's clear that this feature will require the addition of new dependencies, how this feature impact Tauris risk of supply chain attacks. 43 | 44 | ## Performance Considerations 45 | 46 | How will this feature impact the performance of a Tauri app? 47 | 48 | ## Community Considerations 49 | 50 | How does this impact community libraries, tools and other work? Does this invalidate existing tutorials and learning materials? 51 | 52 | # Drawbacks 53 | 54 | Why should we *not* do this? 55 | What are the limitations of this approach? 56 | 57 | # Rationale and alternatives 58 | 59 | - Why is this design the best in the space of possible designs? 60 | - What other designs have been considered and what is the rationale for not choosing them? 61 | - What is the impact of not doing this? 62 | - If this is a language proposal, could this be done in a library or plugin instead? 63 | 64 | # Prior art 65 | 66 | Discuss prior art, both the good and the bad, in relation to this proposal. 67 | A few examples of what this can include are: 68 | 69 | - For community proposals: Is this done by some other community and what were their experiences with it? 70 | - For other teams: What lessons can we learn from what other communities have done here? 71 | - Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. 72 | 73 | # Unresolved questions 74 | 75 | - What parts of the design do you expect to resolve through the RFC process before this gets merged? 76 | - What parts of the design do you expect to resolve through the implementation of this feature before stabilization? 77 | - What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tauri Request For Comment 2 | 3 | This repo is dedicated to the Tauri RFC (Request for Comment) process. When there are significant changes to Tauri this allows the project to undergo a transparent conversation and confirm changes by accepting and merging them into the repo. 4 | 5 | ## When To Create An RFC 6 | 7 | Not everything necessarily requires an RFC. Sometimes you may wish to have a discussion before writing a full RFC or to simply submit an idea. Here's when you could use a [Feature Request](https://github.com/tauri-apps/tauri/issues/new?assignees=&labels=type%3A+feature+request&template=feature_request.yml&title=%5Bfeat%5D+) to start off the conversation. 8 | 9 | Be sure to check through the [existing feature requests in the Tauri repo](https://github.com/tauri-apps/tauri/labels/type%3A%20feature%20request) as your idea may already be there and would be a good place to add your input into! 10 | 11 | ## RFC Process 12 | 13 | 1) Create an RFC Pull Request by following the steps in the [Creating an RFC](#creating-an-rfc) section below. 14 | 2) Once a PR is opened in this repo then the review process begins. This will be left open for a minimum of 2 weeks to allow comment. 15 | 3) After this time period a member of the Tauri Working Group will handle closing the RFC. If accepted, the RFC will be assigned a number. 16 | 4) If an implementation is already underway then the respective PR will be added to the RFC to track. If no implementation is started then a tracking issue in the respective repo will be created and added to the RFC to track. 17 | 18 | An accepted RFC does not necessarily mean that Tauri will be actively working on implementation, but instead signals that the the details in the RFC align with the overall goals of Tauri. The tracking issue or implementation PR are where the status of an RFC's implementation (in implementation, open to someone contributing, etc.) can be found. 19 | 20 | ## Creating an RFC 21 | 22 | Once you have enough information to begin an RFC you can follow this process to get started: 23 | 24 | 1) **Fork this repo** 25 | 2) **Copy the template** Move your copy of `template.md` into the `texts` folder, naming it in the scheme of `0000-feature.md`. Note: the number is literal and will be adjusted just before merging. 26 | 3) **Fill out the template** Replace all relevant sections with explanations. Put care into the details, as it will serve as a reference through the development process. 27 | 4) **Open a PR** After opening a PR, the RFC is open for comment. Discussion should happen in the comments of the PR. RFCs that are "invalid" (don't follow the format/proceedure, violate CoC, or are otherwise unable to be used) may be closed immediately. 28 | 5) **Merged into the repo** The final stage of an RFC that signals it is accepted is it being merged into this repo. If a PR for an implementation is already submitted then it will be used to track the status from there. Otherwise a tracking issue will be created in the respective repo to capture the implementation status. 29 | -------------------------------------------------------------------------------- /texts/0001-webview_bindings.md: -------------------------------------------------------------------------------- 1 | # RFC #0001 Webview 2 | 3 | | Status | Proposed | 4 | :-------------- | ---------------------------------------------------- | 5 | | **RFC #** | 0001 | 6 | | **Authors** | Daniel Thompson-Yvetot (denjell@tauri.studio), Tensor Programming (tensor@tauri.studio) | 7 | | **External Sponsor** | Erlend (e.soghe@gmail.com) | 8 | | **Updated** | 2020-03-10 | 9 | 10 | 11 | ## Objective 12 | We would like to have more direct involvement in the critical upstream libraries upon which Tauri is built. 13 | 14 | ## Motivation 15 | Tauri is a project that is heavily reliant on upstream bindings (currently boscop/web-view and zserge/webview). Over the past year there have been spurts of activity in both of these upstream resources, but communication with the lead developers has been challenging. 16 | 17 | Furthermore, these two libraries have diverged in their source and approach and it is difficult to know where to contribute, let alone know when PRs will be merged. 18 | 19 | Not only are there outstanding features (like [transparent and borderless windows](https://github.com/Boscop/web-view/commit/55f619190e6aa8c54fde8cf72d71a5126238a5e3), [additional menu items](https://github.com/Boscop/web-view/pull/125) etc.), but also [severe memory leaks](https://github.com/Boscop/web-view/issues/79). 20 | 21 | Since we plan to release our Beta at some point in the next 4 months, we absolutely cannot carry this kind of architectural debt with us and need to come to a decision within the next 10 days. 22 | 23 | ## User Benefit 24 | - Consumers of Tauri will be able to have assurance that we are able to protect and maintain essential code. 25 | - The open source community at large becomes less fractured and our work will directly support other communities using webviews. 26 | - Consuming from the "pure" webview source will enable Tauri projects to more easily use other bindings at some point in the future. 27 | 28 | ## Design Proposal 29 | 30 | ### In any Case 31 | We will create generic mappings to the rust bindings, this will allow developers to more easily switch to other forks of webview and potentially other rendering engines entirely. 32 | 33 | ### Solution 34 | We would like to pool our efforts with the OSS community. Our preferance was to take part in the creation of an organization along side @boscop. This is looking to be less likely at this point in time, so we will play it safe and create our own abstraction layer over the various webview backends. This will allow us and our users to pick and chose which is most ideal per platform, as well as make such changes non-breaking and open us up to patching in backends. 35 | 36 | ### Alternatives Considered 37 | - Writing our own bindings. 38 | - Doing nothing and waiting. 39 | 40 | ### Performance Implications 41 | We expect general improvements across the board. 42 | 43 | ### Dependencies 44 | The way this plays out will necessarily impact the dependency tree, but it will be transparent for consumers of Tauri. Also, some of the C++ dependencies will be easier to consume on certain platforms. 45 | 46 | ### Engineering Impact 47 | We expect binary sizes to remain the same and hope to have improved memory management for Windows platforms. 48 | 49 | ### Platforms and Environments 50 | This will affect all platforms, but again, it will not affect the way in which Tauri works on a fundamental level. 51 | 52 | ### Security Impact 53 | Maintaining some kind of influence over the bindings and the headers needed for properly and safely using webviews will absolutely enhance our security posture. 54 | 55 | ### Tutorials and Examples 56 | Since this will mostly concern developers of the library itself, we should anticipate enhancing our own documentation in any case. 57 | 58 | ### Compatibility 59 | There may be API changes, but it will fall in the scope of ALPHA. For information regarding the API changes, refer to the webview repository's [readme](https://github.com/zserge/webview). 60 | 61 | ### User Impact 62 | We anticipate only forward-changes with additionally exposed APIs. 63 | 64 | ## Questions and Discussion Topics 65 | What do you think? Is it going to be better for Tauri to hard fork and go its own way - or be part of the community and work together? 66 | 67 | Would you be more willing to contribute to the webview organization or the Tauri organization? (Or doesn't it matter?) 68 | -------------------------------------------------------------------------------- /texts/0003-code-teams.md: -------------------------------------------------------------------------------- 1 | # RFC #0003 Org Code Teams 2 | 3 | | Status | Proposed | 4 | :-------------- | ---------------------------------------------------- | 5 | | **RFC #** | 0003 | 6 | | **Authors** | Jacob Bolda ( jacob@tauri.studio / @JacobBolda#4211 ) | 7 | | **Sponsor** | core | 8 | | **Updated** | 2020-09-12 | 9 | 10 | ## Objective 11 | Create teams for the various areas of code and docs to help expand our team, create sense of ownership, guide code improvements (through defined tasks), and facilitate decisions. 12 | 13 | ## Motivation 14 | We are sorely in need of help now and in the future when core members get busy or burned out. We need a pipe to bring people in and a way for those on a team to step back when they need the headspace. 15 | 16 | ## Design Proposal 17 | 18 | ### Solution 19 | Create teams (and a workflow to create more in the future) to cover the main parts of the code. Each team's primary function is to drive discussion and facilitate decisions around their area of the code. The team will make a final decision, but it cannot be finalized until the recommendation is put forward to the community to discuss. (The intent to prevent dictator or "from on high" type decisions.) 20 | 21 | As decisions are made, the team should create tasks to take the decision to completion. The tasks should be of a size that is achievable in a PR. This will help scope work to something that anyone could reasonably hop into the code with minimal familiarity and help out. 22 | 23 | Secondary responsibilities would be review the PRs and enable the docs to make it easy for someone to come in and contribute to that portion on the code. ("Docs" doesn't necessarily need to be something on tauri.studio.) 24 | 25 | To address the inflow and outflow of members, we will list all team members and "open positions". Each team should have 3+ members, 3 of which being the primary members. The primary members should have the most expectation of responsibility. The primary members are not lifetime, static positions. There is an expectation that they change with some frequency and not be a "reward" to be earned. 26 | 27 | Members may step back as an "alumnus" member. All roles operate in the open so this is doesn't reduce access in any manner. Rather, the intent is to signal that the time is not available for them to give real attention to the project. A way that one could temporarily or permanently step back without any guilt. 28 | 29 | ### Breakdown 30 | #### Teams 31 | - Tauri Core 32 | - Tauri CLIs 33 | - usage 34 | - onboarding of new users 35 | - Tauri APIs and Commands 36 | - importing Tauri and using it in your app 37 | - Tauri Bundler 38 | - Webview (interfacing with and work to make certain it has the APIs we need) 39 | 40 | ### Engineering Impact 41 | #### Will this increase or decrease build times, developer workload etc.? 42 | More hands should help spread the load and improve the velocity of the docs and code. 43 | 44 | ### Security Impact 45 | #### What changes will this bring, if any, to the security model of CI, developers and users? 46 | This should allow us to bring in more people to help out. More eyes covering every corner will result in more bugs being caught, and relieving some of the managerial duties from core should allow more attention to security. 47 | -------------------------------------------------------------------------------- /texts/0004-wry-raw-window-handle.md: -------------------------------------------------------------------------------- 1 | - Feature Name: wry-raw-window-handle 2 | - Start Date: 16-10-2023 3 | - RFC PR: [tauri-apps/rfcs#12](https://github.com/tauri-apps/rfcs/pull/12) 4 | - Implementation PR: https://github.com/tauri-apps/wry/pull/1041 5 | - Tracking Issue: [tauri-apps/wry#677](https://github.com/tauri-apps/wry/issues/677) 6 | 7 | # Summary 8 | 9 | Make WRY agnostic of the windowing library used and accept a raw-window-handle or gtk-window-handle where applicable. 10 | 11 | # Motivation 12 | 13 | This has been requested in [tauri-apps/wry#677](https://github.com/tauri-apps/wry/issues/677) a long time ago and at work at CrabNebula, 14 | we have been contracted to research and develop an integration of wry and wgpu/bevy. We had a successful results and it aligned with [tauri-apps/wry#677](https://github.com/tauri-apps/wry/issues/677) 15 | so we did an initial implemention of this RFC for Windows which can be found here https://github.com/crabnebula-dev/wry/commits/feat/embedded-webview and we think 16 | it is a good oprtunity to upstream this work. 17 | 18 | # Guide-level explanation 19 | There is two groups of window handles we will need to take in order to support the current platforms we support: 20 | 21 | #### Raw window handle: 22 | This group could leverage the `raw-window-handle` crate; this includes macOS, Windows and Linux (x11) platforms. 23 | - Using winit, tao, egui or any other windowing library that 24 | implements [`raw_window_handle::HasWindowHandle`](https://docs.rs/raw-window-handle/latest/raw_window_handle/trait.HasWindowHandle.html) trait 25 | (or previous versions of `raw-window-handle` crate): 26 | ```rs 27 | let window = Window::new(&evl); // Window implements HasWindowHandle 28 | let webview = WebView::new(&window); 29 | ``` 30 | 31 | - Using raw win32: 32 | ```rs 33 | let hwnd = CreateWindowExW(/* args */); 34 | let webview = WebView::new_hwnd(hwnd); 35 | ``` 36 | 37 | - Using raw AppKit NSWindow: 38 | ```rs 39 | let ns_window = msg_send![/* args */]; 40 | let webview = WebView::new_ns_view(ns_window.contentView()); 41 | ``` 42 | 43 | - Using raw X11 (not recommended): 44 | ```rs 45 | // must initialize gtk first 46 | gtk::init().unwrap(); 47 | let window = XCreateWindow(/* args */); 48 | let webview = WebView::new_x11(window); 49 | 50 | // and in event loop, you need to advance the gtk loop as well 51 | loop { 52 | // 1. handle x11 event loop 53 | // 1. handle gtk event loop through `gtk::main_iteration_do` 54 | } 55 | ``` 56 | 57 | #### Gtk handle: 58 | This group leverages the gtk types, includes Linux platform only (X11 and Wayland). 59 | - Using raw gtk: 60 | ```rs 61 | let gtk_window = gtk::ApplicationWindow::new(/* args */); 62 | let webview = WebView::new_gtk(>k_window); 63 | ``` 64 | 65 | - Using tao: 66 | ```rs 67 | let window = Window::new(/* args */); 68 | let gtk_window = window.gtk_window(); 69 | let webview = WebView::new_gtk(>k_window); 70 | ``` 71 | 72 | 73 | # Reference-level explanation 74 | 75 | There is 2 APIs this RFC is proposing: 76 | - `WebView::new(raw_window_handle)/Webview::new_gtk(gtk_wdiget_handle)` (current behavior) 77 | initializes the webview directly in the passed handle. 78 | - Supported platforms: Windows, macOS and Linux (X11 & Wyaland) 79 | - Does NOT support `webview.set_position()` as managing the size and position of the webview should be done by sizing or changing the position of 80 | the handle passed in. 81 | - `WebView::new_as_child(parent_raw_window_handle)` initializes the Webview as a child in the passed window handle, this allows for multiple webviews in 82 | the same window handle passed. 83 | - Supported platforms: Windows, macOS and Linux (X11 Only) 84 | - Supports `webview.set_position()/webview.set_size()` to change the position and size of the webview child inside the parent. 85 | 86 | There will also be equivalent methods that is specific to each platform, in case someone don't want to 87 | go through `raw-window-handle` crate: 88 | - `WebView::new_hwnd(hwnd)` and `WebView::new_as_child_hwnd`: Windows Only 89 | - `WebView::new_x11(hwnd)` and `WebView::new_as_child_x11`: Linux(X11) Only 90 | - `WebView::new_ns_view(hwnd)` and `WebView::new_as_child_ns_view`: macOS Only 91 | 92 | ## Platform Considerations 93 | 94 | - While Linux (X11) appears in both groups, it is recommended to be used through the gtk window handle instead of the raw X11 handle because 95 | to use the raw x11 handle, you'd still need to initialize gtk and advance its event loop alongside the x11 loop. 96 | - Linux (Wayland) doesn't allow creating a raw `GdkWaylandWindow` from a raw wayland window, so it can only be part of the "Gtk handle" group. 97 | - On Linux, which ever API you choose to use, the developer has to ensure that they initialize gtk through `gtk::init` and 98 | have a gtk event loop running on the thread, either alone or with another loop like X11 event loop using `gtk::main_iteration_do` 99 | 100 | ## Community Considerations 101 | 102 | Implementing this RFC will open up WRY to the broader Rust ecosystems (and potentioally other languages and runtimes). 103 | 104 | # Drawbacks 105 | 106 | _None that I can think of at the moment_ 107 | 108 | # Rationale and alternatives 109 | 110 | Another alternative is to add this RFC behind a feature flag and make it opt-in for those who need it. 111 | 112 | # Unresolved questions 113 | 114 | ### Android 115 | While Android have a form of multi windows, it is not the same as multi windows on Desktop and the current Android implementation 116 | doesn't require any access to a "Window" type of sorts and operates on the assumption that it is One-window, instead it requires an 117 | invokation of a macro to setup some JNI callbacks that is used later to add a webview to the current Android activity. There is no PoCs yet 118 | for this but in theory, the relevant parts from TAO could be extracted out into WRY repo while keeping the current behavior which doesn't conflict with 119 | this proposal. 120 | 121 | ### iOS 122 | _unexplored, needs someone with iOS experience_ 123 | -------------------------------------------------------------------------------- /texts/0005-tauri-config-restructure.md: -------------------------------------------------------------------------------- 1 | - Feature Name: tauri_config_restructure 2 | - Start Date: 2023-12-20 3 | - RFC PR: [tauri-apps/rfcs#13](https://github.com/tauri-apps/rfcs/pull/13) 4 | - Tracking Issue: 5 | 6 | # Summary 7 | 8 | Restructuring the `tauri.conf.json` for more simplicity, consistency and clarity. 9 | 10 | # Motivation 11 | 12 | The current `tauri.conf.json` has a bunch of objects that don't necessarily follow a rule that could reason why they exist there and thus makes it awkward to figure out where to add new fields 13 | for example `tauri > bundle` object is a configuration for the CLI, why does it exist inside `tauri` object, another example is the `plugins` object which is a tauri feature, why does it exist outside of `tauri` object? 14 | These inconsistencies will make it harder to add new fields to the config. 15 | 16 | # Guide-level explanation 17 | 18 | - Unpack `package` fields to the root object. 19 | - Rename `tauri` object to `app`. 20 | - Move `tauri > bundle > identifier` to the root object as it is used by other places in tauri other than bundling. 21 | - Remove `bundle > updater` as the only useful key it has, is `pubkey` field and that should be moveed to `plugin > updater > pubkey`. 22 | This will require changes in the CLI to only sign the bundles when `TAURI_SIGNING_PRIVATE_KEY` key is set . 23 | This will also fix a huge DX when using `tauri-plugin-updater` and you endup having to configure updater-related configs once in `bundle > updater` and `plugin > updater`. 24 | - Move `build > withGlobalTauri` to the new `app > withGlobaltauri` object. 25 | - Move `tauri > pattern` to `app > security > pattern` and make it accept a simple string for `brownfield`. 26 | - Move `tauri > cli` and `tauri > update` fields to `plugins > cli` and `plugins > update` as they are plugins now. 27 | - Rename `build > distDir` to `build > frontendDist` to explicitly set the intent of the option. 28 | - Rename `build > devPath` to `build > devUrl` and only accept urls, 29 | if users don't have a devServer, they should remove this field and only set `build > frontendDist` which will make the CLI 30 | start its built-in devServer or fallback to embed the assets if `--no-dev-server` is used. 31 | - Move `tauri > bundle` to root object. 32 | 33 |
Current Config | 37 |New Config | 38 |
---|---|
43 | 44 | ```jsonc 45 | { 46 | "build": { 47 | "beforeDevCommand": "pnpm dev", 48 | "beforeBuildCommand": "pnpm build", 49 | "devPath": "http://localhost:8080/", 50 | "distDir": "../src", 51 | "withGlobalTauri": true 52 | }, 53 | "package": { 54 | "productName": "tauri-app", 55 | "version": "0.0.0" 56 | }, 57 | "tauri": { 58 | "allowlist": { 59 | "all": true 60 | }, 61 | "bundle": { 62 | "active": true, 63 | "targets": "all", 64 | "identifier": "com.taasduri.dev", 65 | "icon": [ 66 | "icons/32x32.png", 67 | "icons/128x128.png", 68 | "icons/128x128@2x.png", 69 | "icons/icon.icns", 70 | "icons/icon.ico" 71 | ] 72 | }, 73 | "updater": { 74 | "active": true, 75 | "pubkey": "", 76 | "endpoints": ["http://localhost:8080/update.json"], 77 | "windows": { 78 | "installMode": "basicUi" 79 | } 80 | }, 81 | "cli": {}, 82 | "macOSPrivateApi": false, 83 | "security": { 84 | "csp": null 85 | }, 86 | "pattern": { 87 | "use": "brownfield" 88 | }, 89 | "systemTray": { 90 | "iconPath": "./path/to/icon" 91 | }, 92 | "windows": [ 93 | { 94 | "title": "tauri-app", 95 | "width": 800, 96 | "height": 600 97 | } 98 | ] 99 | } 100 | } 101 | ``` 102 | 103 | | 104 |105 | 106 | ```jsonc 107 | { 108 | "productName": "tauri-app", 109 | "version": "0.1.0", 110 | "identifier": "com.tauri.dev", 111 | "build": { 112 | "beforeDevCommand": "pnpm dev", 113 | "beforeBuildCommand": "pnpm build", 114 | "devUrl": "http://localhost:8080/", 115 | "frontendDist": "../src" // or ["../src/index.html", "../src/main.js"] if need to include specific files 116 | }, 117 | "app": { 118 | "windows": [ 119 | { 120 | "title": "tauri-app", 121 | "width": 800, 122 | "height": 600 123 | } 124 | ], 125 | "withGlobalTauri": true, 126 | "macosPrivateApi": false, 127 | "trayIcon": { 128 | "iconPath": "./path/to/icon" 129 | }, 130 | "allowlist": { // soon to be replaced with permissions and cababilities 131 | "all": true 132 | }, 133 | "security": { 134 | "pattern": "brownfield", 135 | "csp": null 136 | }, 137 | "plugins": { 138 | "cli": {}, 139 | "updater": { 140 | "pubkey": "", 141 | "endpoints": ["http://localhost:8080/update.json"], 142 | "windows": { 143 | "installMode": "basicUi" 144 | } 145 | } 146 | } 147 | }, 148 | "bundle": { 149 | "active": true, 150 | "targets": "all", 151 | "icon": [ 152 | "icons/32x32.png", 153 | "icons/128x128.png", 154 | "icons/128x128@2x.png", 155 | "icons/icon.icns", 156 | "icons/icon.ico" 157 | ] 158 | } 159 | } 160 | ``` 161 | 162 | | 163 |