Pendahuluan
Inginkah Anda membangun aplikasi seluler dengan Next.js dari awal? Panduan ini akan membawa Anda melalui pembuatan proyek Next.js 15 baru yang dikonfigurasi untuk seluler dari hari pertama, kemudian mengemasnya sebagai aplikasi native iOS dan Android menggunakan Capacitor 8.
Oleh akhir tutorial ini, Anda akan memiliki aplikasi seluler yang berjalan yang dapat Anda lanjutkan mengembangkan dan akhirnya menerbitkan ke App Store dan Google Play.
Waktu yang dibutuhkan: ~30 menit
Apa yang akan dibangun:
- Proyek Next.js 15 baru dengan App Router
- Konfigurasi ekspor statis untuk seluler
- Capacitor 8 dengan plugin penting
- Aplikasi iOS dan Android asli
- Pengaturan pengembangan reload langsung
Sudah memiliki aplikasi Next.js? Cek Mengubah Aplikasi Next.js menjadi Mobile sebaliknya.
Prerequisites
Pastikan Anda telah menginstal hal-hal berikut:
- Node.js 18+ (periksa dengan
node --version) - Bun manajer paket (
curl -fsSL https://bun.sh/install | bash) - Xcode (hanya untuk pengembang iOS di macOS)
- Studio Android (untuk pengembang Android)
Langkah 1: Buat Projek Next.js Baru
Mulai dengan membuat proyek Next.js 15 yang segar:
bunx create-next-app@latest my-mobile-app
Pilihlah opsi-opsi berikut ketika diminta.
- TypeScript: Ketika diminta, pilih opsi-opsi berikut:
- TypeScript: Yes
- ESLint: Ya Yes (dianjurkan untuk gaya mobile)
src/directory: Yes- Router Aplikasi: Yes (dianjurkan)
- Import alias: Default (
@/*)
Pergi ke proyek Anda:
cd my-mobile-app
Langkah 2: Konfigurasi Next.js untuk Export Statik
Capacitor memerlukan file HTML/JS/CSS statis. Konfigurasi Next.js untuk export statis dengan mengupdate next.config.ts:
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
output: 'export',
images: {
unoptimized: true,
},
// Ensure trailing slashes for proper routing in Capacitor
trailingSlash: true,
};
export default nextConfig;
Mengapa pengaturan ini?
output: 'export'— Membuat HTML statis daripada memerlukan server Node.jsimages: { unoptimized: true }— Menghapus Optimasi Gambar Next.js (memerlukan server)trailingSlash: true— Menjamin routing yang tepat di WebView Native
Langkah 3: Tambahkan Skrip Mobile
Update Anda package.json dengan skrip pengembangan mobile:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"mobile": "bun run build && bunx cap sync",
"mobile:ios": "bun run mobile && bunx cap open ios",
"mobile:android": "bun run mobile && bunx cap open android"
}
}
Tes bangun:
bun run build
Anda harus melihat sebuah out direktori dengan file statis Anda.
Langkah 4: Pasang Capacitor 8
Pasang paket-paket inti Capacitor:
bun add @capacitor/core
bun add -D @capacitor/cli
Pasang plugin-plugin yang paling umum digunakan oleh aplikasi mobile:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
Apa yang dilakukan plugin ini:
- @capacitor/app — Acara Hidup Aplikasi (depan/belakang, tautan dalam)
- @capacitor/keyboard — Mengontrol perilaku kibor
- @capacitor/splash-screen — Pengendalian layar splash native
- @capacitor/status-bar — Mengatur baris status perangkat
- @capacitor/preferences — Penyimpanan nilai kunci (seperti localStorage tetapi native)
Langkah 5: Inisialisasi Capacitor
Mulai Capacitor dengan detail proyek Anda:
bunx cap init "My Mobile App" com.example.mymobileapp --web-dir out
Ubah:
"My Mobile App"Dengan nama layar aplikasi Andacom.example.mymobileappDengan ID aplikasi Anda (notasi domain terbalik)
Ini menciptakan capacitor.config.ts. Perbarui dengan konfigurasi plugin:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.mymobileapp',
appName: 'My Mobile App',
webDir: 'out',
plugins: {
SplashScreen: {
launchShowDuration: 2000,
launchAutoHide: true,
androidScaleType: 'CENTER_CROP',
splashFullScreen: true,
splashImmersive: true,
},
Keyboard: {
resize: 'body',
resizeOnFullScreen: true,
},
StatusBar: {
style: 'light',
},
},
};
export default config;
Langkah 6: Tambahkan Platform Nativ
Instal paket platform:
bun add @capacitor/ios @capacitor/android
Membuat proyek-proyek natif:
bunx cap add ios
bunx cap add android
Ini menciptakan ios dan android direktori yang berisi proyek-proyek natif tersebut.
Langkah 7: Bangun dan Jalankan
Bangun proyek Anda dan sinkron dengan platform native:
bun run mobile
Membuka di Simulator iOS:
bun run mobile:ios
Atau Emulator Android:
bun run mobile:android
Dalam Xcode (iOS):
- Pilih simulator dari dropdown perangkat
- Klik tombol Play atau tekan
Cmd + R
Dalam Studio Android:
- Tunggu Gradle selesai sinkron
- Pilih emulator dari dropdown perangkat
- Klik tombol Run atau tekan
Shift + F10
Langkah 8: Atur Ulang Reload Langsung
Untuk pengembangan yang lebih cepat, aktifkan ulang hidup untuk perubahan muncul secara instan pada perangkat Anda.
- Temukan alamat IP lokal Anda:
# macOS
ipconfig getifaddr en0
# Windows
ipconfig
- Buat konfigurasi pengembangan Capacitor Anda. Tambahkan ke
capacitor.config.ts:
import type { CapacitorConfig } from '@capacitor/cli';
const devConfig: CapacitorConfig = {
appId: 'com.example.mymobileapp',
appName: 'My Mobile App',
webDir: 'out',
server: {
url: 'http://YOUR_IP_ADDRESS:3000',
cleartext: true,
},
plugins: {
// ... same plugin config
},
};
const prodConfig: CapacitorConfig = {
appId: 'com.example.mymobileapp',
appName: 'My Mobile App',
webDir: 'out',
plugins: {
// ... same plugin config
},
};
const config = process.env.NODE_ENV === 'development' ? devConfig : prodConfig;
export default config;
- Mulai server pengembangan dan salin konfigurasi ke native:
bun run dev &
NODE_ENV=development bunx cap copy
- Rebuild di Xcode/Android Studio
Sekarang perubahan pada Next.js code Anda akan memuat ulang secara otomatis di perangkat.
Langkah 9: Buat Layar Mobile Pertama
Buatlah layar utama yang ramah seluler sederhana. src/app/page.tsx:
'use client';
import { useEffect, useState } from 'react';
import { App } from '@capacitor/app';
import { Keyboard } from '@capacitor/keyboard';
export default function Home() {
const [appInfo, setAppInfo] = useState<{ name: string; version: string } | null>(null);
useEffect(() => {
// Get app info on mount
App.getInfo().then(setAppInfo).catch(console.error);
// Handle back button on Android
const backHandler = App.addListener('backButton', ({ canGoBack }) => {
if (!canGoBack) {
App.exitApp();
} else {
window.history.back();
}
});
// Hide keyboard when tapping outside inputs
const keyboardHandler = Keyboard.addListener('keyboardWillShow', () => {
document.body.classList.add('keyboard-open');
});
return () => {
backHandler.then(h => h.remove());
keyboardHandler.then(h => h.remove());
};
}, []);
return (
<main className="min-h-screen bg-linear-to-b from-blue-500 to-blue-700 flex flex-col items-center justify-center p-6 text-white">
<h1 className="text-4xl font-bold mb-4">My Mobile App</h1>
<p className="text-xl mb-8 text-center opacity-90">
Built with Next.js 15 + Capacitor 8
</p>
{appInfo && (
<div className="bg-white/20 rounded-lg p-4 backdrop-blur-sm">
<p className="text-sm">
{appInfo.name} v{appInfo.version}
</p>
</div>
)}
<div className="mt-12 space-y-4 w-full max-w-sm">
<button className="w-full py-4 px-6 bg-white text-blue-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform">
Get Started
</button>
<button className="w-full py-4 px-6 bg-white/20 text-white rounded-xl font-semibold text-lg backdrop-blur-sm active:scale-95 transition-transform">
Learn More
</button>
</div>
</main>
);
}
Mari kita buat layar home yang ramah mobile. Perbarui
Perangkat mobile memiliki notifikasi, indikator rumah, dan bar status. Tambahkan penanganan area aman dengan Tailwind.
Update src/app/globals.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--sat: env(safe-area-inset-top);
--sar: env(safe-area-inset-right);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
}
body {
padding-top: var(--sat);
padding-right: var(--sar);
padding-bottom: var(--sab);
padding-left: var(--sal);
}
/* Prevent text selection on mobile */
* {
-webkit-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
/* Allow text selection in inputs */
input, textarea {
-webkit-user-select: auto;
user-select: auto;
}
/* Keyboard handling */
.keyboard-open {
--sab: 0px;
}
Struktur Proyek
Project Anda sekarang harus terlihat seperti ini:
my-mobile-app/
├── android/ # Android native project
├── ios/ # iOS native project
├── out/ # Static build output
├── src/
│ ├── app/
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ └── ...
├── capacitor.config.ts # Capacitor configuration
├── next.config.ts # Next.js configuration
├── package.json
└── ...
Next Steps
Sekarang Anda memiliki aplikasi seluler Next.js yang berfungsi. Ini langkah selanjutnya:
Pengaturan Dasar
- Ikon Aplikasi: Ganti ikon bawaan di
ios/App/App/Assets.xcassetsdanandroid/app/src/main/res - Layar Splash: Customisasi di proyek native atau gunakan
@capacitor/splash-screenKonfigurasi - Tautan Kunci: Konfigurasi skema URL untuk aplikasi kamu
Tambahkan Fitur Lain
- Kamera:
bun add @capacitor/camera - Geolokasi:
bun add @capacitor/geolocation - Pemberitahuan Push:
bun add @capacitor/push-notifications - Sistem File:
bun add @capacitor/filesystem
Tampilan UI dan transisi native
Pakai plugin Capgo bukan Konsta UI untuk merasakan perangkat mobile yang asli:
- @capgo/capacitor-navigasi native — tab bar Liquid Glass dan navbar native
- @capgo/capacitor-transisi — transisi halaman yang merasakan seperti native
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Untuk area aman Tailwind, tambahkan @capgo/tailwind-capacitor:
bun add -D tailwind-capacitor
Melihat Menggunakan @capgo/capacitor-navigasi native, Menggunakan @capgo/capacitor-transisi, dan repo tailwind-capacitor untuk pengaturan khusus Next.js.
Memperbaiki Masalah Tampilan iOS (Viewport, Area Aman, dan Horizontal Overflow)
Jika konten terlihat dipotong, bergeser, atau dapat di-scroll secara horizontal pada iOS, menambahkan lebih banyak overflow-x: hidden atau mengatur tag viewport saja biasanya tidak dapat memperbaikinya. Jalankan periksaan-periksaan ini secara berurutan.
Pastikan tag meta viewport diterapkan dengan benar
Router Aplikasi (app/: export viewport menggunakan app/layout.tsx:
import type { Viewport } from 'next';
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover',
};
Router Halaman (pages/: masukkan tag meta viewport di pages/_app.tsx, bukan _document.tsx.
Tangani area aman iOS dari satu wrapper root saja
Buat shell aplikasi tunggal dan aplikasikan padding area aman di sana — bukan di komponen nested beberapa kali:
html,
body,
#__next {
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);
}
Tutup semua konten halaman di dalam .app-shell. Menggunakan padding area aman yang sama di header, modal, dan wrapper layout sering membuat UI terlihat dipotong atau terlalu besar.
Dengan @capgo/tailwind-capacitor, Anda dapat menyatakan padding yang sama dengan utilitas seperti pt-safe pb-safe px-safe di shell tunggal itu.
Buat Capacitor iOS contentInset ke never pertama
Dalam capacitor.config.ts, lebih baik menggunakan inset disabled asli dan biarkan CSS (atau Native Navigation's) contentInsetMode: 'css') mengontrol area yang aman:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Menggabungkan Capacitor's automatic content inset dengan CSS env(safe-area-inset-*) padding adalah penyebab umum dari jarak ganda.
Temukan elemen yang mengalir melebihi batas
Biasanya, penjahatnya adalah elemen yang menggunakan 100vw, Tailwind w-screen, lebar piksel tetap, atau besar min-width.
In Safari Web Inspector, jalankan:
[...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,
}));
Dengan Tailwind, ganti w-screen dengan w-full ketika memungkinkan. Banyak masalah overflow horizontal berasal dari 100vw / w-screen, padding area aman yang digandakan, atau kontainer dengan lebar tetap — bukan dari tag meta viewport itu sendiri.
Pembaruan Melalui Jaringan
Konfigurasi Capgo Pembaruan tanpa perlu mengirimkan aplikasi ke toko aplikasi:
bunx @capgo/cli init
Penyelidikan Masalah
Konfigurasi gagal dengan ‘Tidak Dapat Menemukan Modul’
Jalankan bun install dan coba lagi.
iOS: “Tidak ditemukan identitas tanda tangan” Buka Xcode, pergi ke Signing & Capabilities, dan pilih tim pengembangan Anda.
Anda Android: “SDK lokasi tidak ditemukan”
Buat android/local.properties dengan sdk.dir=/path/to/android/sdk
Pertanyaan perubahan tidak muncul di perangkat
Pastikan Anda menjalankan bun run mobile setelah membuat perubahan. Untuk reload hidup, verifikasi alamat IP yang benar dan server pengembangan berjalan.
Sumber Daya
- Capacitor 8 Dokumentasi
- Dokumentasi Next.js 15
- Capgo - Perbarui Hidup
- @capgo/capacitor-navigasi asli
- @capgo/capacitor-transisi
- @capgo/tailwind-capacitor
Ready to ship your app? Learn how Capgo can help you deliver updates faster — daftar gratis sekarang hari ini.
Teruskan dari Membangun Aplikasi Mobile Next.js dari Awal dengan Capacitor 8
Jika Anda menggunakan Membangun Aplikasi Mobile Next.js dari Awal dengan Capacitor 8 untuk merencanakan otomatisasi CI/CD, hubungkannya dengan Capgo CI/CD untuk alur kerja produk dalam Capgo CI/CD, Capgo Native Builds untuk alur kerja produk dalam Capgo Pembangunan Nativ Capgo Integrations untuk alur kerja produk di Capgo Integrations, Pengintegrasian CI/CD untuk detail implementasi di Integrasi CI/CD, dan GitHub Actions Integration Untuk detail implementasi di GitHub Integrasi Aksi.