# 🌐 Expo PWA 開發與測試完整指南
> 使用 Expo (React Native) 建立可安裝至手機/桌面的漸進式網頁應用程式(PWA)
---
## 🎯 目標
建立一個支援:
- 安裝到主畫面
- 離線使用(離線快取)
- 桌面與手機通用的 PWA
---
## 🧠 第一部分:核心概念
### 1️⃣ manifest.json(應用程式資訊清單)
- 告訴瀏覽器 App 的名稱、圖示、啟動畫面顏色、顯示模式等
- 讓網站具備「可安裝」的能力
### 2️⃣ Service Worker(服務工作線程)
- 背景執行的 JS 腳本,用來攔截網路請求
- 功能:離線快取、推播通知等
- 建議使用 Google 的 [Workbox](https://developer.chrome.com/docs/workbox/) 工具簡化設定
---
## 🛠 第二部分:設定步驟(從零開始)
> 前提:已有可正常運作的 Expo 專案
---
### 📁 步驟 1:建立 public 資料夾與 PWA 靜態檔案
```bash
mkdir public
```
**建立 `public/manifest.json`:**
```json
{
"short_name": "您的App簡稱",
"name": "您的App完整名稱",
"icons": [
{ "src": "logo192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "logo512.png", "type": "image/png", "sizes": "512x512" }
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
```
**準備圖示:**
- `logo192.png`(192x192)
- `logo512.png`(512x512)
---
### 🧾 步驟 2:建立與編輯 `index.html`
```bash
npx expo customize public/index.html
```
**編輯 `public/index.html` `<head>` 加入:**
```html
<link rel="manifest" href="/manifest.json" />
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then(registration => {
console.log('Service Worker registered:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
});
}
</script>
```
---
### 🔧 步驟 3:使用 Workbox 設定 Service Worker
```bash
npm install workbox-cli --save-dev
```
**建置靜態網頁:**
```bash
npx expo export -p web
```
**執行 Workbox 設定精靈:**
```bash
npx workbox-cli wizard
```
回答:
- `Root of your web app`: `dist`
- `Which file types`: 預設即可
- `Where to save service worker`: `dist/sw.js`
- `Where to save config`: 預設即可(會產生 `workbox-config.js`)
**產生 Service Worker:**
```bash
npx workbox-cli generateSW workbox-config.js
```
---
### 🧩 步驟 4:整合建置指令
**編輯 `package.json`:**
```json
"scripts": {
"build:web": "expo export -p web && npx workbox-cli generateSW workbox-config.js"
}
```
> ✅ 未來只需 `npm run build:web` 即可建置並產生 Service Worker!
---
## 🧪 第三部分:本機測試與部署
---
### 📱 步驟 5:手機本機測試
```bash
npx serve dist
```
- 查看終端顯示 `http://192.168.x.x:3000`
- 手機與電腦同一 Wi-Fi
- 手機瀏覽器輸入 IP,測試:
- 加入主畫面
- 離線模式
❗ 若失敗,請檢查防火牆設定
---
### 🚀 步驟 6:部署到正式環境
上傳 `dist` 資料夾內容到任一靜態主機:
- Netlify
- Vercel
- GitHub Pages
---
## 📂 附錄:核心檔案程式碼
---
### `App.js`
```jsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.title}>🌿 小農市集</Text>
<Text>這是一個可以安裝到主畫面的 Web App!</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1, justifyContent: 'center', alignItems: 'center',
backgroundColor: '#fffbe6',
},
title: {
fontSize: 28, fontWeight: 'bold', marginBottom: 20,
},
});
```
---
### `app.json`
```json
{
"expo": {
"name": "pwa_test",
"slug": "pwa_test",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": { "supportsTablet": true },
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true
},
"web": {
"favicon": "./assets/favicon.png",
"name": "PWA 測試",
"shortName": "PWA",
"display": "standalone",
"startUrl": ".",
"backgroundColor": "#ffffff",
"themeColor": "#4CAF50"
}
}
}
```
---
### `public/index.html`
```html
<!DOCTYPE html>
<html lang="%LANG_ISO_CODE%">
<head>
<link rel="manifest" href="/manifest.json" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>%WEB_TITLE%</title>
<style id="expo-reset">
html, body { height: 100%; overflow: hidden; }
#root { display: flex; height: 100%; flex: 1; }
</style>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then(reg => console.log('SW scope:', reg.scope))
.catch(err => console.error('SW error:', err));
});
}
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
```
---
🧑💻 完成!您現在擁有一個可以「安裝、離線、跨平台」的 React Native PWA!