Flutter Dart Define Api Url Testflight

Flutter TestFlight 빌드에서 API URL이 localhost로 고정되는 문제

Flutter 앱을 TestFlight에 올렸는데 실기기에서 모든 API 요청이 실패하는 경우, --dart-define으로 API URL이 주입되지 않아서 앱이 localhost로 요청을 보내고 있는 게 원인일 수 있다. 증상 시뮬레이터에서는 정상 동작 (로컬 서버에 연결되니까) TestFlight 빌드(실기기)에서는 로그인, API 호출 모두 실패 서버 로그에 해당 요청이 아예 안 찍힘 → 클라이언트가 서버에 요청 자체를 안 하고 있음 원인 Flutter에서 환경별 API URL을 --dart-define으로 주입받는 패턴을 쓰는 경우, 빌드 명령에 이 인자를 빠뜨리면 코드 내 기본값이 사용된다. ...

2025-07-13 · 2분 소요 · Seunghan
Flutter Clean Architecture Multi Feature

Flutter Clean Architecture 실전 - Feature 여러 개 한 번에 추가하기

Flutter 앱에 기능을 한 번에 여러 개 추가할 때 가장 먼저 고민되는 건 폴더 구조다. 기능 하나하나는 단순해 보여도, 여러 개가 동시에 들어오면 금방 엉킨다. Feature별 폴더 구조 Clean Architecture를 기반으로 각 Feature를 아래 구조로 만든다. lib/features/{feature_name}/ ├── data/ │ ├── datasources/ # API 호출 │ └── repositories/ # 인터페이스 구현체 ├── domain/ │ ├── entities/ # 순수 데이터 모델 │ └── repositories/ # 인터페이스 정의 └── presentation/ ├── bloc/ # BLoC (이벤트/상태) └── pages/ # UI 이걸 따르면 기능이 몇 개가 늘어도 구조는 동일하다. 새 기능 추가 = 폴더 복사 + 내용 채우기 수준이 된다. ...

2025-07-09 · 3분 소요 · Seunghan
Flutter Bloc Complex State Management

Flutter BLoC - Q&A 세션처럼 상태가 복잡할 때 설계하기

목록을 불러오고 보여주는 수준의 BLoC는 어렵지 않다. 문제는 세션 기반의 흐름, 예를 들어 “세션을 만들고 → 질문을 추가하고 → 답변을 받고 → 완료” 같은 단계적 워크플로우를 BLoC 하나로 관리할 때다. 상태를 먼저 그려라 BLoC를 코딩하기 전에 상태부터 정의하는 게 순서다. 이 워크플로우에서 UI가 보여줘야 하는 상태를 나열하면: 초기 (아무것도 없음) 세션 목록 로딩 중 세션 목록 표시 새 세션 생성 중 세션 상세 로딩 중 세션 상세 표시 (질문 목록 포함) 질문 추가 중 답변 입력 중 오류 abstract class ReviewQaState {} class ReviewQaInitial extends ReviewQaState {} class ReviewQaLoading extends ReviewQaState {} class ReviewQaSessionListLoaded extends ReviewQaState { final List<QaSession> sessions; ReviewQaSessionListLoaded(this.sessions); } class ReviewQaSessionLoaded extends ReviewQaState { final QaSession session; final List<ReviewQuestion> questions; ReviewQaSessionLoaded({required this.session, required this.questions}); } class ReviewQaQuestionAdded extends ReviewQaState { final ReviewQuestion question; ReviewQaQuestionAdded(this.question); } class ReviewQaError extends ReviewQaState { final String message; ReviewQaError(this.message); } 상태 클래스를 이렇게 구체적으로 나눠야 UI에서 if (state is ReviewQaSessionLoaded) 처럼 명확하게 분기할 수 있다. ...

2025-07-06 · 3분 소요 · Seunghan
Firebase Phone Auth Not Working Diagnosis

Flutter Firebase Phone Auth - SMS가 안 와요? 진단부터 코드 수정까지

Flutter 앱에 전화번호 인증을 붙이고 나서 “인증번호가 안 와요"라는 상황을 마주쳤다. 그리고 개발용 bypass 버튼을 눌러서 인증을 건너뛰고 회원가입을 시도하면 서버에서 “인증이 완료되지 않은 전화번호입니다"가 떴다. 두 문제를 같이 정리한다. 구조부터 파악 Flutter Firebase Phone Auth의 흐름은 이렇다. Flutter → FirebaseAuth.verifyPhoneNumber() → Firebase가 SMS 직접 발송 ↓ 사용자가 코드 입력 ↓ Flutter → Firebase로 코드 검증 → ID Token 획득 ↓ Flutter → 백엔드로 firebase_token 전송 → 서버가 토큰 검증 → PhoneVerification 레코드 생성 ↓ Flutter → 회원가입 요청 → 서버가 PhoneVerification 확인 후 유저 생성 핵심은 SMS 발송 자체를 Firebase가 담당한다는 점이다. Rails나 다른 백엔드에서 Twilio 등을 호출하는 구조가 아니다. ...

2025-07-02 · 3분 소요 · Seunghan
Firebase Android Sha1 Ios Apns Complete Setup

Firebase Phone Auth 플랫폼 설정 완전 정복 - Android SHA-1, iOS APNs

