TuBrief
구독 채널
비디오
커뮤니티

Como distribuir apps de desktop criados por um desenvolvedor solo sem avisos de segurança

TuBrief 편집팀
2026년 7월 15일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

Português한국어EnglishEspañol中文العربيةहिन्दीDeutschFrançaisРусскийBahasa Indonesia日本語

관련 영상

Qual é a melhor alternativa ao Electron? Vamos descobrir.6:33

Qual é a melhor alternativa ao Electron? Vamos descobrir.

Better Stack

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Como distribuir apps de desktop criados por um desenvolvedor solo sem avisos de segurança

Se você terminou um aplicativo de desktop que roda perfeitamente localmente, o desenvolvimento está apenas pela metade. O verdadeiro obstáculo começa no momento em que o usuário clica no link de download e uma janela de aviso vermelha aparece na tela, dizendo algo como "arquivo corrompido" ou "o computador foi protegido".

Superar as barreiras de segurança do sistema operacional, controlar a velocidade de build e criar um sistema de atualização automática que mantenha a versão mais recente sempre que o usuário abrir o app é algo mais cansativo do que parece. Mesmo que você tenha escolhido o Tauri v2 por ser mais leve que o Electron, os problemas práticos do processo de distribuição permanecem. Reuni abaixo formas de desenvolvedores solo ou pequenas equipes distribuírem seus produtos de forma limpa, sem desperdiçar tempo e dinheiro desnecessários.


1. Usar assinatura na nuvem em vez de certificados de 700 dólares por ano

Um app de desktop sem Code Signing (assinatura de código) é tratado como malware pelo sistema operacional. Para evitar que avisos de segurança apareçam no PC do usuário, você precisa de dinheiro e burocracia.

macOS: Configuração de Apple Developer Account e Entitlements

Para distribuir no macOS, é obrigatório aderir ao Apple Developer Program, que custa 99 dólares por ano. Uma vez obtida a conta, você deve criar um arquivo src-tauri/Entitlements.plist que defina as permissões de exceção de segurança de memória para que o webview do Tauri funcione corretamente. Se essa configuração faltar, o app fechará imediatamente após ser aberto.

`xml




com.apple.security.cs.allow-jit

com.apple.security.cs.allow-unsigned-executable-memory


`

Especifique este arquivo na opção de bundle do seu src-tauri/tauri.conf.json.

`json
{
"bundle": {
"macOS": {
"signingIdentity": "Developer ID Application: Your Name (TEAMID)",
"entitlements": "./Entitlements.plist",
"minimumSystemVersion": "11.0",
"dmg": {
"appPosition": { "x": 180, "y": 170 },
"applicationFolderPosition": { "x": 480, "y": 170 }
}
}
}
}

`

Windows: Economizando com o Azure Trusted Signing

Antigamente, para passar pelo filtro SmartScreen do Windows, era necessário obter um certificado EV (Extended Validation) na forma de um token USB físico, custando entre 400 e 700 dólares por ano. Além do custo, é extremamente trabalhoso para um indivíduo gerenciar.

A alternativa é o Azure Trusted Signing (ATS), o serviço de assinatura baseado em nuvem da Microsoft. Pagando apenas uma taxa de assinatura mensal na casa dos 9,99 dólares, o processo de assinatura é feito dentro da nuvem HSM gerenciada pela Microsoft, eliminando a necessidade de manter chaves físicas.

  1. Crie uma conta no Azure Trusted Signing e um perfil de certificado no portal do Azure.
  2. Insira as informações de assinatura do Azure (Secrets no GitHub Actions: AZURE_TENANT_ID, CLIENT_ID, CLIENT_SECRET) e as informações do ATS.
  3. Durante o processo de build, execute o sign-tool para aplicar a assinatura digital nos arquivos MSI ou EXE compilados pelo Tauri.

Apps assinados desta forma evitam os avisos do Windows SmartScreen desde o primeiro download, ajudando a reter usuários que poderiam desistir durante a instalação.


2. Como acelerar o build no GitHub Actions em 90%

O Tauri é leve, mas o processo de build exige rodar o compilador Rust e a cadeia de ferramentas nativa de cada SO. É comum ter erros de linker no computador de outros membros da equipe ou ter builds corrompidos devido à poluição de dependências do ambiente local, mesmo que funcione na sua máquina. Builds de distribuição devem, obrigatoriamente, rodar em um pipeline de CI/CD isolado.

