@tauri-native/cli 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @tauri-native/cli
2
2
 
3
- Experimental CLI for packaging a Tauri microfrontend and its Rust application core for an iOS host.
3
+ Experimental CLI for packaging a Tauri microfrontend and its Rust application core for iOS and Android hosts.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,7 +8,11 @@ Experimental CLI for packaging a Tauri microfrontend and its Rust application co
8
8
  npm install --save-dev @tauri-native/cli@experimental
9
9
  ```
10
10
 
11
- Node.js 22.12 or newer, Rust with the iOS targets, and Xcode are required.
11
+ Node.js 22.12 or newer and Rust are required. iOS exports require Xcode and the iOS Rust targets. Android exports require the Android NDK and [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk):
12
+
13
+ ```sh
14
+ cargo install cargo-ndk --locked
15
+ ```
12
16
 
13
17
  Install the package in the Tauri project that owns the frontend and Rust core. React Native and Lynx hosts consume its exported artifacts and do not need the CLI as a dependency.
14
18
 
@@ -35,6 +39,28 @@ The output directory contains:
35
39
 
36
40
  Copy or reference the exported directory from the native host, then add its generated local Pod before installing native dependencies.
37
41
 
42
+ ## Export for Android
43
+
44
+ The Rust library must include both mobile crate types:
45
+
46
+ ```toml
47
+ [lib]
48
+ crate-type = ["staticlib", "cdylib"]
49
+ ```
50
+
51
+ Run the Android export from the Tauri project root:
52
+
53
+ ```sh
54
+ npx tauri-native export android
55
+ ```
56
+
57
+ The default output is `src-tauri/gen/tauri-native/android` and contains:
58
+
59
+ - `jniLibs/<abi>/libtauri_native_core.so` for `arm64-v8a`, `armeabi-v7a`, `x86`, and `x86_64`
60
+ - `assets/tauri-native` containing the unchanged frontend distribution
61
+
62
+ The React Native Expo config plugin installs these files during Android prebuild. Bare React Native and Lynx hosts can copy both directories into `android/app/src/main` or reference them from the app source set.
63
+
38
64
  ## License
39
65
 
40
66
  MIT
package/dist/index.mjs CHANGED
@@ -44,6 +44,93 @@ function run(command, args, options = {}) {
44
44
  });
45
45
  }
46
46
  //#endregion
47
+ //#region src/commands/export-android.ts
48
+ const ANDROID_ABIS = [
49
+ "arm64-v8a",
50
+ "armeabi-v7a",
51
+ "x86",
52
+ "x86_64"
53
+ ];
54
+ const ANDROID_TARGETS = [
55
+ "aarch64-linux-android",
56
+ "armv7-linux-androideabi",
57
+ "i686-linux-android",
58
+ "x86_64-linux-android"
59
+ ];
60
+ const ANDROID_API_LEVEL = "24";
61
+ const OUTPUT_LIBRARY_NAME = "libtauri_native_core.so";
62
+ function copyAndroidLibraries(cargoOutput, outputDirectory, libraryName) {
63
+ const jniLibraries = path.join(outputDirectory, "jniLibs");
64
+ rmSync(jniLibraries, {
65
+ recursive: true,
66
+ force: true
67
+ });
68
+ for (const abi of ANDROID_ABIS) {
69
+ const source = path.join(cargoOutput, abi, `lib${libraryName}.so`);
70
+ requireFile(source);
71
+ const abiDirectory = path.join(jniLibraries, abi);
72
+ mkdirSync(abiDirectory, { recursive: true });
73
+ cpSync(source, path.join(abiDirectory, OUTPUT_LIBRARY_NAME));
74
+ }
75
+ }
76
+ function exportAndroid(options) {
77
+ const workingDirectory = process.cwd();
78
+ const tauriDirectory = path.resolve(workingDirectory, options.tauriDir);
79
+ const manifest = options.manifest ? path.resolve(workingDirectory, options.manifest) : path.join(tauriDirectory, "crates/app-core/Cargo.toml");
80
+ const outputDirectory = path.resolve(workingDirectory, options.outputDir ?? path.join(tauriDirectory, "gen/tauri-native/android"));
81
+ const configPath = path.join(tauriDirectory, "tauri.conf.json");
82
+ for (const requiredPath of [manifest, configPath]) requireFile(requiredPath);
83
+ const config = JSON.parse(readFileSync(configPath, "utf8"));
84
+ const frontendDirectory = path.dirname(tauriDirectory);
85
+ if (typeof config.build?.beforeBuildCommand === "string") {
86
+ message(`Building the Tauri microfrontend in ${frontendDirectory}`);
87
+ execSync(config.build.beforeBuildCommand, {
88
+ cwd: frontendDirectory,
89
+ stdio: "inherit"
90
+ });
91
+ }
92
+ if (typeof config.build?.frontendDist !== "string") throw new Error(`${configPath} must define build.frontendDist`);
93
+ const frontendDist = path.resolve(tauriDirectory, config.build.frontendDist);
94
+ requireFile(path.join(frontendDist, "index.html"));
95
+ const libraryName = readLibraryName(manifest);
96
+ const targetDirectory = path.join(tauriDirectory, "target/tauri-native");
97
+ const cargoOutput = path.join(targetDirectory, "android-jniLibs");
98
+ const cargoEnvironment = {
99
+ ...process.env,
100
+ CARGO_TARGET_DIR: targetDirectory
101
+ };
102
+ run("rustup", [
103
+ "target",
104
+ "add",
105
+ ...ANDROID_TARGETS
106
+ ]);
107
+ rmSync(cargoOutput, {
108
+ recursive: true,
109
+ force: true
110
+ });
111
+ run("cargo", [
112
+ "ndk",
113
+ "--platform",
114
+ ANDROID_API_LEVEL,
115
+ ...ANDROID_ABIS.flatMap((abi) => ["--target", abi]),
116
+ "--output-dir",
117
+ cargoOutput,
118
+ "build",
119
+ "--manifest-path",
120
+ manifest,
121
+ "--release"
122
+ ], { env: cargoEnvironment });
123
+ mkdirSync(outputDirectory, { recursive: true });
124
+ copyAndroidLibraries(cargoOutput, outputDirectory, libraryName);
125
+ const assets = path.join(outputDirectory, "assets/tauri-native");
126
+ rmSync(assets, {
127
+ recursive: true,
128
+ force: true
129
+ });
130
+ cpSync(frontendDist, assets, { recursive: true });
131
+ message(`Created ${path.join(outputDirectory, "jniLibs")}\nCreated ${assets}`, "◆ ");
132
+ }
133
+ //#endregion
47
134
  //#region src/commands/export-ios.ts
48
135
  const IOS_TARGETS = [
49
136
  "aarch64-apple-ios",
@@ -165,7 +252,9 @@ function exportIos(options) {
165
252
  function createProgram() {
166
253
  const program = new Command();
167
254
  program.name("tauri-native").description("Export a Tauri microfrontend for a native host").showHelpAfterError();
168
- program.command("export").description("Export Tauri artifacts for a native host").command("ios").description("Export an XCFramework and a Tauri web asset bundle").option("--tauri-dir <path>", "Tauri Rust directory", "src-tauri").option("--manifest <path>", "native core Cargo.toml").option("--header <path>", "C ABI header").option("--output-dir <path>", "generated artifact directory").action((options) => exportIos(options));
255
+ const exportCommand = program.command("export").description("Export Tauri artifacts for a native host");
256
+ exportCommand.command("ios").description("Export an XCFramework and a Tauri web asset bundle").option("--tauri-dir <path>", "Tauri Rust directory", "src-tauri").option("--manifest <path>", "native core Cargo.toml").option("--header <path>", "C ABI header").option("--output-dir <path>", "generated artifact directory").action((options) => exportIos(options));
257
+ exportCommand.command("android").description("Export Android Rust libraries and Tauri web assets").option("--tauri-dir <path>", "Tauri Rust directory", "src-tauri").option("--manifest <path>", "native core Cargo.toml").option("--output-dir <path>", "generated artifact directory").action((options) => exportAndroid(options));
169
258
  return program;
170
259
  }
171
260
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tauri-native/cli",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "Export a Tauri microfrontend and its Rust core for native hosts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,6 +26,7 @@
26
26
  "commander": "^15.0.0"
27
27
  },
28
28
  "keywords": [
29
+ "android",
29
30
  "ios",
30
31
  "react-native",
31
32
  "rust",