tauri1.x→tauri2.0(beta.19)migration + iOSアプリ開発(現在エラー発生中 beta.23でNG)
現在ベータ版のtauri2.0(v2.0.0-beta.23)で、iOSアプリ開発をしてみます。
javascriptランタイムは、bun(1.1.8)を利用します。
ネタは、chatGPTのクライアントアプリ。
win,macos,linux用のクライアントとしては既に作成済みなので、
基本的には、このプログラムをtauri2.0にmigrationしながら、変更点を確認していきます。
参考にさせていただいた記事
※tauri2.0の導入はこちらの記事が詳しいので、ここではある程度省略して、その先の実践的な内容をメモしていきます。
※bunでの地雷もいくつかあったので、そのままメモしていきます。
プロジェクト作成&初期設定を進めます。
frontは、javascript(vue)で実装します。
$ bun create tauri-app --beta
✔ Project name · ai_client
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, bun)
✔ Choose your package manager · bun
✔ Choose your UI template · Vue - (https://vuejs.org/)
✔ Choose your UI flavor · JavaScript
✔ Would you like to setup the project for mobile as well? · yes
Template created! To get started run:
cd ai_client
bun install
bun run tauri android init
bun run tauri ios init
For Desktop development, run:
bun run tauri dev
For Android development, run:
bun run tauri android dev
For iOS development, run:
bun run tauri ios dev
動作確認してみる
$ bun i
$ bun run tauri dev
OK.
1.xとの違い
- バックエンドの処理が、main.rsではなく
lib.rsに記述されている(mobile対応にしたから?)
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
mainはこうなってた
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
ai_client_lib::run()
}
iOSビルドの準備
rustのtargetとして、ios系を追加する
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
homebrew, cocoapadをインストール
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install cocoapods
create project後のインフォメーションの通り、iOS用のinitを行い、devで立ち上げる
※bunでios initをすると、現時点でバグがあり先に進めなくなります。
回避したい場合、ここだけ、npm run tauri ios init
を実行してください。
bun run tauri ios init
run.
シミュレータを選択して実行
$ bun run tauri ios dev
==> Running `brew cleanup ios-deploy`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Detected iOS simulators:
[0] iPad (10th generation)
[1] iPad (10th generation)
[2] iPad Air (5th generation)
[3] iPad Air (5th generation)
[4] iPad Pro (11-inch) (4th generation)
[5] iPad Pro (11-inch) (4th generation)
[6] iPad Pro (12.9-inch) (6th generation)
[7] iPad Pro (12.9-inch) (6th generation)
[8] iPad mini (6th generation)
[9] iPad mini (6th generation)
[10] iPhone 15
[11] iPhone 15
[12] iPhone 15 Plus
[13] iPhone 15 Plus
[14] iPhone 15 Pro
[15] iPhone 15 Pro
[16] iPhone 15 Pro Max
[17] iPhone 15 Pro Max
[18] iPhone SE (3rd generation)
[19] iPhone SE (3rd generation)
Enter an index for a simulator above.
Simulator: 15
エラー発生。
clang: error: linker command failed with exit code 1 (use -v to see invocation)
note: Run script build phase 'Build Rust Code' will be run during every build because the option to run the script phase "Based on dependency analysis" is unchecked. (in target 'ai_client_iOS' from project 'ai_client')
** BUILD FAILED **
The following build commands failed:
Ld /Users/masatoyuna/Library/Developer/Xcode/DerivedData/ai_client-fwvrscpltheatpeipnofdrvehucn/Build/Products/debug-iphonesimulator/ai_client.app/ai_client normal (in target 'ai_client_iOS' from project 'ai_client')
(1 failure)
Error command ["xcodebuild"] exited with code 65
error: script "tauri" exited with code 1
tauriのissueをsearchしてみると、同様のバグが発生している事例を見つけた。
結論としては、bun initのバグっぽく、initはbunではなくnpmなど別のランタイムで構築して、
buildをbunでやることで回避できるらしい。
ということで、tauri ios initだけ、npmで実行することで回避した。
$ npm run tauri ios init
$ bun run tauri ios dev
$ bun run tauri ios dev
chatGPT clientのロジックを構築していきます。
1.xから2.0へのmigration箇所については、こちらにまとまっています。
バックエンドで作成済みのapiエンドポイントを、そのままコピー
migrationが必要だった場所
path_resolverは、シンプルにpathに変更
app.path_resolver().app_config_dir()
↓
app.path().app_config_dir()
menu系の実装を修正
Menu, MenuEvent, CustomMenuItem, Submenu, WindowMenuEvent, MenuItem and Builder::on_menu_event APIs removed.
tauri::SystemTrayMenu
↓
tauri::menu::Menu
tauri::SystemTraySubmenu
↓
tauri::menu::Submenu
tauri::SystemTrayMenuItem
↓
tauri::menu::PredefinedMenuItem
CustomMenuItemは、記述を変更
tauri::CustomMenuItem
↓
tauri::menu::MenuItemBuilder
tauri::Builder::on_menu_event
↓
tauri::App::on_menu_event
、 tauri::AppHandle::on_menu_event
実際に置き換えたコード
let main_page = MenuItem::new("main".to_string(), "Main");
let settings = CustomMenuItem::new("settings".to_string(), "Settings");
let submenu = Submenu::new("Menu", Menu::new().add_item(main_page).add_item(settings));
let menu = tauri::Menu::os_default(&context.package_info().name).add_submenu(submenu);
〜〜省略〜〜
.menu(menu)
.on_menu_event(|event| match event.menu_item_id() {
"settings" => {
event.window().emit("open_settings", "").unwrap();
}
"main" => {
event.window().emit("open_main", "").unwrap();
}
_ => {}
})
↓
.setup(|app| {
let main_page = MenuItemBuilder::with_id("main","Main").build(app)?;
let settings = MenuItemBuilder::with_id("settings", "Settings").build(app)?;
let submenu = SubmenuBuilder::with_id(app, "menu", "Menu").items(&[&main_page, &settings]).build()?;
let menu = MenuBuilder::new(app).items(&[&submenu]).build()?;
app.set_menu(menu)?;
app.on_menu_event(move |app, event| {
let window_list = app.webview_windows();
let window_tuple = window_list.iter().next().unwrap();
println!("event: {:#?}, window:{:?}", event.id(), window_tuple.0);
let window = window_tuple.1;
match event.id().0.as_str() {
"settings" => {
window.emit("open_settings", "").unwrap();
}
"main" => {
window.emit("open_main", "").unwrap();
}
_ => {}
}
});
init_config(app).expect("config init error");
Ok(())
})```
frontendを、旧コードから新コードにコピー
rustコードと同様に、frontendもmigrationが必要。
今回のサンプルでは、一箇所の修正だけで済んだ。
@tauri-apps/api/tauri
→ @tauri-apps/api/core
tauri.conf.jsonのコピー
要素の位置が多く変更されているので、公式を見ながら変更する。
allowlistの変更について
allowlistは、ver2.0になってマルチウィンドウ対応など、細かい設定を行えるようにするために大きく変更されています。
アプリの権限を有効にするには、src-tauri/capabilities フォルダー内に機能ファイルを作成する必要があるため、いったんtauri.conf.jsonの変更のみを記述します。
{
"build": {
"beforeDevCommand": "bun dev",
"beforeBuildCommand": "bun build",
"devPath": "http://localhost:1420",
"distDir": "../dist"
},
"package": {
"productName": "ai_client",
"version": "0.0.6"
},
"tauri": {
"allowlist": {
"all": false,
"shell": {
"all": false,
"open": true
}
},
"windows": [
{
"fullscreen": false,
"resizable": true,
"title": "ai_client",
"width": 1200,
"height": 1000
}
],
"security": {
"csp": null
},
"updater": {
"active": false
},
"bundle": {
"active": true,
"targets": "all",
"identifier": "jp.co.generalworks.ai-client",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
}
{
"productName": "ai_client",
"version": "0.1.0",
"identifier": "jp.co.generalworks.ai-client",
"build": {
"beforeDevCommand": "bun run dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "bun run build",
"frontendDist": "../dist"
},
"app": {"windows": [
{
"fullscreen": false,
"resizable": true,
"title": "ai_client",
"width": 1200,
"height": 1000
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
アプリ権限設定
src-tauri/capabilities
に権限設定を作成します。
migrate
CLI command を使うと、v1.xから自動的に権限ファイルを生成してくれるので、
今回はこれを使ってみました。
旧プロジェクト上で、migrationコマンドを実行
bun add -D @tauri-apps/cli@next
bun run tauri migrate
ソースコードが生成された。これを新プロジェクトのsrc-tauriディレクトリにコピーする。
{
"identifier": "migrated",
"description": "permissions that were migrated from v1",
"local": true,
"windows": [
"main"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"shell:allow-open",
"shell:default"
]
}
これで、win, linux, macosのデスクトップ版は稼働確認できた。
iOSビルドの再確認(エラー発生)
bun run tauri ios dev
エラーが出るようになってしまった。
Error [tauri_cli_node] Failed to run `cargo build`: command ["cargo", "build", "--package", "ai_client", "--manifest-path", "/Users/masatoyuna/Project/ai_client_new/ai_client/src-tauri/Cargo.toml", "--target", "aarch64-apple-ios-sim", "--features", "tauri/rustls-tls", "--lib", "--no-default-features"] exited with code 101
Command PhaseScriptExecution failed with a nonzero exit code
** BUILD FAILED **
The following build commands failed:
PhaseScriptExecution Build\ Rust\ Code /Users/masatoyuna/Library/Developer/Xcode/DerivedData/ai_client-fwvrscpltheatpeipnofdrvehucn/Build/Intermediates.noindex/ai_client.build/debug-iphonesimulator/ai_client_iOS.build/Script-C336E540F6E8980E617A63A7.sh (in target 'ai_client_iOS' from project 'ai_client')
(1 failure)
Error command ["xcodebuild"] exited with code 65
似たようなissueが上がっており、
どうやらdesktopアプリで実装している何らかの設定が、mobileでエラーを引き起こしていると思われます。
さらに調査を進めたところ、reqwestを含むビルドに何らかの問題がありそう。
エラーの発生するminimalコードリポジトリを作成し、issueを登録しました。
現時点でiOSのai_client実装は進めなくなったため、検証は中止してバグフィックスを待つことにします。
追記
iOSのSecurity.framework bindingの rust-security-framework 内のバグに起因する事が判明。
tauri2.0(beta.20)でおそらく修正されるので、そのタイミングで確認することにします。