WorkoutPlan

Workout 45 – Lộ trình tập tại nhà cá nhân hoá (iOS + Web)

Cấu trúc

WorkoutPlan/Resources/
  planner.js.txt     ← bộ tạo lộ trình DUY NHẤT, dùng chung cho iOS (JavaScriptCore) và web
  exercises.json     ← 79 bài tập (10 ngôn ngữ + khung hình động tác)
  content.json       ← chuỗi giao diện, mục đích, loại buổi tập, mức độ, giai đoạn (10 ngôn ngữ)
WorkoutPlan/         ← mã nguồn iOS (SwiftUI)
web/                 ← web app (HTML/CSS/JS thuần, không cần build)
Tools/               ← script Python sinh exercises.json / content.json (python3 Tools/build.py)
Config/Info.plist    ← URL scheme cho Google Sign-In (iOS)
firestore.rules      ← luật bảo mật Firestore
.github/workflows/pages.yml ← tự deploy web lên GitHub Pages

planner.js.txt có đuôi .txt để Xcode chép nó vào app như tài nguyên. Bản web dùng đúng file đó (khi deploy được đổi tên thành planner.js).


1. Deploy web lên workout.vnpt.app (GitHub Pages)

  1. Repo doanhnn/WorkoutPlan cần để Public (gói GitHub Free chỉ có Pages cho repo public).
  2. GitHub → repo → Settings → Pages → Build and deployment → Source: GitHub Actions.
  3. Push code lên nhánh main → tab Actions chạy workflow Deploy web app to GitHub Pages.
  4. Settings → Pages → Custom domain: nhập workout.vnpt.app → Save.
  5. Google Cloud DNS (zone của vnpt.app) → Add standard → DNS name workout, Type CNAME, TTL 300, Canonical name doanhnn.github.io. Hoặc bằng lệnh:
    gcloud dns record-sets create workout.vnpt.app. --zone=<TEN_ZONE> --type=CNAME --ttl=300 --rrdatas=doanhnn.github.io.
    
  6. Chờ GitHub báo DNS check successful, rồi tick Enforce HTTPS. Tên miền .app bắt buộc HTTPS, nên trang chỉ mở được sau khi GitHub cấp chứng chỉ (thường vài phút đến 1 giờ).
  7. (Khuyến nghị) GitHub → Settings (tài khoản) → Pages → Add a domain để xác minh vnpt.app bằng bản ghi TXT, chống bị chiếm subdomain.

Xem thử trên máy: ./web/serve.sh rồi mở http://localhost:8080

2. Bật đăng nhập Google + đồng bộ (Firebase)

  1. https://console.firebase.google.com → Add project. Có thể chọn đúng project Google Cloud đang dùng cho DNS.
  2. Build → Authentication → Get started → Sign-in method → Google → Enable, chọn email hỗ trợ → Save. Authentication → Settings → Authorized domains → Add domain: workout.vnpt.app (và doanhnn.github.io nếu muốn).
  3. Build → Firestore Database → Create database → chọn vùng (ví dụ asia-southeast1) → Production mode. Tab Rules → dán nội dung file firestore.rulesPublish.
  4. Web: Project settings → Your appsAdd app → Web → copy object firebaseConfig → dán vào web/firebase-config.js (thay null) → commit & push.
  5. iOS: Project settings → Add app → iOS, Bundle ID com.ezekiel.workoutplan → tải GoogleService-Info.plist (tải sau khi đã bật Google ở bước 2) → kéo vào thư mục WorkoutPlan/WorkoutPlan/. Mở plist, copy giá trị REVERSED_CLIENT_ID → Xcode → target WorkoutPlanBuild Settings → tìm GOOGLE_REVERSED_CLIENT_ID → dán vào.
  6. Build lại app. Đăng nhập cùng một tài khoản Google trên iPhone và web: lộ trình, ngôn ngữ và lịch sử tập sẽ tự đồng bộ.

Dữ liệu Firestore: users/{uid} = { profile, profileT, lang, langT, log: { "yyyy-MM-dd": { d, t, m } } }. Gộp dữ liệu theo nguyên tắc bản ghi mới nhất thắng.

3. Build iOS

  1. Mở WorkoutPlan.xcodeproj bằng Xcode 16 trở lên. Lần đầu mở, Xcode tự tải các Swift Package: firebase-ios-sdkGoogleSignIn-iOS.
  2. Chọn Team trong Signing & CapabilitiesRun.
  3. Chưa có GoogleService-Info.plist thì app vẫn chạy bình thường, chỉ chưa đăng nhập được.

Lưu ý sức khoẻ: nếu có bệnh lý tim mạch, huyết áp, chấn thương, hoặc thấy đau/chóng mặt khi tập, hãy dừng lại và hỏi ý kiến bác sĩ.