O problema é que o executor hospedado padrão do GitHub não tem especificações suficientes para compilar Rust rapidamente. Se a estrutura baixa as dependências e compila tudo do zero a cada vez, um build de release pode facilmente levar mais de 10 minutos.

Neste caso, em vez de usar apenas o actions/cache para compactar e enviar arquivos para a nuvem, combinar plugins de cache dedicados que visam armazenamento NVMe de alto desempenho (swatinem/rust-cache) ou usar executores hospedados dedicados (como Namespace ou Depot) mudará drasticamente a velocidade.

Com base nos logs de build do projeto open source de player de música spotify-player, aqui está a comparação de desempenho entre um executor comum do GitHub e um executor dedicado com cache de volume local aplicado:

Plataforma e Configuração de Cache Tempo no executor comum do GitHub Tempo com otimização de cache Redução no tempo de build
Ubuntu Linux 9min 31s 34s 94,0%
macOS Darwin 9min 31s 27s 95,2%
Windows MSVC 9min 31s 44s 92,2%
Custo do Workflow $0,44 por execução $0,074 por execução 83,1% de economia

Simplesmente conectar uma infraestrutura de cache de volume persistente reduz o tempo de espera de build da equipe de desenvolvimento em pelo menos 40%.

Configure a automação de distribuição no arquivo .github/workflows/publish.yml da seguinte maneira:

`yaml
jobs:
build-binaries:
strategy:
matrix:
platform: [macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
# ... Após concluir os passos de build, chame o tauri-action

`

Ao colocar o tauri-apps/tauri-action no final do fluxo de trabalho, a cada novo tag enviado, o instalador assinado para ambos os sistemas operacionais será registrado automaticamente no GitHub Release Draft.


3. Isolamento de dados em SQLite para preparar a inicialização da sessão do webview

Ao empacotar o instalador para Windows, você precisa decidir o método de instalação do WebView2, que é o mecanismo do webview. Se a conexão com a internet for garantida e o tamanho do arquivo de download precisar ser reduzido ao extremo, o método downloadBootstrapper é aceitável, pois não aumenta o tamanho do pacote. Por outro lado, se você estiver visando redes fechadas ou ambientes offline, é mais seguro incluir o offlineInstaller, mesmo que isso adicione cerca de 127 MB ao arquivo de instalação.

A forma como você lida com os dados ao operar um app baseado em Tauri também é importante. É arriscado confiar apenas no IndexedDB ou LocalStorage do navegador para armazenar dados.

