Skip to main content

Quickstarter

아래 repository에서 예시 코드를 바로 확인해보실 수 있습니다.

iOS Cashback Web Objective-c

실제로 예시 코드 앱을 실행해보시려면, 앱의 bundle ID를 사용하실 프로젝트에 등록해주시기 바랍니다.

사전 준비

Getting Started > iOS Setup 을 먼저 완료하세요.

단계별 가이드

1. 캐시백 웹 엔드포인트 & 쿼리 파라미터 확인하기

기본 URL

  • https://cashback-ui.moment.fairytech.ai/main

지원되는 쿼리 파라미터

redirect_to: 캐시백 웹 내에서 리다이렉트 될 페이지의 경로이며 아래와 같은 페이지들을 지원합니다.
아래 경로들을 반드시 인코딩 후 쿼리 파라미터로 전달해주셔야 합니다
페이지경로전체 url
메인 페이지/cashback?category=뷰티https://cashback-ui.moment.fairytech.ai/main?redirect_to=%2Fcashback%3Fcategory%3D%EB%B7%B0%ED%8B%B0
캐시백 프로그램/cashback/detail?business_id=11sthttps://cashback-ui.moment.fairytech.ai/main?redirect_to=%2Fcashback%2Fdetail%3Fbusiness_id%3D11st
사용자 실적 내역/cashback/transactionshttps://cashback-ui.moment.fairytech.ai/main?redirect_to=%2Fcashback%2Ftransactions
설정/settingshttps://cashback-ui.moment.fairytech.ai/main?redirect_to=%2Fsettings
CS 문의 접수/cshttps://cashback-ui.moment.fairytech.ai/main?redirect_to=%2Fcs
지원되는 business_id 리스트가 필요하신 경우, eng@fairytech.ai로 연락주시기 바랍니다.

2. 웹뷰 설정하기

앱 내에서 웹뷰로 캐시백 웹을 안전하게 로드하고, 네이티브–웹 간 통신을 원활히 하기 위한 필수 설정을 안내합니다.

1) 기본 설정

- (**void**)setupWebView {
    WKWebViewConfiguration *config = [WKWebViewConfiguration new];

    // 1) JS 팝업/새 창 허용
    WKPreferences *prefs = [WKPreferences new];
    prefs.javaScriptCanOpenWindowsAutomatically = **YES**;
    config.preferences = prefs;

    // 2) 페이지 내 JS 실행 허용
    config.defaultWebpagePreferences.allowsContentJavaScript = **YES**;

    // 3) DOM storage 활성화
    config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];

    // 4) 쿠키 동기화(iOS13 이하 호환 예시)
    // iOS13 이하:
    **for** (NSHTTPCookie *cookie **in** [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
        [config.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:**nil**];
    }
}

2) 외부 링크 처리

