mirror of
https://github.com/tauri-apps/tauri-docs.git
synced 2026-01-31 00:35:16 +01:00
merge in docs from next branch
Signed-off-by: Lorenzo Lewis <lorenzo_lewis@icloud.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import Stub from '@components/Stub.astro';
|
||||
- Linux
|
||||
- macOS
|
||||
- Windows
|
||||
- Android
|
||||
- Android `pnpm tauri [ios|android] build`
|
||||
- iOS
|
||||
- Updater (link to recipe)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import Stub from '@components/Stub.astro';
|
||||
|
||||
- Create a new app using `create-tauri-app`
|
||||
- Manually create the app using the Tauri CLI
|
||||
- Add mobile to an existing project
|
||||
- Add mobile to an existing project (revise what's here [integrate mobile](./mobile))
|
||||
- Frontend framework-specific guides (right now limiting to React, Angular, Vue, Svelte, and Solid)
|
||||
|
||||
</Stub>
|
||||
211
src/content/docs/2/guide/create/mobile.mdx
Normal file
211
src/content/docs/2/guide/create/mobile.mdx
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
title: Integrate
|
||||
---
|
||||
|
||||
If you have a desktop Tauri project and want to target mobile platforms using the same code, you must configure your Rust crate.
|
||||
|
||||
## Change your crate type
|
||||
|
||||
The Rust crate must output a library that will be embedded in the Android and iOS packages. Add the following section to your `Cargo.toml` file:
|
||||
|
||||
```toml title=src-tauri/Cargo.toml
|
||||
[lib]
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
```
|
||||
|
||||
## Create the library source code
|
||||
|
||||
The default entry point for the Rust library is the `lib.rs` file.
|
||||
Let's write a `tauri::Builder` wrapper that will be reused by both the desktop and mobile targets.
|
||||
|
||||
```rust title=src-tauri/src/lib.rs
|
||||
use tauri::App;
|
||||
|
||||
#[cfg(mobile)]
|
||||
mod mobile;
|
||||
#[cfg(mobile)]
|
||||
pub use mobile::*;
|
||||
|
||||
pub type SetupHook = Box<dyn FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AppBuilder {
|
||||
setup: Option<SetupHook>,
|
||||
}
|
||||
|
||||
impl AppBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn setup<F>(mut self, setup: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut App) -> Result<(), Box<dyn std::error::Error>> + Send + 'static,
|
||||
{
|
||||
self.setup.replace(Box::new(setup));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) {
|
||||
let setup = self.setup;
|
||||
tauri::Builder::default()
|
||||
.setup(move |app| {
|
||||
if let Some(setup) = setup {
|
||||
(setup)(app)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the `AppBuilder::run` function is where you write all the shared logic. Custom mobile/desktop code can be defined in the AppBuilder methods, such as the setup method.
|
||||
|
||||
Now let's create the mobile module that will have the entry point for iOS and Android and consume the shared AppBuilder logic:
|
||||
|
||||
```rust title=src-tauri/src/mobile.rs
|
||||
#[tauri::mobile_entry_point]
|
||||
fn main() {
|
||||
super::AppBuilder::new().run();
|
||||
}
|
||||
```
|
||||
|
||||
The default Tauri project has the binary source code under `src-tauri/src/main.rs`. Let's change it to use the AppBuilder struct:
|
||||
|
||||
```rust title=src-tauri/src/main.rs
|
||||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
pub fn main() {
|
||||
app::AppBuilder::new().run();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Frontend Configuration
|
||||
|
||||
To develop mobile Tauri applications, your frontend must serve the assets listening on your public network address.
|
||||
The network address can be found using the `internal-ip` NPM:
|
||||
|
||||
```shell
|
||||
npm install --save-dev internal-ip
|
||||
```
|
||||
|
||||
```shell
|
||||
yarn add -D internal-ip
|
||||
```
|
||||
|
||||
```shell
|
||||
pnpm add -D internal-ip
|
||||
```
|
||||
|
||||
Then you need to configure your framework to use the internal IP.
|
||||
|
||||
### Vite
|
||||
|
||||
For Vite, you need to change your configuration to be defined using the `defineConfig` helper with an async closure.
|
||||
Then, resolve the internal IP address and set it to the [server object][vite server].
|
||||
|
||||
```javascript title=vite.config.js
|
||||
import { defineConfig } from 'vite';
|
||||
import { internalIpV4 } from 'internal-ip';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => {
|
||||
const host = await internalIpV4();
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
const config = {
|
||||
server: {
|
||||
host: '0.0.0.0', // listen on all addresses
|
||||
port: 5173,
|
||||
strictPort: true,
|
||||
hmr: {
|
||||
protocol: 'ws',
|
||||
host,
|
||||
port: 5183,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return config;
|
||||
});
|
||||
```
|
||||
|
||||
### Next.js
|
||||
|
||||
For Next.js, you need to configure the [assetPrefix] to use the internal IP so the server properly resolves your assets.
|
||||
|
||||
```typescript title=next.config.js
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
module.exports = async (phase, { defaultConfig }) => {
|
||||
let internalHost = null;
|
||||
if (!isProd) {
|
||||
const { internalIpV4 } = await import('internal-ip');
|
||||
internalHost = await internalIpV4();
|
||||
}
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
*/
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
// Note: This experimental feature is required to use NextJS Image in SSG mode.
|
||||
// See https://nextjs.org/docs/messages/export-image-api for different workarounds.
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
assetPrefix: isProd ? null : `http://${internalHost}:3000`,
|
||||
};
|
||||
return nextConfig;
|
||||
};
|
||||
```
|
||||
|
||||
Currently, there is no configuration option to configure Next.js to use the internal IP address, only the CLI allows changing it.
|
||||
So you need to append `--hostname $HOST` to the [beforeDevCommand].
|
||||
|
||||
### Webpack
|
||||
|
||||
Webpack has a built-in option to use the local IP address as the host for the development server:
|
||||
|
||||
```typescript title=webpack.config.js
|
||||
export default {
|
||||
devServer: {
|
||||
host: 'local-ipv4',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
[vite server]: https://vitejs.dev/config/server-options.html
|
||||
[assetprefix]: https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix
|
||||
[beforedevcommand]: ../../api/config.md#buildconfig.beforedevcommand
|
||||
[tauri releases on github]: https://github.com/tauri-apps/tauri/releases
|
||||
|
||||
## Conditional compilation
|
||||
|
||||
The `#[cfg(desktop)]` and `#[cfg(mobile)]` conditional checks can be used to conditionally compile code for each target.
|
||||
|
||||
```rust title=lib.rs
|
||||
#[cfg(mobile)]
|
||||
fn do_something() {
|
||||
println!("Hello from Mobile!");
|
||||
}
|
||||
|
||||
#[cfg(desktop)]
|
||||
fn do_something() {
|
||||
println!("Hello from Desktop!");
|
||||
}
|
||||
|
||||
fn run() {
|
||||
if cfg!(mobile) {
|
||||
println!("Hello from Mobile!");
|
||||
} else {
|
||||
println!("Hello from Desktop!");
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -4,4 +4,8 @@ title: Develop
|
||||
|
||||
import Stub from '@components/Stub.astro';
|
||||
|
||||
<Stub />
|
||||
<Stub>
|
||||
|
||||
- `pnpm tauri [android|ios] dev [--open]`
|
||||
|
||||
</Stub>
|
||||
|
||||
Reference in New Issue
Block a user