Na verdade, na transição do Tauri v1 para o v2, houve uma mudança interna no esquema de domínio do webview no ambiente Windows, indo de [https://tauri.localhost](https://tauri.localhost) para [http://tauri.localhost](http://tauri.localhost). Por causa disso, o caminho do cache do navegador foi alterado à força, fazendo com que muitos perdessem seus dados existentes.

Para evitar o desastre de perder dados após a distribuição, as informações principais devem ser armazenadas diretamente como arquivos SQLite na área do sistema de arquivos nativo, em vez de no armazenamento do webview. A API appDataDir do Tauri v2 encontra automaticamente o caminho seguro de sandboxing adequado ao padrão do sistema operacional:

  • Windows: C:\Users\<UserName>\AppData\Roaming\<BundleIdentifier>
  • macOS: /Users/<UserName>/Library/Application Support/<BundleIdentifier>

Um exemplo de como intervir no ciclo de vida do app dentro do código Rust do backend do Tauri v2 (src-tauri/src/lib.rs) para vincular o banco de dados SQLite à área segura e rodar a migração de esquema é:

`rust
use std::fs;
use tauri::Manager;
use tauri_plugin_sql::{Migration, MigrationKind};

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let database_migrations = vec![
Migration {
version: 1,
description: "initialize_user_profiles_table",
sql: "CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
);",
kind: MigrationKind::Up,
}
];

tauri::Builder::default()
    .setup(|app| {
        let local_app_dir = app.path().app_data_dir()
            .expect("Critical: Could not resolve target operating system app data path.");

        if !local_app_dir.exists() {
            fs::create_dir_all(&local_app_dir)
                .expect("Critical: Failed to establish persistent storage directory structure.");
        }
        
        Ok(())
    })
    .plugin(
        tauri_plugin_sql::Builder::default()
            .add_migrations("sqlite:users.db", database_migrations)
            .build()
    )
    .run(tauri::generate_context!())
    .expect("error while running tauri application");

}

`

Configurando desta forma, mesmo que o cache interno do webview do Electron ou Chromium seja limpo devido a uma atualização automática ou reinstalação, o banco de dados real do usuário será preservado com segurança.


4. Construindo atualização automática em segundo plano

O método de induzir o usuário a visitar a página inicial toda vez para baixar a nova versão aumenta a taxa de rejeição. É necessário estruturar um sistema que sirva silenciosamente os arquivos de atualização, conectando um armazenamento de objetos em nuvem (Object Storage) e uma CDN.

A combinação de Cloudflare R2 e AWS CloudFront é eficiente como servidor de distribuição. O Cloudflare R2 não possui taxas de saída de dados (Egress Fees), permitindo manter o custo de tráfego de rede gerado ao liberar grandes arquivos de atualização em zero.

Política de controle de cache de CDN

O arquivo de metadados (latest.json), consultado pelo cliente para verificar se existe uma nova versão, não deve ser armazenado em cache na CDN ou no navegador. A política abaixo deve ser especificada no cabeçalho de resposta:

`http
Cache-Control: no-cache, no-store, must-revalidate

`

Por outro lado, os arquivos binários de instalação reais, como contêm um valor de hash único, são imutáveis (Immutable); portanto, configure-os para serem mantidos na CDN pelo maior tempo possível para aliviar a carga de tráfego do servidor de origem.

`http
Cache-Control: public, max-age=31536000, immutable

`

Mudanças nas configurações do atualizador do Tauri v2

No Tauri v2, a localização das opções relacionadas à atualização mudou para dentro do bloco plugins.updater. Abaixo está a especificação de configuração do tauri.conf.json:

`json
{
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"active": true,
"endpoints": [
"https://cdn.myapp.com/releases/latest.json"
],
"dialog": false,
"pubkey": "dW5zaWduZWQgYm91bmRmaXg...",
"windows": {
"installMode": "passive"
}
}
}
}

`

Para que o usuário no Windows atualize sem precisar clicar em janelas de confirmação irritantes, o installMode deve ser definido como passive ou quiet. O modo passive exibe apenas uma barra de progresso discreta em vez de uma janela de assistente de instalação, concluindo a substituição silenciosamente.

Uma vez finalizada a configuração, integre @tauri-apps/plugin-updater e @tauri-apps/plugin-process na parte do frontend para verificar novos patches no momento em que o app for aberto e induzir a reinicialização.

`typescript
import { check } from "@tauri-apps/plugin-updater";
import { ask } from "@tauri-apps/plugin-dialog";
import { relaunch } from "@tauri-apps/plugin-process";

export async function runBackgroundUpdater(): Promise {
try {
const updatePayload = await check();

if (updatePayload && updatePayload.available) {
  const userResponse = await ask(
    `Uma nova versão [v${updatePayload.version}] está disponível. Deseja atualizar agora e reiniciar o aplicativo?`,
    {
      title: "Aviso de atualização automática de software",
      kind: "info",
      okLabel: "Instalar atualização e reiniciar",
      cancelLabel: "Aplicar mais tarde"
    }
  );

  if (userResponse) {
    await updatePayload.downloadAndInstall();
    await relaunch();
  }
}

} catch (error) {
console.error("Ocorreu um erro durante o processo de verificação de atualização automática:", error);
}
}

`

Ao colocar esta função na etapa de montagem inicial do seu componente React ou View principal, o usuário sempre terá a versão mais recente do software sem precisar vasculhar o site diretamente.


5. Resumo

  • Redução de custos: Em vez de certificados EV que custam centenas de dólares todos os anos, é mais realista para uma equipe de um desenvolvedor só aplicar o Azure Trusted Signing, que custa cerca de 10 dólares por mês, e combiná-lo com o Cloudflare R2, que não cobra taxa de tráfego de download.
  • Preservação de dados: Não é necessário depender do armazenamento local do navegador, que é facilmente perdido em caso de expiração de sessão ou mudança na especificação de domínio. Coloque o arquivo de banco de dados SQLite sob o caminho appDataDir controlado nativamente e execute migrações de esquema a longo prazo para que os dados não fiquem corrompidos durante a atualização do app.
  • Velocidade de distribuição: Não faça builds no seu próprio computador para depois fazer o upload manualmente. Configure uma matriz de build com técnicas de cache de executor para automatizar as versões de release e não sofrer com o estresse na etapa de criação de pacotes.