- (nullable WKWebView *)webView:(WKWebView *)webView
       createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
                   forNavigationAction:(WKNavigationAction *)navigationAction
                        windowFeatures:(WKWindowFeatures *)windowFeatures
{
    NSURL *url = navigationAction.request.URL;
    if ([url.host containsString:FAIRY_CASHBACK_DOMAIN]) {
        // 내부 도메인: WebView에서 처리
        return nil;
    }
    // 외부 도메인: 시스템 브라우저로 오픈
    [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
    return nil;
}
  • 🤔 왜 외부 링크를 따로 처리해야 하나요?
    • 고객사 앱 안에 다른 외부 링크(광고, 파트너 페이지 등)가 포함될 수 있습니다.
    • 외부 링크를 WebView에서 그대로 열면, 원치 않는 도메인에서 JS·쿠키를 공유하거나 피싱 위험이 있습니다.
    • 따라서 우리 도메인만 WebView에서 렌더링하고, 나머지는 반드시 시스템 브라우저로 오픈하여 도메인 경계를 명확히 합니다.

3. JavaScript Interface 구현하기 (fairyCashbackBridge)

아래의 두 가지 bridge api를 반드시 구현해주셔야 합니다.
- (void)setupWebView {
    WKWebViewConfiguration *config = [WKWebViewConfiguration new];

    ...
    // JS 브릿지 스크립트 주입
    NSString *js = @"window.fairyCashbackBridge = {"
                    "finish: function() { window.webkit.messageHandlers.finish.postMessage(null); },"
                    "reload: function(redirectTo) { window.webkit.messageHandlers.reload.postMessage({redirectTo: redirectTo}); }"
                   "};";
    WKUserScript *bridgeScript = [[WKUserScript alloc]
        initWithSource:js
        injectionTime:WKUserScriptInjectionTimeAtDocumentStart
        forMainFrameOnly:NO];
    WKUserContentController *uc = [WKUserContentController new];
    [uc addUserScript:bridgeScript];
    [uc addScriptMessageHandler:self name:@"finish"];
    [uc addScriptMessageHandler:self name:@"reload"];
    config.userContentController = uc;

    ...
}

- (void)loadPage {
    // URL 구성
    NSURLComponents *comps = [NSURLComponents new];
    comps.scheme = @"https";
    comps.host   = FAIRY_CASHBACK_DOMAIN;
    comps.path   = FAIRY_CASHBACK_PATH;
    if (self.redirectTo) {
        comps.queryItems = @[
            [NSURLQueryItem queryItemWithName:@"redirect_to" value:self.redirectTo]
        ];
    }
    NSURL *url = comps.URL;
    if (!url) return;

    // 요청 헤더 설정
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
    [req setValue:self.userId    forHTTPHeaderField:@"x-moment-user-id"];
    [req setValue:self.projectId forHTTPHeaderField:@"x-moment-project-id"];
    [req setValue:self.apiKey     forHTTPHeaderField:@"x-moment-web-api-key"];
    [req setValue:@"IOS"         forHTTPHeaderField:@"x-moment-platform"];

    [self.webView loadRequest:req];
}

- (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message
{
    if ([message.name isEqualToString:@"finish"]) {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    else if ([message.name isEqualToString:@"reload"]) {
        NSString *newRedirect = message.body[@"redirectTo"];
        self.redirectTo = newRedirect;
        [self loadPage];
    }
}
  • 🤔 왜 reload(redirectTo: String)를 구현해야 하나요?
    redirectTo는 encoding되지 않은 값이 전달되므로, 인코딩 해서 redirect_to 쿼리 파라미터로 전달해주셔야 합니다.
    • 웹에는 보안상 API 키를 저장하지 않기 때문에, 토큰 재발급은 네이티브 앱을 통해서만 가능합니다.
    • 또한 이 과정에서 redirectTo를 함께 넘겨주면, 웹 쪽에서 페이지가 리로드된 것을 인지할 수 있기 때문에 “세션이 만료되어 페이지를 리로드했습니다”라는 안내를 사용자에게 정확히 노출할 수 있습니다.
    • 이를 지원하기 위해, 웹에서 fairyCashbackBridge.reload(redirectTo)를 호출하면 전달받은 redirectTo를 redirect_to 쿼리 파라미터로 추가해서 웹뷰를 리로드해주셔야 합니다.
  • 🤔 왜 finish를 구현해야 하나요?
    • WebView 내부에 더 이상 뒤로 갈 페이지가 없을 때, 웹 UI의 ‘뒤로 가기’ 버튼을 누르면 앱의 이전 화면으로 돌아가야 합니다.
    • 이를 지원하기 위해, 웹에서 fairyCashbackBridge.finish()를 호출하면 웹뷰가 종료될 수 있도록 finish()를 구현해주셔야 합니다.

4. 웹뷰에서 캐시백 웹 url 열기

webView.load(request) 로 페이지를 열 때, 아래 4개의 헤더를 반드시 추가해주셔야 합니다.
헤더 이름설명
x-moment-project-idProject ID (페어리 발급)
x-moment-web-api-keyWeb API Key (페어리 발급)
x-moment-user-id캐시백 사용자 식별
x-moment-platformIOS (호출 플랫폼 구분)
- (void)loadPage {
    // URL 구성
    NSURLComponents *comps = [NSURLComponents new];
    comps.scheme = @"https";
    comps.host   = FAIRY_CASHBACK_DOMAIN;
    comps.path   = FAIRY_CASHBACK_PATH;
    if (self.redirectTo) {
        comps.queryItems = @[
            [NSURLQueryItem queryItemWithName:@"redirect_to" value:self.redirectTo]
        ];
    }
    NSURL *url = comps.URL;
    if (!url) return;

    // 요청 헤더 설정
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
    [req setValue:self.userId    forHTTPHeaderField:@"x-moment-user-id"];
    [req setValue:self.projectId forHTTPHeaderField:@"x-moment-project-id"];
    [req setValue:self.apiKey     forHTTPHeaderField:@"x-moment-web-api-key"];
    [req setValue:@"IOS"         forHTTPHeaderField:@"x-moment-platform"];

    [self.webView loadRequest:req];
}

다음 단계

캐시백 서비스 추가 활용 가이드

캐시백 웹내 특정페이지로 바로가기

캐시백 프로그램 목록을 외부에서 노출하기