반응형

 

App Store에 심사를 올렸다가 거부를 당했다.

많은 이유 중 하나가 나를 아주 불지옥에서 불타게 했는데, 그건 바로 kakao로그인...

App Store에서 요구하는 바는 kakao로그인을 할 때 외부링크를 통해 브라우저로 로그인 하는 것은 유저 경험에 부정적인 영향을 미친다는 것이다.

그리고 난 그 문제를 해결하다가 유저가 아니라 내가 미칠뻔했다...

왜냐하면 난 Supabase를 통해 로그인을 구현한 상태였고, 그 Auth와 kakao의 Auth를 따로 관리하는 것은 말이 안되는 일이었기 때문에 kakao와 Supabase의 인증을 내가 따로 해야하는 상황이었다.

그래서 찾고 찾다가,

https://miryang.dev/blog/how-to-use-kakao-login-js-sdk-with-supabase

 

Supabase에서 Kakao Login JS SDK를 사용하는 방법

Supabase에서 Kakao OIDC를 사용해서 카카오 로그인하기 | 미량의 개발 블로그, miryang.dev

miryang.dev

위의 블로그 글을 발견하고 드디어 해결할 수 있겠다는 희망을 품고 문제를 해결해보려 하였으나, 실패했다.

왜냐?

나는 api관련 지식 레벨이 허접이라서 key를 잘 몰랐기 때문이다.

위 글을 참조하면 카카오에서 인증 code를 받고 그 code를 supabase로 전달하고 인증을 받는 형태인것 같은데, 난 계속 에러가 났다.

에러 메세지는

AuthException (AuthException(message: Code verifier could not be found in local storage., statusCode: null, errorCode: null))

위와 같다.

 

아니, 나는 분명히 님들이 요구하는 key를 잘 맞춰서 전달하고 있다구요?! 하며 별에 별 방법을 다 써본지 약 3일차...

나의 갓갓 남편님이 해결책을 발견해주었다.

위의 이미지는 카카오에서 알려주는 key에 대한 정보인데, 여기에서 보면 분명히 'REST API'키가 있다.

 

여기는 Supabase의 세팅인데 여기도 분명히 REST API Key라고 똑똑히 적혀있다.

그래서 난 철썩같이 이 둘을 믿었기에 카카오의 REST API Key를 Supabase에게 설정하고 전달하고 있었다.

하 지 만 !

내 믿음은 철저히 배신당했고 사실 저 REST API Key의 자리엔 네이티브 앱 키가 들어가야했다.

왜냐?

난 Flutter로 개발하고 있고 모바일이니까.

ㅋㅋㅋㅋㅋㅋ.... 왜, 왜 저따위(?)로 적혀있어서 사람을 이렇게 고통받게 한건지...

심지어 관련된 문서도 없고 설명도 없고 정보도 없었다. (LLM도 잘 모르더라...그럴 수 밖에 없지만)

물론 api와 key, 네트워크관련해서 좀 치는 사람이면 금방 해결할 수 있을 수도 있지만, 난 아니었다.

게다가 난 항상 공식문서를 잘 따라하는게 가장 좋은 방법이라고 믿었기 때문에 그저 따르기만 했다.

그렇게 내 3일은 증발했고 내 스트레스 수치는 임계점을 돌파했다.

혹시나 Flutter로 개발을 하는데 kakao 로그인 - Supabase 로그인 관련 문제에서 고통 받는 사람이 있다면 이 글이 도움이 되면 좋겠다.

반응형
반응형

Flutter로 개발을 하다보면 State관리에서 여러가지 도구들을 보게된다.

그런데 개인적으로 Provider과 Consumer, FutureBuilder이 헷갈려서 정리해보는 글이다.

LLM최고

 

1. Provider

- 상태 관리 솔루션의 기본 클래스
- 데이터를 앱의 위젯 트리 전체에 제공하는 역할
- 주로 ChangeNotifier와 함께 사용됨

2. Consumer

- Provider에서 제공하는 데이터를 사용하는 위젯
- Provider의 데이터가 변경될 때 자동으로 rebuild됨
- 위젯 트리의 특정 부분만 업데이트할 때 유용

3. FutureBuilder

- 비동기 데이터를 처리하기 위한 위젯
- Future의 상태에 따라 다른 UI를 표시
- API 호출, 데이터베이스 작업 등에 사용

 

주요 차이점:

1. 용도

- Provider: 전역 상태 관리
- Consumer: Provider 데이터 사용 및 UI 업데이트
- FutureBuilder: 비동기 데이터 처리

2. 데이터 유형

- Provider: 모든 타입의 데이터
- Consumer: Provider가 제공하는 데이터
- FutureBuilder: Future 객체

3. 업데이트 방식

- Provider: 데이터 변경 알림
- Consumer: Provider 변경 시 자동 rebuild
- FutureBuilder: Future 완료 시 UI 업데이트

 

위의 문제들이 문제가 된 경우는 주로 'Provider을 어디서 뿌리는지'와 Consumer을 사용하지 않을 경우, Provider에서 notify를 호출해도 왜 UI가 rebuild되지 않는지 등의 문제를 겪다가 개념에 대한 정리가 필요해서 알아봤다.

