Tauri でモバイルアプリをビルドする

株式会社ACCESS Advent Calendar 18日目の記事です。

# 概要

2022/12/09 に Tauri Mobile 2.0.0-alpha.0 がリリースされました。

https://tauri.app/blog/2022/12/09/tauri-mobile-alpha/

こちらを手元で実際に動かしてみた記事になります。

## Tauri とは

https://next--tauri.netlify.app/

Tauri は、[Electron](https://www.electronjs.org/ja/) の代替を目指して開発されている、マルチプラットフォームのフレームワークです。
Tauri の基盤はすべて Rust で実装されており、ファイルサイズとメモリ容量が小さい点が特徴とされています。

# 環境

* macOS Ventura 13.0.1
* Intel Core i7 (x86_64)

# フロントエンドのビルド

まず初めにフロントエンドをビルドします。
今回はフロントエンドのフレームワークとして、公式でも推奨されている Next.js (v13.0.7) を利用します。
(実行環境にNode.js がインストールされていることが前提です。)

```sh
$ npx create-next-app@latest --use-npm --typescript tauri-mobile-sample
```

上記のコマンドの実行が完了したら、 `next export` コマンドを使えるようにするために `package.json` を以下のように書き換えます。
(Tauri では `next export` による SSG モードでのビルドが必須となっています。)

```package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "export": "next export",
    "tauri": "tauri"
  },

```

`next.config.js` を以下のように書き換え、必要なパッケージをインストールします。

```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
}
```

```sh
$ npm install --save-dev internal-ip
```

ここまでで以下のコマンドが成功すればOKです。

```
$ npx next build
$ npx next export
```

## Tauri のインストール

Tauri では、ネイティブコードを Rust を通じて呼び出すことができ、そのための Rust プロジェクトを作成します。
前提条件として、 Rust のビルドシステムである `cargo` コマンドが実行できるようになっている必要があります。
https://doc.rust-lang.org/cargo/getting-started/index.html

まずは Tauri の実行環境を構成します。
モバイルのサポートを受けたい場合は、
`✔ What is your frontend build command?` 
の設定だけデフォルトから変更する必要があります。

```sh
$ npm install @tauri-apps/cli@next @tauri-apps/api@next
$ npx tauri init
✔ What is your app name? · tauri-mobile-sample
✔ What should the window title be? · tauri-mobile-sample
? Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that will be created? › ../ou
✔ Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that will be created? · ../out
✔ What is the url of your dev server? · http://localhost:3000
✔ What is your frontend dev command? · npm run dev
✔ What is your frontend build command? · npm run build && npm run export
```

上記で生成された `src-tauri` ディレクトリが Rust のプロジェクトディレクトリとなり、
cargo で Tauri 2.0.0-alpha.0 の依存関係を更新し、ビルドします。

```sh
$ cd src-tauri
$ cargo add tauri@2.0.0-alpha.0
$ cargo add tauri-build@2.0.0-alpha.0 --build
$ cargo install tauri-cli --version "^2.0.0-alpha"
$ cargo build
$ cd ..
```

# Tauri Mobile の実行

ここまでを実施すると、 Android と iOS 向けの Tauri App をビルドできるようになります。

ビルドの前に、まずは bundle identifier を設定する必要があります。
`src-tauri/tauri.conf.json > tauri > bundle > identifier` の設定を編集します。

```src-tauri/tauri.conf.json
{
  "tauri": {
    "bundle": {
      "identifier": "com.example.tauri-mobile",
```

モバイルの前に、試しにデスクトップアプリをビルドしてみます。

```
$ npm run tauri dev
```

デスクトップアプリのウィンドウが開き、create-next-app のトップページが表示されました。
コードを変更すると、ホットリロードが走ります。

![tauri.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/555a1029-cd9b-a152-41c9-b1ffe4f93808.png)


## iOS アプリのビルド

### 事前準備

XCode がインストールしてあり、通常の iOS アプリがビルドできる環境が整っていることが前提です。

1. XCode のコマンドラインツールをインストールしていない場合は、ここでインストールしておきます。

```
$ xcode-select --install
```

2\. 環境変数に、Tauri が使う Apple Development Team ID を設定します。

```sh
$ export TAURI_APPLE_DEVELOPMENT_TEAM="XXXX"
```

### ビルド手順

```sh
$ npx tauri ios init
$ npx tauri ios dev
...
Detected iOS simulators:
...
  [10] iPhone 11
  [11] iPhone 11 Pro
  [12] iPhone 11 Pro Max
  [13] iPhone 14
...
  Enter an index for a simulator above.
Simulator: 13
        Info Starting simulator iPhone 14
Building app...
...
```

エミュレータを選択し、ビルドが完了すると、無事トップページが表示されました。

![ios.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/9cf8ab4e-2450-1f15-1e48-481862fd4254.png)

## Android アプリのビルド (TBD)

Android アプリのビルドは、当方の環境では一部上手くいきませんでした。

### 事前準備

Android Studio がインストールしてあり、通常の Android アプリがビルドできる環境が整っていることが前提です。

1. 環境変数に `ANDROID_HOME` と `NDK_HOME` を設定します。

```sh
export ANDROID_HOME="/Users/$USER/Library/Android/sdk"
export NDK_HOME="$ANDROID_HOME/ndk/25.1.8937393"
```

2\. `JAVA_HOME` を Java 11 のディレクトリに向けます。
(Java 1.8に設定しているとビルドエラーになります。)

```sh
export JAVA_HOME="/Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home"
```

### ビルド手順 (上手くいかなかった方法)

```sh
$ npx tauri android init
$ npx tauri android dev
```

上記では Android エミュレータが開くだけで、アプリのインストールは上手くいきませんでした。
(iOS ではコマンド実行後に Rust のビルドが走ったのですが、こちらではそれが始まる様子がありません。)

```sh
$ npx tauri android dev
✔ What external IP should we use for your development server? · 192.168.1.2
     Running BeforeDevCommand (`npm run dev`)

> tauri-mobile-sample@0.1.0 dev /Users/user/tauri-mobile-sample
> next dev

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 409 ms (165 modules)
        Info detected host target triple "x86_64-apple-darwin"
INFO    | Android emulator version 31.2.10.0 (build_id 8420304) (CL:N/A)
WARNING | unexpected system image feature string, emulator might not function correctly, please try updating the emulator.
INFO    | configAndStartRenderer: setting vsync to 60 hz
WARNING | cannot add library /Users/user/Library/Android/sdk/emulator/qemu/darwin-x86_64/lib64/vulkan/libvulkan.dylib: failed
INFO    | Sending adb public key [xxxxx]
INFO    | added library /Users/user/Library/Android/sdk/emulator/lib64/vulkan/libvulkan.dylib
INFO    | Rootcanal has  been activated.
INFO    | Started GRPC server at 127.0.0.1:8554, security: Local
INFO    | Advertising in: /Users/suser/Library/Caches/TemporaryItems/avd/running/pid_38446.ini
```

### ビルド手順 (上手くいった方法)

以下のコマンドで、事前に Tauri のコードをビルドした上で、
サーバーを起動させつつ Android Studio のプロジェクトを開きます。

```
$ npm run tauri android build
$ npm run tauri android dev -- --open
```

Build Variant の CPU アーキテクチャが開発環境と異なっている場合は、そちらに変更します。
今回は x86_64Debug に変更しました。

```
$ uname -m              
x86_64
```

![build-valiant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/e83de2ea-bfbd-6ffe-d831-9d2646f51fe0.png)

上記を実施後、 Android Studio でアプリをビルドするとトップページが表示されました。

<img width="400px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/8d074f32-1779-31b6-7a0a-d8cd12d55da0.png"/>


但し、こちらは正攻法ではないはずなので、`npx tauri android dev` が成功する方法がないかは別途探ろうと思っています。
追加情報があればこちらに随時追記していきます。（何か有用な情報があればコメントください。）

### 追記

本件に似た事象のIssueが立っていました。

https://github.com/tauri-apps/tauri/issues/5810

(情報提供がてら、上記の Issue に[上手くいったときのビルド手順](https://github.com/tauri-apps/tauri/issues/5810#issuecomment-1358032686)をコメントしておきました。)

# おわりに

* Rust でネイティブの API を呼び出せるのは魅力的かもしれない。
  * 私はサーバーサイドのコードを少し読んだことがあるくらいですが...
* Tauri Mobile 自体はまだ alpha 版で、不安定な印象。
  * 公式ドキュメントの情報もやや不十分。
  * Mobile に限らず、フレームワーク自体の前例や情報が少なめ。 
  * 今後安定板がリリースされればより開発しやすくなるかもしれません。