本頁由機器翻譯,可能有錯誤。 閱讀英文原文

文件

打包

nsh package 可將應用程式變成可安裝的成品:供 iOS 模擬器使用的 .app、供 iOS 裝置使用的已簽署 .ipa、供 Android 使用的已簽署 .apk、供 macOS 使用的 ad hoc 簽署 .app、供 Linux 使用的目錄和 .tar.gz、供 Windows 使用的目錄和 .zip,或供網頁使用的靜態網站。無需 Xcode 專案,也無需 Gradle。

  • Rust 應用程式(nsh.json 指定其 "root")會從其目錄打包。nsh 以 release 模式建置目標平台的 runner,並編入你的 crate、掛載根元件,不含 QuickJS:需要 Cargo、該平台的 Rust target(rustup target add …),Android 還需要 NDK。
  • TSX 應用程式需指定其入口。其 release 建置(經壓縮、編譯為 QuickJS bytecode,與 nsh build --release 的建置方式完全相同)會與 NSH 隨附的預建 runtime 放在一起,因此無需 Rust 工具鏈。擁有自己 crate 的應用程式(有 "rust" 而無 "root")則會連同其 crate 建置 runner。
# 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

輸出會寫入 .nsh/out/,除非你傳入 --out。以下各節列出 Rust 應用程式在各目標平台的指令;TSX 應用程式則需加上其入口(nsh package App.tsx --target …)。

#應用程式元數據:nsh.json

nsh package 會讀取應用程式目錄中的 nsh.json(TSX 應用程式則在入口檔案旁)。nsh init 會寫入一個:

{
  "name": "Gallery",
  "id": "com.example.gallery",
  "version": "1.0.0",
  "build": 1,
  "icon": "icon.png"
}
鍵 類型 預設值 用途
name string 入口所在目錄的名稱 圖示下方顯示的名稱(CFBundleDisplayName、Android 的 android:label)及輸出檔案名稱。
id string 必填 套件識別碼 / Android 套件名稱,採用你擁有的網域的反向 DNS 格式。它同時決定應用程式儲存空間的位置,令每個應用程式各有自己的儲存空間。nsh package 和 nsh publish 會對 com.example. 佔位值發出警告。
version string "1.0.0" 使用者可見的版本(CFBundleShortVersionString、versionName)。
build number 1 建置編號(CFBundleVersion、versionCode)。每次上傳新版本都要調高。
icon string 無 正方形 PNG,建議 1024×1024,路徑相對於 nsh.json。

nsh.json 亦包含 rust 和 root(應用程式的 crate 及其根元件,參閱使用 Rust 建置)、theme 和 appearance、tailwind(參閱 Tailwind)以及 capabilities(參閱沙盒與權限);所有鍵的完整列表請見專案結構。未知的鍵會導致錯誤。

上述每個鍵都可以在命令列覆寫,這在 CI 中很方便:

nsh package --target android --app-version 1.4.0 --build 42

#選項

旗標 說明
--target <ios | ios-simulator | android | macos | linux | windows | web> 要為哪個平台建置(必填)。
-o, --out <dir> 輸出目錄。預設為 .nsh/out。
--name <name> 顯示名稱。
--id <id> 套件識別碼,例如 com.example.app。
--app-version <version> 版本,例如 1.2.0。
--build <n> 建置編號。
--icon <png> 應用程式圖示:正方形 PNG,建議 1024×1024。
--sign <identity> iOS:裝置用的程式碼簽署身分。
--profile <file> iOS:裝置用的佈建描述檔(.mobileprovision)。
--keystore <file> Android:release keystore(預設:debug 金鑰)。
--key-alias <alias> Android:keystore 中的金鑰別名。
--keystore-password <password> Android:keystore 密碼;亦可從 NSH_KEYSTORE_PASSWORD 讀取。
--abi <abi> Android:APK 的 ABI,可重複指定或以逗號分隔(預設:arm64-v8a 和 armeabi-v7a)。
--run 建置後安裝並啟動:在 iOS 模擬器中,或在 adb 偵測到的 Android 裝置或模擬器上;macOS、Linux 和 Windows 應用程式會在本機啟動;網站則會在本機提供服務並在瀏覽器中開啟。不適用於 --target ios。

#iOS 模擬器

nsh package --target ios-simulator --run