게다가 최근 Cashed Query를 사용하다 보니 더욱 복잡해져서 헷갈리는 상황이다.

아무튼, 최대한 이해를 열심히 해서 잘 사용해야겠다.

반응형
반응형

 

Flutter로 개발을 하다보면 아무래도 프론트엔드 언어라서 그런지 에러핸들링이 미묘하다.

특히, 타입과 관련된 경우 더욱 그렇다!

그래서 나름 신중하게 코드를 짠다고 해도 나중에 테스트를 하다보면 꼭 타입관련 오류가 나는편이다..

하지만 모든 타입마다 하나하나 모델을 따로 만들어주는 것은 여간 번거로운 일이 아닌데, 우연히 알게 된 라이브러리가 아주 좋아서 포스팅해본다.

https://github.com/mmvergara/supadart

 

GitHub - mmvergara/supadart: Typesafe queries in Supabase Flutter! Generate Flutter / Dart 🎯 classes from your Supabase schem

Typesafe queries in Supabase Flutter! Generate Flutter / Dart 🎯 classes from your Supabase schema. - mmvergara/supadart

github.com

 

위 링크를 통해서 파일을 생성해주면 연관 된 Supabase의 테이블을 보고 Type을 토대로 한 모델을 생성해준다.

예전에 이 라이브러리를 몰라서 그냥 ts파일을 받아서 LLM으로 만들었었는데...

그런 경우 역시 업데이트에 바로바로 대응하는게 힘들어서 이 방법이 훨씬 효율적인듯 하다.

앞으로도 애용할 예정!

반응형
반응형

코드를 작성하다 보면 가끔 타입에 대해 신뢰가 가지 않는 경우가 종종있다.

최근에는 Edge-function에 Supabase의 DB에 있는 타입을 활용해야할 때 그랬는데, 간단한 명령어로 현재 설정되어 있는 DB의 데이터 타입들을 가져올 수 있었다.

supabase gen types typescript --project-id "[your project id]" --schema public > supabase.ts

 

 

위의 명령어를 활용하여 내 프로젝트에서 supabase의 type들을 받아올 수 있다.

supabase의 타입들이 해당 파일에 입력된다.

 

이렇게 입력 된 타입들은 아래의 예시와 같다.

이 타입들은 edge-function에서 활용할 수 있다.

import { Database } from "../supabase.ts";
.
.
  const sourceArticles: Database["public"]["Tables"]["table name"]["Insert"][] =
    data.map((element) => {
      return {
        .
        .
        .
      };
    });

이런식으로 타입을 활용하면 DB에 insert혹은 update등 여러가지 작업을 할 때 타입이 맞지않아 문제가 생기는 것을 사전에 방지할 수 있다.

 

조금 번거로운 점은 DB의 구조를 바꿀 때마다 가장 상단의 명령어를 통해서 타입을 불러와줘야한다는 것 인데, 그 번거로움을 감안하고도 나머지 장점이 큰것 같다.

 

 

Generating TypeScript Types | Supabase Docs

How to generate types for your API and Supabase libraries.

supabase.com

 

 

반응형
반응형

Supabase로 작업을 하던 중에 일정한 시간마다 Edge-function을 호출해야하는 상황이 발생했다.

그래서 확인해보니 아주 유용한 확장을 제공하고 있어서 해당 확장들을 활용했고 결과는 성공적이었다.

 

Supabase Edge-function 스케쥴링하기

 

1. Supabase의 사이드 바에서 Database > Extensions로 이동한다.

2. 검색창에서 pg_net을 검색하고 활성화해준다.

💭 pg_cron을 활용하기 위해서는 먼저 net을 활성화해서 http호출을 가능하도록 해줘야 한다.

3. 위와 동일하게 cron을 검색하고 활성화해준다.

4. Supabase의 사이드 바에서 SQL Editor로 이동한 후 아래의 쿼리를 입력한다.

select
cron.schedule(
'invoke-your-edge-function', -- name of cron
'0 11 * * *', -- every day at 11:00
$$
select
net.http_post(
url:='https://project-ref.supabase.co/functions/v1/[your-edge-funtion-name]', -- your edge function
headers:='{"Content-Type": "application/json", "Authorization": "Bearer [your anon key]"}'::jsonb,
body:=concat('{"time": "', now(), '"}')::jsonb
) as request_id;
$$
);

위의 쿼리 중 몇가지 직접 설정 및 입력해줘야하는 값들이 있다.

 

- 'invoke-your-edge-function', -- name of cron:

말 그대로 이 cron 스케쥴에 대한 이름이 될 값.

 

- '0 11 * * *', -- every day at 11:00:

이 값은 주로 코드를 통해 스케쥴을 설정할 때 사용하게 되는데, 헷갈리는 경우가 많아 guru를 통해서 설정하길 추천한다.

guru링크 👉 https://crontab.guru/#*_*_*_*_*

 

Crontab.guru - The cron schedule expression generator

