はじめに
Have an existing Nuxt web application? In this guide, you’ll learn how to transform it into native iOS and Android mobile apps using Capacitor 8 — パフォーマンスが向上し、新機能が追加された最新バージョンです。
Capacitor は、既存の Vue コードベースを維持したまま、Web アプリをネイティブコンテナでラップします。これにより、カメラ、ファイルシステム、プッシュ通知などのデバイス API へのアクセスが可能になります。Flutter や React Native とは異なり、コードを書き直す必要はありません。Nuxt の code がそのまま動作します。
学習内容:
- 既存の Nuxt アプリを静的生成用に設定する
- 必須のネイティブプラグインを含む Capacitor 8 を追加する
- iOS および Android シミュレーターでのビルドとテスト
- 開発を高速化するライブリロードの有効化
- iOS でよくあるレイアウトの問題(viewport、セーフエリア、横方向のオーバーフロー)の修正
- Capgo Native Navigation と Transitions でネイティブに近い UI を実現する
ゼロから新しいプロジェクトを始めたいですか?こちらのガイドも参考にしてください: Nuxt モバイルアプリをゼロから構築する.
Nuxt と Capacitor を使用するメリット
- Code による再利用性: VueコンポーネントとロジックをWebアプリとモバイルアプリ間で共有できます。
- パフォーマンス: Nuxtの静的生成は、モバイルに最適な最適化済みbundleを生成します。
- ネイティブ機能: Capacitorプラグインを通じて、カメラ、位置情報、ファイルシステムなどのデバイス機能にアクセスできます。
- シンプルな開発: ネイティブ開発を学ぶことなく、使い慣れたVue/Nuxtのパターンを利用できます。
前提条件
始める前に、以下が準備されていることを確認してください:
- Node.js 18以上 インストール済み
- 既存の Nuxt 4 アプリケーション
- Xcode (iOS開発用、macOSのみ)
- Android Studio (Android開発用)
Nuxtアプリのモバイル向け設定
最初のステップは、Nuxtアプリを静的生成(SSG)用に設定することです。Capacitor でネイティブアプリにバンドルするには、静的なHTML/JS/CSSファイルが必要になります。
以下の項目が package.json generateスクリプトを持っていることを確認してください:
{
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"mobile": "bun run generate && bunx cap sync",
"mobile:ios": "bun run mobile && bunx cap open ios",
"mobile:android": "bun run mobile && bunx cap open android"
}
}
重要: サーバーサイドの機能(API ルートやサーバーミドルウェアなど)を使用している場合は、クライアントサイドの代替手段や外部APIを使用するようにリファクタリングする必要があります。
以下のコマンドを実行して、静的生成をテストしてください:
bun run generate
以下が表示されるはずです: .output/public 静的ファイルが含まれるフォルダです。Capacitor は、この内容をネイティブアプリの bundle に含めます。
プロジェクトに Capacitor 8 を追加する
Nuxt アプリをネイティブモバイルコンテナにパッケージングするには、以下の手順に従ってください:
- Capacitor core と CLI をインストールします:
bun add @capacitor/core
bun add -D @capacitor/cli
- よく使用する Capacitor プラグインをインストールします:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
これらのプラグインは、以下の必須機能を提供します:
- @capacitor/app:アプリのライフサイクルイベント(フォアグラウンド/バックグラウンド、ディープリンク)の処理
- @capacitor/keyboard:モバイルでのキーボード動作の制御
- @capacitor/splash-screen: ネイティブのスプラッシュ画面を管理
- @capacitor/status-bar: デバイスのステータスバーをスタイリング
- @capacitor/preferences: キー・バリュー型のストレージ(localStorageのようにネイティブで動作)
- プロジェクトの詳細を指定して Capacitor を初期化します:
bunx cap init my-app com.example.myapp --web-dir .output/public
置き換え: my-app アプリ名と、 com.example.myapp アプリID(リバースドメイン形式)を指定します。
- 適切な設定を含む
capacitor.config.tsファイルを新規作成または更新します:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: '.output/public',
plugins: {
SplashScreen: {
launchShowDuration: 2000,
launchAutoHide: true,
androidScaleType: 'CENTER_CROP',
splashFullScreen: true,
splashImmersive: true,
},
Keyboard: {
resize: 'body',
resizeOnFullScreen: true,
},
StatusBar: {
style: 'dark',
},
},
};
export default config;
- ネイティブプラットフォームのインストール:
bun add @capacitor/ios @capacitor/android
- ネイティブプラットフォームのフォルダを追加:
bunx cap add ios
bunx cap add android
Capacitor により、 ios と android ネイティブプロジェクトを含むフォルダがプロジェクトのルートに作成されます。
Androidプロジェクトをビルドするには、 Android Studioが必要です。iOSの場合は、Macと Xcode.
- が必要です。プロジェクトのビルドと同期:
bun run mobile
これにより、カスタムスクリプトが実行され、Nuxtの静的ビルドの生成とネイティブプラットフォームへのファイルの同期が行われます。
ネイティブアプリのビルドとデプロイ
ネイティブモバイルアプリのビルドとデプロイは、以下の手順で行います:
iOSアプリを開発するには、以下が必要です: Xcode をインストールしておくこと。また、Androidアプリの場合は、 Android Studio をインストールしてください。また、アプリをストアで配布する予定なら、iOSではApple Developer Program、AndroidではGoogle Play Consoleへの登録が必要です。
- ネイティブプロジェクトを開く:
iOS の場合:
bun run mobile:ios
Androidの場合:
bun run mobile:android
または Capacitor CLI で直接実行:
bunx cap open ios
bunx cap open android
- アプリのビルドと実行:

