手機 App:
iOS + Android 全包
網站做完不夠。客戶會問「能不能上 App Store?」這章三條路全教:React Native(一份 code 兩平台)、Kotlin(Android 原生)、Swift(iOS 原生)。 了解每條路的取捨,你才能跟客戶報出對的價、做出對的選擇。
- 看懂 RN / Kotlin / Swift 三條路的取捨
- 會用 Expo 寫 RN,做出能上架的 App
- 會原生 Android / iOS 基本架構
- 會處理推播、相機、定位、IAP
- 會把 App 上架 Play Store 與 App Store
三條路怎麼選
| React Native (Expo) | Kotlin(Android 原生) | Swift(iOS 原生) | |
|---|---|---|---|
| 學習 | 會 React 就能寫 | 新語言新工具 | 新語言新工具 |
| 平台 | iOS + Android(一份 code) | 只有 Android | 只有 iOS |
| 效能 | 好(80% 場景夠) | 頂 | 頂 |
| UI | 跨平台一致 | 原生 | 原生 |
| 適合 | MVP、新創、跨平台 | 大公司、效能要求高 | 大公司、效能要求高 |
| 市場 | 新創 70% 用 | 大公司 Android team | 大公司 iOS team |
還有 Flutter(Dart)、Capacitor(Web 包成 App)、Tauri(桌面為主)。但接案 / 個人最強組合是會 RN + 略懂 Kotlin/Swift。
建議學習順序:(1) 先 RN/Expo 上架你的第一個 App;(2) 接案接到「客戶要原生效能」時再學 Kotlin(市佔較高);(3) iOS 客戶多再學 Swift。
React Native + Expo
npx create-expo-app my-app
cd my-app
npx expo start
# 手機裝 Expo Go App,掃 QR 直接看
// app/index.tsx(Expo Router)
import { View, Text, Button, FlatList } from 'react-native';
import { useState } from 'react';
export default function Home() {
const [todos, setTodos] = useState([]);
return (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 24 }}>待辦事項</Text>
<FlatList
data={todos}
keyExtractor={item => item.id}
renderItem={({ item }) => <Text>{item.text}</Text>}
/>
<Button title="新增" onPress={() => setTodos([...todos, { id: Date.now(), text: '新事項' }])} />
</View>
);
}
跟 Web React 差在哪
- 沒有
div,用<View> - 沒有
p,文字一律包<Text> - 沒有 CSS 檔,用 inline
styleobject 或 StyleSheet - 沒有 click,用
onPress - 列表用
FlatList(虛擬化效能好)
常用套件
expo-router:檔案路由expo-image-picker:相機 / 相簿expo-notifications:推播expo-location:GPSexpo-secure-store:加密儲存(不要把 token 放 AsyncStorage)nativewind:在 RN 用 Tailwind 寫 style
上架
# 用 EAS Build(Expo 雲端打包)
npx eas-cli build --platform ios
npx eas-cli build --platform android
npx eas-cli submit
不用 Mac 也能 build iOS。
Apple 開發者帳號 $99/年,Google Play 一次性 $25。Apple 審核嚴,常被拒;Google 審核較鬆但會用機器掃。第一次上架預留 1~2 週。
Android 原生:Kotlin + Jetpack Compose
Kotlin = Google 官方欽定的 Android 開發語言(取代 Java)。Jetpack Compose = 現代宣告式 UI(類似 React)。
裝 Android Studio
到 developer.android.com 下載 Android Studio。內含 Kotlin compiler、emulator、SDK。
// MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CounterScreen()
}
}
}
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(24.dp)) {
Text("計數: $count", fontSize = 24.sp)
Button(onClick = { count++ }) {
Text("+")
}
}
}
Android 生態關鍵字
- Activity:一個畫面
- Fragment:可重用的子畫面(Compose 後較少用)
- ViewModel:管畫面的狀態與業務邏輯
- Room:本地 SQLite 資料庫的 ORM
- Hilt:依賴注入
- Coroutine + Flow:非同步
- Material 3:Google 設計系統
- Gradle:build 工具(KTS 寫設定)
權限
AndroidManifest.xml 宣告 + runtime 申請(Android 6+):
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted -> if (granted) openCamera() }
launcher.launch(Manifest.permission.CAMERA)
上架 Play Store
- 產 release AAB(Android App Bundle)
- 簽名(Play App Signing)
- 到 Play Console 上傳
- 填店面資訊、隱私權政策、目標年齡
- 送審(通常幾小時~幾天)
iOS 原生:Swift + SwiftUI
Swift = Apple 官方語言。SwiftUI = 跟 Compose 對標的宣告式 UI。需要 Mac(Apple 沒給 Windows / Linux 開發 iOS 的選擇)。
import SwiftUI
struct ContentView: View {
@State var count = 0
var body: some View {
VStack(spacing: 20) {
Text("計數: \(count)")
.font(.title)
Button("+") {
count += 1
}
}
.padding()
}
}
iOS 生態關鍵字
- Xcode:開發環境(Mac only)
- UIKit:舊的 UI 框架(仍多數產品在用)
- SwiftUI:新框架(2019+,現在主推)
- Combine:響應式(被 async/await 部分取代)
- Core Data:本地資料庫
- HIG(Human Interface Guidelines):必讀
- TestFlight:beta 測試發布
上架 App Store
- App Store Connect 建立 App record
- Xcode → Archive → 上傳
- 填店面資訊、隱私標籤(很嚴)
- 送審(1~3 天,可能被退)
Apple 審核會被退的常見原因:UI 寫得像 Web(不像 iOS)、隱私政策不全、有「測試」字樣、用了第三方支付規避抽成(除遊戲外允許 EU)。
共通:推播、IAP、深度連結
推播(Push Notifications)
- iOS:APNs(Apple Push Notification service)
- Android:FCM(Firebase Cloud Messaging)
- 跨平台統一:用 Firebase / OneSignal / Expo Push
- 記得取得權限(iOS 必須使用者主動同意)
IAP(In-App Purchase)
- 數位商品(訂閱、虛擬幣、解鎖功能)必須用平台 IAP(Apple/Google 抽 15~30%)
- 實體商品 / 服務可以走外部金流(Stripe、藍新)
- RN:
react-native-iap或 RevenueCat(推薦,費用 1%)
Deep Link / Universal Link
讓 https://example.com/post/42 在裝有 App 時打開 App。
App 設計建議
- iOS 跟 Android 不要長一樣:每平台有 native pattern(iOS 底部 tab、Android 頂部 app bar)
- 處理離線狀態:手機隨時會斷網。show offline indicator、cache 資料
- Touch target 至少 44pt(iOS HIG)/ 48dp(Material)
- 支援 Dark Mode:使用者預期
- Onboarding ≤ 3 步
- 不要動不動就要登入:先讓使用者體驗,再要註冊
練習:用 Expo 做你的第一個 App
- 把第 6 章的 To-Do List 用 Expo + React Native 重做
- 加入:相機拍照當待辦封面(
expo-image-picker) - 加入:本地推播提醒
- 用 EAS Build 出 APK,安裝到自己手機
- 選擇性:上架到 Google Play 內測