loading... We created Cronitor because cron itself can't alert you if your jobs fail or never start. Cronitor is easy to integrate and provides you with instant alerts when things go wrong. Sign Up Free

crontab.guru

위의 사이트를 활용하면 cron스케쥴을 설정하기 위한 시간을 쉽게 수정하고 확인 및 적용이 가능하다.

위의 이미지는 매 분 마다 실행됨을 의미

 

- url:='https://project-ref.supabase.co/functions/v1/[your-edge-funtion-name]', -- your edge function:

실제 edge function을 호출하는 url

 

- headers:='{"Content-Type": "application/json", "Authorization": "Bearer [your anon key]"}'::jsonb,:

여기서는 다른값은 수정하지 않고 [your anon key]만 바꿔주면 되는데, Supabase의 사이드 바의 Project Setting > API에서 찾을 수도 있고 다른 곳에서도 찾을 수 있다.

 

5. 여기까지 완료했다면 Table의 cron Schema에서 생성 된 스케쥴을 확인할 수 있다.

 

생성 된 스케쥴은 설정 된 시간에 실행되고 결과는 job_run_details에 기록된다.

만약 생성 된 스케쥴을 취소하고 싶다면 아래의 쿼리를 활용할 수 있다.

select cron.unschedule('name of cron');

 

참고로 cron schema의 값들은 read only라서 직접 UI로 수정 및 삭제가 불가능하다.

그래서 변화를 주고 싶다면 위와같이 쿼리를 통해서만 가능하다.

 

Supabase pg_cron docs

https://supabase.com/docs/guides/database/extensions/pg_cron

 

pg_cron: Job Scheduling | Supabase Docs

pgnet: a simple cron-based job scheduler for PostgreSQL that runs inside the database.

supabase.com

 

 

반응형
반응형

RxSwift - BehaviorSubject

 

BehaviorSubject는 Subject중 하나로, 최초 구독을 당하는 시점에 이전에 방출 된 값이 없다면 BehaviorSubject의 초기값을 방출하고 이미 방출 된 값이 있다면 최근의 값을 방출하는 Subject이다.

// 3이란 초기값을 가진 BehaviorSubject를 생성
let behaviorSubject = BehaviorSubject(value: 3)
	// 처음으로 구독하는 observer는 3의 값을 방출
    behaviorSubject.subscribe { value in
        print("First subscriber gets value: \(value)")
    }
    // 10의 값을 방출
    behaviorSubject.onNext(10)
    print("BehaviorSubject has already sent 10!")
    // 두번째로 구독하는 observer는 가장 최근의 값인 10을 방출 함
    behaviorSubject.subscribe { value in
        print("Second subscriber gets value: \(value)")
    }
    // 두개의 observer가 75를 동시에 방출
    behaviorSubject.onNext(75)

 

실행 결과

First subscriber gets value: next(3)
First subscriber gets value: next(10)
BehaviorSubject has already sent 10!
Second subscriber gets value: next(10)
First subscriber gets value: next(75)
Second subscriber gets value: next(75)

 

추가적으로, 중간에 만약 Error가 방출된다면 그 후 observer에겐 계속 Error를 전달하게 된다.

반응형

'iOS > Swift' 카테고리의 다른 글

[Swfit] Swift는 무엇일까?  (1) 2023.02.24
반응형

Custom NavigationBar : 네비게이션 바 제목에 이미지 넣기

let logo = UIImageView(image: UIImage(named: "logo.jpeg"))

        logo.contentMode = .scaleAspectFit
        logo.widthAnchor.constraint(equalToConstant: 120).isActive = true
        logo.heightAnchor.constraint(equalToConstant: 50).isActive = true

        navigationItem.titleView = logo

🕶️ 코드 설명 :

1. logo라는 이름의 UIImageView를 생성(logo.jpeg라는 파일을 기준으로 UIImage를 생성해서 인자로 사용)

2. 생성 된 logo에 contentMode를 .scaleAspectFit (이미지의 외곡 없이 크기에 맞게 설정 됨)으로 설정

3. Anchor로 width 120, height 50으로 설정

4. navigationItem의 titleView에 logo를 대입

반응형
반응형

Custom NavigationBar : 네비게이션 바에 직접 만든 버튼 넣기

  let btn = UIButton()
        btn.backgroundColor = .orange
        btn.setTitle("testButton", for: .normal)
        btn.widthAnchor.constraint(equalToConstant: 120).isActive = true
        btn.heightAnchor.constraint(equalToConstant: 40).isActive = true
        
        btn.addTarget(self, action: #selector(testAction), for: .touchUpInside)
        
        navigationItem.titleView = btn

🕶️ 코드 설명 :

1. btn이란 이름의 UIButton인스턴스 생성

2. 생성 된 btn버튼에 backgroundColor로 배경색 설정

3. 이어서 setTitle메소드로 버튼의 제목을 "testButton"으로 변경

4. Anchor속성으로 크기를 설정 (width 120, height 40)

5. addTarget으로 버튼에 클릭/터치에 대한 이벤트를 부여

6. 네비게이션아이템에 titleView를 위의 버튼으로 설정

반응형

+ Recent posts