Firebase 전화 인증을 붙이고 에뮬레이터에서는 되는데 실기기에서 안 된다면, 대부분 플랫폼별 추가 설정이 빠진 것이다. Android와 iOS 각각 필요한 설정을 정리한다. Android: SHA-1 지문 등록 Firebase Phone Auth는 Android에서 Play Integrity API를 사용한다. 이 때문에 앱의 서명 키 지문(SHA-1)을 Firebase에 등록해야 한다. 없으면 인증 요청 자체가 실패한다. 1. 키스토어에서 SHA-1 추출 keytool -list -v \ -keystore android/app/upload-keystore.jks \ -alias upload \ -storepass YOUR_STORE_PASSWORD 출력 예시: SHA1: 64:60:03:0B:00:6F:E2:29:A4:40:DD:E3:44:3A:7D:32:39:2B:6A:42 SHA256: 24:83:18:41:D6:9A:E5:84:26:71:8E:A2:... key.properties 파일이 있다면 비밀번호를 거기서 확인한다. ...

2025-06-29 · 3분 소요 · Seunghan
Telegram Bot Intent Classification Bugs

Telegram 봇 의도 분류 버그 3가지와 Inline Keyboard 확인 플로우 구현

Telegram 봇에 자연어로 할 일을 추가하는 기능을 운영하던 중 발생한 버그 3가지와, 사용자 경험 개선을 위한 inline keyboard 확인 플로우 구현 내용을 정리한다. 버그 1: “저녁9시” → 09:00(AM)으로 파싱되는 문제 현상 입력: "내일 저녁 커피챗 미팅 저녁9시일정추가" 기대: due_time = "21:00" 실제: due_time = "09:00" 원인 extract_time_from_text 메서드에서 패턴 체크 순서가 잘못되어 있었다. # 버그 코드 if match = text.match(/오후\s*(\d{1,2})시/) # 1) 오후 ... end if match = text.match(/오전\s*(\d{1,2})시/) # 2) 오전 ... end if match = text.match(/(\d{1,2})시\s*(\d{1,2})?분?/) # 3) 숫자시 ← 여기서 "9시" 매칭 hour = match[1].to_i # 9 → "09:00" 반환, 아래 case/when은 도달 불가 return "#{hour.to_s.rjust(2, '0')}:00" end case text when /저녁/ return "18:00" # ← 절대 도달 못 함 end “저녁9시"에서 오후, 오전 패턴은 불일치하지만 세 번째 /(\d{1,2})시/ 패턴이 9시를 잡아 09:00을 반환해버린다. 그 아래 case when /저녁/은 절대 실행되지 않는다. ...

2025-06-25 · 5분 소요 · Seunghan
Rails Api Token Not Null Constraint

Rails API 토큰 생성: NOT NULL 컬럼 누락으로 발생하는 오류

Rails API 서버에서 소셜 로그인(SSO) 후 토큰을 발급하는 로직을 작성하다가 발생한 문제를 정리한다. 상황 Apple Sign In / Google Sign In 후 서버에서 access token과 refresh token을 발급해 클라이언트에 반환해야 한다. 컨트롤러에서 아래와 같이 직접 생성을 시도했다. token = user.api_tokens.create!( token_type: "bearer", expires_at: 1.hour.from_now ) 오류 ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR: null value in column "token_digest" violates not-null constraint 원인 api_tokens 테이블의 실제 스키마를 확인해보니 아래 컬럼들이 NOT NULL로 정의되어 있었다. # db/schema.rb create_table "api_tokens" do |t| t.string "token_digest", null: false # SHA-256 해시값 t.string "refresh_token_digest", null: false # refresh token 해시값 t.datetime "refresh_expires_at", null: false # refresh 만료 시각 t.string "jti", null: false # JWT ID (중복 방지) # ... end 직접 create!를 호출하면 이 컬럼들에 값이 자동으로 채워지지 않는다. ...

2025-06-22 · 2분 소요 · Seunghan
Ios Codesign Testflight Full Setup

iOS 배포 인증서 전체 세팅: Distribution Cert → APNs → Provisioning Profile → TestFlight

Flutter 앱을 TestFlight에 올리는 과정에서 코드 서명 관련 설정을 처음부터 다시 잡으면서 정리한 내용이다. Xcode 자동 서명이 아닌 수동 + App Store Connect API Key 방식으로 진행했다. 전체 흐름 [1] Distribution Certificate 발급 [2] APNs Certificate 발급 (CSR 생성 필요) [3] App ID에 Push Notifications 활성화 [4] Provisioning Profile 생성 (App Store, Push 포함) [5] xcodebuild archive + export (API Key 인증) [6] xcrun altool로 TestFlight 업로드 1. Distribution Certificate Apple Developer → Certificates → + → Apple Distribution 선택. ...

2025-06-18 · 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
Google Oauth Keeps

Flutter 앱 Google OAuth 동의 화면 인증 셋업 정리

Flutter 앱에 Google 로그인을 붙이면서 OAuth 동의 화면 인증까지 진행한 과정을 정리한다. Firebase 없이 Google Cloud Console에서 직접 OAuth 클라이언트 ID를 발급받아 연동하는 경우, 동의 화면 설정과 인증 제출 과정에서 예상치 못한 에러가 자주 발생한다. 실제로 겪은 삽질 위주로 기록한다. 전체 흐름 요약 Google Cloud Console에서 OAuth 2.0 클라이언트 ID 생성 (iOS 타입) 동의 화면 브랜딩 설정 앱 도메인 및 개인정보처리방침 URL 등록 필요한 범위(scope) 설정 인증 제출 및 프로덕션 전환 브랜딩 설정 Google Cloud Console → API 및 서비스 → OAuth 동의 화면 → 브랜딩 에서 아래 항목을 입력한다. ...

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