會寫入 .nsh/out/<Name>.app,以 ad hoc 方式簽署(模擬器需要簽署,但不需要身分)。使用 --run 時,若沒有正在運行的模擬器,它會啟動一個,安裝應用程式並啟動。需要 Xcode。

#iOS 裝置

nsh package --target ios \
  --sign "Apple Distribution: Example Inc (ABCDE12345)" \
  --profile AppStore.mobileprovision

會寫入 .nsh/out/<Name>.ipa,可用於 TestFlight、App Store 上傳工具或直接安裝(視乎描述檔而定)。過程如下:

  • 佈建描述檔會以 embedded.mobileprovision 的名稱複製到應用程式中。
  • 權利(entitlements)來自描述檔。NSH 會檢查描述檔的應用程式識別碼是否涵蓋應用程式的 id(TEAMID.* 或 TEAMID.com.example.* 等萬用字元描述檔亦可),否則會報錯並停止。
  • 應用程式會以 codesign 使用該身分簽署,然後壓縮成 .ipa(Payload/<Name>.app)。

可用以下指令找出你的身分:

security find-identity -v -p codesigning

若沒有 --sign 和 --profile,NSH 會寫入未簽署的 .nsh/out/<Name>.app 並告知你;它無法直接安裝到裝置上。

應用程式支援 iPhone 和 iPad、直向和橫向(上下顛倒的直向僅限 iPad),並需要 iOS 15.0 或更新版本。

#Android

nsh package --target android --run

會寫入 .nsh/out/<Name>.apk。APK 直接以 SDK 的建置工具(aapt2、zipalign、apksigner)組裝,無需 Gradle。需求如下:

  • Android SDK,透過 ANDROID_HOME(或 ANDROID_SDK_ROOT,或 ~/Library/Android/sdk)尋找,並包含建置工具和 platforms;android-35 套件。如有缺少,NSH 會告訴你應執行的 sdkmanager 指令。
  • JDK,用於首次建立 debug keystore。
  • 對於 Rust 應用程式,還需要 Android NDK(sdkmanager "ndk;<version>",或 ANDROID_NDK_HOME),用來建置其 libnsh.so。

應用程式的目標為 API 35,並需要 API 28(Android 9)或更新版本。它包含手機 ABI 的原生程式碼,即 arm64-v8a 和 armeabi-v7a;使用 --run 時,還會包含裝置本身的 ABI,例如模擬器的 x86_64。--abi 可自行選擇,例如 --abi arm64-v8a 只包含 64 位元手機,APK 最小:

nsh package --target android --abi arm64-v8a

#為 release 簽署

沒有 --keystore 時,APK 會以標準 debug 金鑰(~/.android/debug.keystore,如不存在則會建立)簽署,NSH 會警告它不適用於商店發佈。發佈 release 時,請先建立一次 keystore,然後傳入:

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

建議使用環境變數而非 --keystore-password,以免密碼留在你的 shell 歷史記錄中。

#macOS

nsh package --target macos --run

會寫入 .nsh/out/<Name>.app:可執行檔位於 Contents/MacOS/,而 nsh/assets/…、nsh/app.json(視窗標題及應用程式外觀)以及 TSX 應用程式的 nsh/bundle.nshc 則位於 Contents/Resources/。應用程式以 ad hoc 方式簽署,需要 macOS 14 或更新版本;如要發佈,請以 Developer ID 簽署並進行公證(notarize)。參閱 macOS。

#Linux

nsh package --target linux --run

會寫入 .nsh/out/<Name>/(可執行檔 <Name>、nsh/assets/…、載有視窗標題和應用程式 id 的 nsh/app.json、TSX 應用程式的 nsh/bundle.nshc、<id>.desktop 和圖示 <id>.png),以及與 .nsh/out/<Name>.tar.gz 相同的內容。須在 Linux 上打包:runner 是為建置它的機器而建置的。應用程式運行的地方必須安裝 GTK 4(4.14 或更新版本)、Pango 和 WebKitGTK 6.0(用於網頁檢視)。安裝及桌面項目的說明:Linux。

#Windows

nsh package --target windows --run

會寫入 .nsh\out\<Name>\(帶有應用程式圖示的可執行檔 <Name>.exe、nsh\assets\…、載有視窗標題、應用程式 id、版本和外觀的 nsh\app.json,以及 TSX 應用程式的 nsh\bundle.nshc),以及與 .nsh\out\<Name>.zip 相同的內容。TSX 應用程式不需要任何工具;Rust 應用程式的 runner 則以 Visual Studio Build Tools 建置。須在 Windows 上打包:runner 是為建置它的機器而建置的,而且只有 Windows 能嵌入圖示。應用程式可從其目錄被複製到的任何位置運行,無需安裝。參閱 Windows。

