Rails 앱을 Hotwire Native로 iOS 앱 만들어 TestFlight 올리기까지의 삽질 기록

Rails 8로 만든 긴급 신고 웹앱 바로신고를 Hotwire Native으로 iOS 앱으로 감싸서 TestFlight에 올리기까지의 과정을 정리합니다. 기술 스택 Backend: Rails 8 + Turbo iOS: Hotwire Native 1.2.2 + XcodeGen 빌드: Makefile 자동화 프로젝트 구조 ios/ ├── project.yml # XcodeGen 설정 ├── ExportOptions.plist # App Store 내보내기 ├── Makefile # 빌드 자동화 └── BaroSingo/ ├── AppDelegate.swift ├── SceneController.swift ├── AppTab.swift ├── Bridge/ │ ├── FormComponent.swift │ ├── HapticComponent.swift │ └── ShareComponent.swift └── Resources/ ├── Assets.xcassets/ └── path-configuration.json 삽질 1: Hotwire Native API 변경 Hotwire.config.userAgent — 읽기 전용 // ❌ 컴파일 에러: 'userAgent' is a get-only property Hotwire.config.userAgent = "BaroSingo iOS" // ✅ 해결: makeCustomWebView 사용 Hotwire.config.makeCustomWebView = { configuration in let webView = WKWebView(frame: .zero, configuration: configuration) webView.customUserAgent = "BaroSingo iOS/1.0 Turbo Native" return webView } Hotwire.loadPathConfiguration — 존재하지 않는 API // ❌ 컴파일 에러: no member 'loadPathConfiguration' Hotwire.loadPathConfiguration(from: [source]) // ✅ 해결: config.pathConfiguration.sources 직접 설정 Hotwire.config.pathConfiguration.sources = [ .file(Bundle.main.url(forResource: "path-configuration", withExtension: "json")!), .server(URL(string: "\(baseURL)/api/hotwire/path-configuration")!) ] Bridge Component에서 ViewController 접근 // ❌ 컴파일 에러: optional type must be unwrapped delegate.webView?.findViewController() // ✅ 해결: delegate?.destination 사용 guard let viewController = delegate?.destination as? UIViewController else { return } 교훈: Hotwire Native는 버전별 API 변경이 잦다. 공식 소스코드와 실제 동작하는 프로젝트를 참고하는 게 가장 확실하다. ...

2026-03-07 · 4분 소요 · Seunghan
Google Oauth Wrong Project Number

Google OAuth 클라이언트 ID의 프로젝트 번호가 Firebase 프로젝트 번호와 다른 경우

Google OAuth를 새로운 환경에서 재설정하려는데 기존에 저장된 Client ID의 프로젝트 번호가 Firebase 프로젝트 번호와 달라 secret을 찾을 수 없었던 케이스를 정리한다. 상황 .env 파일에 이런 형태로 저장되어 있었다. GOOGLE_CLIENT_ID=1091056260493-xxxxxxxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET= # 비어있음 Firebase 콘솔을 확인하니 해당 앱의 실제 프로젝트 번호는 333977052282였다. Google OAuth Client ID의 앞부분 숫자가 GCP 프로젝트 번호다. 즉 1091056260493이라는 프로젝트가 따로 존재해야 하는데, gcloud 계정에서 확인해보니 해당 번호의 프로젝트가 없었다. 원인 파악 # 전체 프로젝트 목록 확인 curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ "https://cloudresourcemanager.googleapis.com/v1/projects" | \ python3 -c "import sys,json; [print(p['projectNumber'], p['projectId']) for p in json.load(sys.stdin)['projects']]" 결과에서 1091056260493 번호를 가진 프로젝트가 없음을 확인. ...

2025-06-15 · 2분 소요 · Seunghan
개인정보처리방침 문의