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 변경이 잦다. 공식 소스코드와 실제 동작하는 프로젝트를 참고하는 게 가장 확실하다. ...