- Android Studioでプロジェクトの準備が整うまで待ち、「Run」ボタンをクリックして、接続されたデバイスまたはエミュレータにアプリをデプロイします。

- Xcodeで、実機にデプロイするための署名アカウントを設定します。初めての場合は、Xcodeのガイドに従って設定してください(Apple Developer Programへの登録が必要です)。設定完了後、「Play」ボタンをクリックすると、接続されたデバイスでアプリが実行されます。
おめでとうございます!Nuxtウェブアプリのモバイルデバイスへのデプロイが完了しました。
でも、ちょっと待ってください。開発中にもっと速い方法があります…
Capacitor Live Reload
開発中は、Live Reloadを活用すると、モバイルデバイスで変更をすぐに確認できます。この機能を有効にするには、以下の手順に従ってください:
- ローカルIPアドレスを確認する:
-
macOSの場合は、ターミナルで以下のコマンドを実行してください:
ipconfig getifaddr en0 -
Windowsの場合は、以下を実行してください:
ipconfig出力結果からIPv4アドレスを確認してください。
- 以下の内容を含めるように
capacitor.config.ts開発サーバーを指定するには:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: '.output/public',
server: {
url: 'http://YOUR_IP_ADDRESS:3000',
cleartext: true,
},
plugins: {
// ... your plugin config
},
};
export default config;
置き換え: YOUR_IP_ADDRESS ローカルIPアドレスを使用します(例: 192.168.1.100).
- 変更をネイティブプロジェクトに適用するには:
bunx cap copy
この copy このコマンドは、プロジェクト全体を更新することなく、webフォルダと設定の変更内容をネイティブプロジェクトにコピーします。
- Nuxtのdevサーバーを起動し、Xcode/Android Studioでリビルドします:
bun run dev
これで、Nuxtアプリに変更を加えるたびに、モバイルアプリが自動的にリロードされ、変更が反映されるようになります。
注意: 新しいプラグインをインストールしたり、ネイティブファイルを変更したりした場合は、ネイティブプロジェクトのリビルドが必要です。ライブリロードはwebの code の変更にのみ適用されるためです。
Capacitor Plugins の使用
Capacitor プラグインを使用すると、Nuxt アプリからデバイスのネイティブ機能にアクセスできます。今回は、 Share プラグイン を例に、その使い方を見ていきましょう:
- Share プラグインをインストールします:
bun add @capacitor/share
- Share プラグインを使用するページを作成または更新します。Nuxt 4 では、ページは
app/pages/:
<template>
<div class="p-6">
<h1 class="text-2xl font-bold mb-4">Welcome to Nuxt + Capacitor!</h1>
<button
@click="shareContent"
class="px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold"
>
Share now!
</button>
</div>
</template>
<script setup lang="ts">
import { Share } from '@capacitor/share';
async function shareContent() {
await Share.share({
title: 'Check this out!',
text: 'Built with Nuxt and Capacitor',
url: 'https://capacitorjs.com',
dialogTitle: 'Share with friends',
});
}
</script>
- 変更をネイティブプロジェクトに同期します:
bun run mobile
再ビルドせずに同期のみ行う場合:
bunx cap sync
- アプリを再ビルドしてデバイスで実行します。
これで、「Share now!」ボタンをクリックすると、ネイティブの共有ダイアログが表示されます。
次に、Capgo のナビゲーションとトランジションを使用して iOS や Android でアプリをよりネイティブらしく感じさせ、横方向のオーバーフローやセーフエリアの欠けといった iOS 特有のレイアウト問題も解決できます。
Capgo Native Navigation and Transitions でネイティブのような UI を実現
私は長年、 Ionic はクロスプラットフォームアプリの開発に適していますが、Nuxtとの統合は無理やりな感があり、すでに Tailwind CSS.
Nuxt + Capacitor アプリでネイティブアプリのような操作感を実現するには、Konsta UI のような Web 専用の UI キットではなく、Capgo プラグインを使用しましょう:
- @capgo/capacitor-native-navigation — ネイティブのナビゲーションバー、iOS の Liquid Glass タブバー、Android のブラー加工されたタブバー。Nuxt router がルートの状態を管理し、プラグインがネイティブの UI 要素(chrome)を制御します。
- @capgo/capacitor-transitions — Ionic UI を導入することなく、WebView レイヤーで Ionic スタイルのページ遷移や iOS のエッジスワイプバックを実現します。
両方をインストールします:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
CSS の inset モードを使用してネイティブナビゲーションを設定し、Web コンテンツがネイティブバーと重ならないようにします:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Liquid Glass タブバーをレンダリングします(iOS はシステムによるレンダリング、Android はブラーのかかった WebView バックドロップを使用):
await NativeNavigation.setTabbar({
selectedId: 'home',
labelVisibilityMode: 'labeled',
icons: true,
colors: { dynamic: true },
tabs: [
{ id: 'home', title: 'Home', icon: { svg: '...' } },
{ id: 'settings', title: 'Settings', icon: { svg: '...' } },
],
});
await NativeNavigation.addListener('tabSelect', ({ id }) => {
router.push(`/${id}`);
});
アプリシェルにネイティブのページ遷移を追加します:
<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';
initTransitions({ platform: 'auto' });
const router = useRouter();
const outletRef = ref(null);
onMounted(() => {
if (outletRef.value) {
setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
}
});
const openSettings = () => {
setDirection('forward');
router.push('/settings');
};
</script>
<template>
<cap-router-outlet ref="outletRef">
<router-view />
</cap-router-outlet>
</template>
ルーティングされたページを cap-router-outlet, cap-page、および cap-contentでラップし、遷移前に setDirection('forward') または setDirection('back') を呼び出します。ネイティブナビゲーションがそれらの領域を制御している場合、Web側のヘッダーやフッターを重複して表示しないでください。
詳細なガイドはこちら: @capgo/capacitor-native-navigation の使い方 と @capgo/capacitor-transitions の使用方法.
Tailwind でセーフエリアを扱う
Tailwind CSS でデバイスのセーフエリアを使用するには、 @capgo/tailwind-capacitor (公開日: tailwind-capacitor on npm)。提供内容は safe-areas ユーティリティや Capacitor と相性の良い Tailwind プラグイン:
bun add -D tailwind-capacitor
「 app/assets/css/main.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Tailwind CSS 4 を使用する Nuxt 4 では、この import を次から参照される CSS ファイルに残してください: nuxt.config.ts.
次のようなユーティリティを使用します: pt-safe, pb-safe、および px-safe いちいち散りばめる代わりに env(safe-area-inset-*) 手作業で。このプロジェクトは活発に開発されているので、Nuxt のセットアップに足りないものがあれば、 GitHub で PR を作成してください.
iOSのレイアウト問題を修正(ビューポート、セーフエリア、横方向のオーバーフロー)
iOS でコンテンツが切れている、ずれている、横スクロールできるように見える場合は、さらに overflow-x: hidden viewportタグを調整するだけでは通常解決しません。以下のチェックを順番に進めてください。
viewport メタタグが正しく適用されているか確認する
「 nuxt.config.ts、viewportは次で設定してください: app.head:
export default defineNuxtConfig({
app: {
head: {
meta: [
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, viewport-fit=cover',
},
],
},
},
});
iOSのセーフエリアは単一のルートラッパーでのみ処理する
単一のapp shellを作成し、そこにsafe areaのpaddingを適用してください。複数のネストしたコンポーネントには適用しないでください:
html,
body,
#__nuxt {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
.app-shell {
min-height: 100dvh;
width: 100%;
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
すべてのページコンテンツを次の中でラップしてください: .app-shellヘッダー、モーダル、レイアウトのラッパーで safe-area パディングが重複すると、UI が切り取られたり大きすぎたりして見えることがよくあります。
本番環境で @capgo/tailwind-capacitor、次のようなユーティリティで同じパディングを表現できます: pt-safe pb-safe px-safe その単一のシェル上で。
Capacitor の iOS 設定を contentInset へ never 先に
「 capacitor.config.ts、native inset を無効にすることを推奨し、CSS(または Native Navigation の contentInsetMode: 'css')に safe area を任せます:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Capacitor の自動 content inset と CSS を混在させると env(safe-area-inset-*) padding は余白が二重になるよくある原因です。
実際にオーバーフローしている要素を特定する
よくある原因は、次のいずれかを使っている要素です: 100vwTailwind、 w-screen固定ピクセル幅、または大きな min-width.
Safari Web Inspector で次を実行:
[...document.querySelectorAll('*')]
.filter(el => el.scrollWidth > document.documentElement.clientWidth)
.map(el => ({
el,
tag: el.tagName,
class: el.className,
scrollWidth: el.scrollWidth,
clientWidth: document.documentElement.clientWidth,
}));
Tailwind を使う場合は置き換え: w-screen と w-full 可能であれば。水平方向のオーバーフロー問題の多くは、 100vw / w-screen、重複したセーフエリアのパディング、または固定幅のコンテナが原因であり、viewport metaタグ自体が原因ではありません。
まとめ
Capacitor 8 を使用して、既存の Nuxt ウェブアプリケーションを iOS および Android のネイティブアプリへの変換に成功しました。Vue のコードベースは、デバイス API にアクセスしながらモバイルデバイス上でネイティブに動作します。
実現したこと:
- Nuxt の静的生成の設定
- 必須プラグインを含む Capacitor 8 の追加
- iOS および Android シミュレーターへのビルドとデプロイ
- 開発用の live reload を有効化
- iOSでよくあるレイアウトの問題(viewport、セーフエリア、overflow)を修正
- Capgo Native NavigationとTransitionsによるネイティブなUIを追加
次のステップ:
- セットアップ Capgo App Storeの再申請なしでOTAアップデートを行う
- Camera、Geolocation、Push Notificationsなどのネイティブプラグインを追加する
- 本番環境用のアプリアイコンとスプラッシュ画面を設定する
- App StoreとGoogle Playへの申請準備を行う
新規プロジェクトを始めるなら、こちらをチェック: Nuxtでネイティブモバイルアプリをゼロから構築する ステップバイステップのガイドがあります。
リソース
- Nuxt ドキュメント
- Capacitor 8 ドキュメント
- @capgo/capacitor-native-navigation — Liquid Glass タブバーとネイティブな UI
- @capgo/capacitor-transitions — ネイティブのようなページ遷移
- @capgo/tailwind-capacitor — Capacitor 用の Tailwind safe-area ユーティリティ
- Capgo - Capacitor アプリ向け Live Updates
Capgoがより良いアプリをより速く構築するのにどう役立つかを学び、 無料アカウントに登録して 今すぐ。
Capacitor を使って Nuxt アプリを iOS & Android に変換する 8 節へ続く
以下を使用している場合: Capacitor を使って Nuxt アプリを iOS & Android に変換する 8 ネイティブプラグインの作業を計画するには、それを以下と連携させる Capgo プラグインディレクトリ Capgo プラグインディレクトリでのプロダクトワークフロー向けに、 Capgo による Capacitor プラグイン Capgo による Capacitor プラグインの実装詳細については、 プラグインの追加・更新 プラグインの追加・更新における実装詳細については、 Ionic Enterprise プラグインの代替案 Ionic Enterprise プラグインの代替案のプロダクトワークフロー、および Capgo Native Build Capgo Native Builds のプロダクトワークフローについて。