Documentação
Empacotamento
nsh package transforma um app em algo que você pode instalar: um .app para o simulador do iOS, um .ipa assinado para dispositivos iOS, um .apk assinado para Android, um .app com assinatura ad hoc para macOS, um diretório e .tar.gz para Linux, um diretório e .zip para Windows, ou um site estático para a web. Não precisa de projeto Xcode nem de Gradle.
- Um app Rust (
nsh.jsonnomeia o seu"root") é empacotado a partir do seu diretório.nshcompila o runner do alvo em modo release, com o seu crate compilado junto e a raiz montada, sem QuickJS. São necessários: Cargo, o alvo Rust da plataforma (rustup target add …) e, para Android, o NDK. - Um app TSX nomeia a sua entrada. Seu build de release (minificado, compilado para bytecode do QuickJS, exatamente como
nsh build --releaseo compila) vai junto com o runtime pré-compilado que acompanha o NSH, portanto não precisa de toolchain Rust. Um app com um crate próprio ("rust"sem"root") recebe runners compilados com o seu crate.
# A Rust app, from its directory
nsh package --target ios-simulator --run # build, install and launch in the simulator
nsh package --target android --run # build, install and launch on a device or emulator
nsh package --target macos --run # build and launch on this Mac
nsh package --target linux --run # build and launch on this machine
nsh package --target windows --run # build and launch on this machine
nsh package --target web --run # build, serve on this machine and open in the browser
nsh package --target ios --sign "Apple Development: Jane Doe (ABCDE12345)" --profile Dev.mobileprovision
# A TSX app: the same with its entry
nsh package App.tsx --target ios-simulator --run
A saída vai para .nsh/out/, a menos que você passe --out. As seções abaixo mostram o comando de cada alvo para um app Rust; um app TSX acrescenta a sua entrada (nsh package App.tsx --target …).
#Metadados do app: nsh.json
nsh package lê nsh.json no diretório do app (ao lado do arquivo de entrada, no caso de um app TSX). nsh init cria um:
{
"name": "Gallery",
"id": "com.example.gallery",
"version": "1.0.0",
"build": 1,
"icon": "icon.png"
}
| Chave | Tipo | Padrão | Usado para |
|---|---|---|---|
name |
string | o nome do diretório da entrada | O nome exibido sob o ícone (CFBundleDisplayName, android:label no Android) e o nome do arquivo de saída. |
id |
string | obrigatório | O identificador do bundle / nome do pacote Android, no formato DNS reverso sob um domínio que você possui. Também nomeia o local onde o app guarda seu armazenamento, de modo que cada app tenha o seu. nsh package e nsh publish avisam sobre o placeholder com.example.. |
version |
string | "1.0.0" |
A versão visível ao usuário (CFBundleShortVersionString, versionName). |
build |
número | 1 |
O número do build (CFBundleVersion, versionCode). Aumente-o a cada release que você enviar. |
icon |
string | nenhum | Um PNG quadrado, idealmente de 1024×1024, relativo a nsh.json. |
nsh.json também contém rust e root (os crates do app e seu componente raiz, Desenvolvendo com Rust), theme e appearance, tailwind (veja Tailwind) e capabilities (veja Sandbox e capabilities); Estrutura do projeto lista todas as chaves. Chaves desconhecidas causam erro.
Toda chave acima pode ser sobrescrita na linha de comando, o que é útil em CI:
nsh package --target android --app-version 1.4.0 --build 42
#Opções
| Flag | Descrição |
|---|---|
--target <ios | ios-simulator | android | macos | linux | windows | web> |
Para o que compilar (obrigatório). |
-o, --out <dir> |
Diretório de saída. Padrão: .nsh/out. |
--name <name> |
Nome exibido. |
--id <id> |
Identificador do bundle, como com.example.app. |
--app-version <version> |
Versão, como 1.2.0. |
--build <n> |
Número do build. |
--icon <png> |
Ícone do app: um PNG quadrado, idealmente de 1024×1024. |
--sign <identity> |
iOS: a identidade de assinatura de código para dispositivos. |
--profile <file> |
iOS: o provisioning profile para dispositivos (.mobileprovision). |
--keystore <file> |
Android: um keystore de release (padrão: a chave de debug). |
--key-alias <alias> |
Android: o alias da chave no keystore. |
--keystore-password <password> |
Android: a senha do keystore; também lida de NSH_KEYSTORE_PASSWORD. |
--abi <abi> |
Android: as ABIs do APK, repetidas ou separadas por vírgulas (padrão: arm64-v8a e armeabi-v7a). |
--run |
Instala e executa em seguida: no simulador do iOS, ou no dispositivo ou emulador Android que adb enxerga; apps macOS, Linux e Windows são executados nesta máquina; um site web é servido nesta máquina e aberto no navegador. Não se aplica a --target ios. |
#Simulador do iOS
nsh package --target ios-simulator --run
Gera .nsh/out/<Name>.app, com assinatura ad hoc (o simulador exige uma assinatura, mas não uma identidade). Com --run, ele inicia um simulador se nenhum estiver em execução, instala o app e o executa. Requer o Xcode.
#Dispositivos iOS
nsh package --target ios \
--sign "Apple Distribution: Example Inc (ABCDE12345)" \
--profile AppStore.mobileprovision
Gera .nsh/out/<Name>.ipa, pronto para o TestFlight, para as ferramentas de envio à App Store ou para instalação direta (dependendo do profile). O que acontece:
- O provisioning profile é copiado para dentro do app como
embedded.mobileprovision. - Os entitlements vêm do profile. O NSH verifica se o application identifier do profile cobre o
iddo app (profiles curinga, comoTEAMID.*ouTEAMID.com.example.*, funcionam) e, caso contrário, para com um erro. - O app é assinado com
codesignusando a identidade e depois compactado em um.ipa(Payload/<Name>.app).
Encontre suas identidades com:
security find-identity -v -p codesigning
Sem --sign e --profile, o NSH gera um .nsh/out/<Name>.app não assinado e avisa você; ele não pode ser instalado em um dispositivo dessa forma.
O app oferece suporte a iPhone e iPad, em retrato e paisagem (retrato de cabeça para baixo apenas no iPad), e exige iOS 15.0 ou mais recente.
#Android
nsh package --target android --run
Gera .nsh/out/<Name>.apk. O APK é montado diretamente com as ferramentas de build do SDK (aapt2, zipalign, apksigner), sem Gradle. Requisitos:
- O Android SDK, localizado por meio de
ANDROID_HOME(ouANDROID_SDK_ROOT, ou~/Library/Android/sdk), com build tools e o pacoteplatforms;android-35. O NSH informa o comandosdkmanagerquando algum está faltando. - Um JDK, para criar o keystore de debug na primeira vez.
- Para um app Rust, o Android NDK (
sdkmanager "ndk;<version>"ouANDROID_NDK_HOME), que compila olibnsh.sodele.
O app tem como alvo a API 35 e exige a API 28 (Android 9) ou mais recente. Ele contém código nativo para as ABIs de celulares, arm64-v8a e armeabi-v7a; com --run, também a do dispositivo, como o x86_64 de um emulador. --abi escolhe as ABIs por conta própria, por exemplo --abi arm64-v8a apenas para celulares de 64 bits, o menor APK:
nsh package --target android --abi arm64-v8a
#Assinatura para release
Sem --keystore, o APK é assinado com a chave de debug padrão (~/.android/debug.keystore, criada se não existir), e o NSH avisa que ele não serve para releases em lojas. Para um release, crie um keystore uma única vez e passe-o:
keytool -genkeypair -v -keystore release.jks -alias upload -keyalg RSA -keysize 2048 -validity 10000
NSH_KEYSTORE_PASSWORD=… nsh package --target android \
--keystore release.jks --key-alias upload
Prefira a variável de ambiente a --keystore-password, para que a senha não fique no histórico do seu shell.
#macOS
nsh package --target macos --run
Gera .nsh/out/<Name>.app: o executável em Contents/MacOS/, e nsh/assets/…, nsh/app.json (o título da janela e a aparência do app) e o nsh/bundle.nshc de um app TSX em Contents/Resources/. O app é assinado ad hoc e exige macOS 14 ou posterior; para distribuí-lo, assine-o com um Developer ID e faça a notarização. Veja macOS.
#Linux
nsh package --target linux --run
Gera .nsh/out/<Name>/ (o executável <Name>, nsh/assets/…, nsh/app.json com o título da janela e o id do aplicativo, o nsh/bundle.nshc de um app TSX, <id>.desktop e o ícone <id>.png) e o mesmo que .nsh/out/<Name>.tar.gz. Empacote no Linux: o runner é compilado para a máquina em que é gerado. GTK 4 (4.14 ou posterior), Pango e WebKitGTK 6.0 (para web views) devem estar instalados onde o app for executado. Instalação e entrada de desktop: Linux.
#Windows
nsh package --target windows --run
Gera .nsh\out\<Name>\ (o executável <Name>.exe com o ícone do app, nsh\assets\…, nsh\app.json com o título da janela, o id do app, a versão e a aparência, e o nsh\bundle.nshc de um app TSX) e o mesmo que .nsh\out\<Name>.zip. Um app TSX não precisa de ferramentas; o runner de um app Rust é compilado com o Visual Studio Build Tools. Empacote no Windows: o runner é compilado para a máquina em que é gerado, e somente o Windows consegue incorporar o ícone. O app é executado de onde quer que seu diretório seja copiado; nada é instalado. Veja Windows.
#Web
nsh package --target web --run
Gera .nsh/out/<Name>/, um site estático: index.html, manifest.webmanifest, o script da página (nsh.<digest>.js) e nsh.<digest>.wasm (o engine e o crate de um app Rust; para um app TSX, o runtime, ao lado do módulo ES do app app.<digest>.js), seus assets e ícones, cada um nomeado a partir do seu conteúdo para que os hosts possam fazer cache deles indefinidamente. Publique o diretório em qualquer servidor web ou CDN; --run o serve em http://127.0.0.1:4173/ para você abrir. Cabeçalhos de cache e incorporação: Web.
#Ícones
Forneça um PNG quadrado, idealmente de 1024×1024, em nsh.json ("icon": "icon.png") ou com --icon:
- iOS: compilado pelo
actooldo Xcode no catálogo de assets do app (Assets.car), que gera todos os tamanhos de que o iOS precisa. - Android: redimensionado para 192×192 e usado como ícone do launcher (
mipmap-xxxhdpi). - macOS: convertido por
sipsemAppIcon.icns. - Linux: copiado como
<id>.png, que o arquivo.desktopindica como seuIcon. - Windows: redimensionado para de 16 a 64 pixels e para 256 pixels e incorporado ao executável como seu ícone, que a janela, o Explorer e a barra de tarefas exibem.
- Web: redimensionado para 32 pixels (o favicon), 180 (
apple-touch-icon), 192 e 512 (o web app manifest).
Sem um ícone, o sistema exibe o seu padrão.
#O que há dentro
O pacote de um app Rust é o seu runner, compilado com o seu crate e a raiz montada, mais os assets que seus crates registram (assets!()). O pacote de um app TSX contém o seu bytecode, o seu capabilities.json (quando declara capabilities) e os assets que ele importa, ao lado do runtime pré-compilado:
| Alvo | Runtime | Um app TSX |
|---|---|---|
| iOS | o executável nsh-ios-app |
<Name>.app/nsh/bundle.nshc, nsh/assets/… |
| Android | classes.dex, lib/<abi>/libnsh.so (sem símbolos, armazenadas sem compressão, alinhadas a 16 KB) |
assets/nsh/bundle.nshc, assets/nsh/assets/… |
| macOS | o executável nsh-macos-app, renomeado para <Name> |
<Name>.app/Contents/Resources/nsh/bundle.nshc, nsh/assets/… |
| Linux | o executável nsh-linux-app, renomeado para <Name> |
<Name>/nsh/bundle.nshc, nsh/assets/… |
| Windows | o executável nsh-windows-app.exe, renomeado para <Name>.exe |
<Name>\nsh\bundle.nshc, nsh\assets\… |
| Web | nsh.<digest>.wasm, nsh.<digest>.js |
<Name>/app.<digest>.js, assets/…, index.html |
Um app empacotado não registra componentes nativos; para isso, incorpore o NSH ao seu próprio app.
#Localizando o runtime
Um app Rust compila seus próprios runners. Para apps TSX, nsh package procura o runtime pré-compilado ao lado da CLI (bin/../runtime na distribuição). Em um checkout do NSH, ele usa target/<triple>/<profile> e target/android/<profile>, com o perfil da própria CLI (uma CLI de debug usa runtimes de debug): compile-os com cargo build -p nsh-ios-app --target aarch64-apple-ios-sim (ou aarch64-apple-ios para dispositivos) e cargo xtask android (acrescente --release para uma CLI de release); nsh-macos-app (no macOS), nsh-linux-app (no Linux) e nsh-windows-app (no Windows) são compilados para esta máquina em target/<profile> (cargo build -p nsh-macos-app, cargo build -p nsh-linux-app, cargo build -p nsh-windows-app); o runtime web é compilado com o perfil web, seja qual for o da CLI, em target/wasm32-unknown-unknown/web/. A variável de ambiente NSH_RUNTIME aponta a CLI para outro diretório organizado como o runtime/ da distribuição (ios/iphoneos, ios/iphonesimulator, android/release, macos, linux, windows, gpui, web, …).
#Veja também
- CLI: todos os comandos
- Pacotes assinados: atualizações que os apps baixam
- Estrutura do projeto:
nsh.jsone os arquivos de um app