#網頁

nsh package --target web --run

會寫入 .nsh/out/<Name>/,這是一個靜態網站:index.html、manifest.webmanifest、頁面腳本(nsh.<digest>.js)和 nsh.<digest>.wasm(Rust 應用程式的引擎和 crate;TSX 應用程式則是 runtime,與應用程式的 ES module app.<digest>.js 放在一起),以及其資產和圖示,每個檔案都以其內容命名,方便主機長期快取。將該目錄部署到任何網頁伺服器或 CDN 即可;--run 會在 http://127.0.0.1:4173/ 上提供服務供你開啟。快取標頭和嵌入方式:Web。

#圖示

在 nsh.json("icon": "icon.png")中或以 --icon 提供一個正方形 PNG,建議 1024×1024:

  • **iOS:**由 Xcode 的 actool 編譯進應用程式的資產目錄(Assets.car),由它衍生 iOS 所需的所有尺寸。
  • **Android:**縮放為 192×192 並用作啟動器圖示(mipmap-xxxhdpi)。
  • **macOS:**由 sips 轉換為 AppIcon.icns。
  • **Linux:**複製為 <id>.png,由 .desktop 檔案將其指定為 Icon。
  • **Windows:**縮放為 16 至 64 像素及 256 像素,並嵌入可執行檔作為其圖示,視窗、檔案總管和工作列都會顯示它。
  • **網頁:**縮放為 32 像素(favicon)、180(apple-touch-icon)、192 和 512(web app manifest)。

沒有圖示時,系統會顯示其預設圖示。

#內含內容

Rust 應用程式的套件包含其 runner(連同你的 crate 建置並掛載其根元件),以及其 crate 登記的資產(assets!())。TSX 應用程式的套件包含其 bytecode、其 capabilities.json(當它宣告權限時)以及它匯入的資產,並與預建 runtime 放在一起:

目標平台 Runtime TSX 應用程式
iOS nsh-ios-app 可執行檔 <Name>.app/nsh/bundle.nshc、nsh/assets/…
Android classes.dex、lib/<abi>/libnsh.so(不含符號、以未壓縮方式儲存、16 KB 對齊) assets/nsh/bundle.nshc、assets/nsh/assets/…
macOS nsh-macos-app 可執行檔,重新命名為 <Name> <Name>.app/Contents/Resources/nsh/bundle.nshc、nsh/assets/…
Linux nsh-linux-app 可執行檔,重新命名為 <Name> <Name>/nsh/bundle.nshc、nsh/assets/…
Windows nsh-windows-app.exe 可執行檔,重新命名為 <Name>.exe <Name>\nsh\bundle.nshc、nsh\assets\…
Web nsh.<digest>.wasm、nsh.<digest>.js <Name>/app.<digest>.js、assets/…、index.html

已打包的應用程式不會登記原生元件;如需使用,請將 NSH 嵌入你自己的應用程式。

#尋找 runtime

Rust 應用程式會自行建置 runner。對於 TSX 應用程式,nsh package 會在 CLI 旁尋找預建 runtime(發行版中的 bin/../runtime)。在 NSH 的 checkout 中,它會使用 target/<triple>/<profile> 和 target/android/<profile>,並採用 CLI 本身的 profile(debug CLI 使用 debug runtime):請以 cargo build -p nsh-ios-app --target aarch64-apple-ios-sim(裝置則用 aarch64-apple-ios)和 cargo xtask android(release CLI 需加上 --release)建置它們;nsh-macos-app(在 macOS 上)、nsh-linux-app(在 Linux 上)和 nsh-windows-app(在 Windows 上)是為本機而建置,位於 target/<profile>(cargo build -p nsh-macos-app、cargo build -p nsh-linux-app、cargo build -p nsh-windows-app);網頁 runtime 不論 CLI 使用哪個 profile,都以 web profile 建置,輸出到 target/wasm32-unknown-unknown/web/。環境變數 NSH_RUNTIME 可讓 CLI 指向另一個目錄,其結構須與發行版的 runtime/ 相同(ios/iphoneos、ios/iphonesimulator、android/release、macos、linux、windows、gpui、web 等)。

#另請參閱