# React Native API

React Native SDK의 주요 API와 사용법을 설명합니다.

***

## AdchainSdk 모듈

### SDK 초기화

앱이 시작되면 가장 먼저 `initialize()`를 호출해야 합니다. 이 메서드는 네이티브 모듈을 활성화하고 애드체인 서버와 연결을 설정합니다.

```typescript
import { AdchainSdk } from '@1selfworld/adchain-sdk-core-react-native';

await AdchainSdk.initialize({
  appKey: 'your-app-key',
  appSecret: 'your-app-secret',
  environment: 'PRODUCTION'  // 또는 'STAGING', 'DEVELOPMENT'
});
```

**설정 옵션**:

```typescript
interface AdchainConfig {
  appKey: string;        // 필수: AdChain 대시보드에서 발급
  appSecret: string;     // 필수: AdChain 대시보드에서 발급
  environment?: 'PRODUCTION' | 'STAGING' | 'DEVELOPMENT';  // 선택: 기본값 'PRODUCTION'
  timeout?: number;      // 선택: 네트워크 타임아웃 (ms)
}
```

초기화는 앱 시작 시 한 번만 수행합니다. `App.tsx`의 `useEffect`에서 호출하거나, 사용자가 특정 화면에 진입할 때 호출할 수 있습니다.

***

### 사용자 로그인

오퍼월을 사용하려면 먼저 사용자를 로그인시켜야 합니다. 앱의 사용자 ID를 AdChain에 전달하면, 애드체인 서버에서 세션을 생성합니다.

```typescript
await AdchainSdk.login({
  userId: 'user-12345',
  gender: 'MALE',      // 선택 (권장)
  birthYear: 1990      // 선택 (권장)
});
```

**사용자 정보**:

```typescript
interface AdchainUser {
  userId: string;                                          // 필수: 앱의 고유 사용자 ID
  gender?: 'MALE' | 'FEMALE' | 'OTHER' | 'M' | 'F';     // 선택
  birthYear?: number;                                      // 선택 (예: 1990)
}
```

userId는 필수이고, gender와 birthYear는 선택사항입니다. 다만 성별과 출생연도를 제공하면 광고 타겟팅 정확도가 높아지므로 가급적 포함하는 게 좋습니다.

**주의**: userId는 빈 문자열이면 안 됩니다. 앱 로그아웃 후 다른 사용자로 전환할 때는 반드시 `logout()` 후 `login()`을 호출하세요.

***

### 로그아웃

```typescript
await AdchainSdk.logout();
```

현재 로그인된 사용자의 세션을 종료합니다. 로그아웃 후에는 오퍼월을 사용할 수 없습니다.

***

### 오퍼월 열기

전체 화면 방식으로 오퍼월을 표시합니다. 새로운 Activity(Android) 또는 ViewController(iOS)가 생성됩니다.

```typescript
await AdchainSdk.openOfferwall('main_tab');
```

`placementId`는 오퍼월이 어디에서 호출되었는지 식별하는 문자열입니다. 애드체인 팀과 사전 협의하여 정의하며, 이 값에 따라 다른 URL이 로드될 수 있습니다.

**placementId 예시**:

* `"main_tab"` - 메인 탭
* `"profile_section"` - 프로필 섹션
* `"popup_event"` - 팝업 이벤트
* `"banner_promo"` - 배너 프로모션

> 전체 화면 오퍼월(`openOfferwall`)은 커스텀 이벤트 콜백을 지원하지 않습니다. WebView ↔ 앱 양방향 통신이 필요하면 `<AdchainOfferwallView>` 임베디드 컴포넌트의 `onCustomEvent` / `onDataRequest` props를 사용하세요. 자세한 내용은 [임베디드 오퍼월 통합](/undefined-5/embedded-offerwall-integration.md)을 참고하세요.

***

### 외부 브라우저로 URL 열기

```typescript
await AdchainSdk.openExternalBrowser(url: string, placementId?: string): Promise<SuccessResponse>
```

시스템 기본 브라우저로 URL을 엽니다. 앱 내 WebView가 아닌 외부 브라우저로 연결이 필요할 때 사용합니다.

***

### 퀴즈 목록 조회

```typescript
const quizResponse = await AdchainSdk.loadQuizList(unitId: string): Promise<QuizResponse>
```

주어진 `unitId`에 해당하는 퀴즈 목록을 가져옵니다. 자세한 사용법은 [퀴즈 가이드](/undefined-2/quiz.md)를 참고하세요.

***

### 미션 목록 조회

```typescript
const missionResponse = await AdchainSdk.loadMissionList(unitId: string): Promise<MissionListResponse>
```

주어진 `unitId`에 해당하는 미션 목록을 가져옵니다. 자세한 사용법은 [미션 가이드](/undefined-2/mission.md)를 참고하세요.

***

### 상태 확인 메서드

SDK와 사용자의 현재 상태를 확인합니다.

```typescript
// SDK 초기화 여부
const isReady = await AdchainSdk.isInitialized();
if (!isReady) {
  console.log('SDK가 아직 초기화되지 않았습니다');
}

// 로그인 여부
const loggedIn = await AdchainSdk.isLoggedIn();
if (!loggedIn) {
  console.log('로그인이 필요합니다');
}

// 현재 로그인된 사용자 정보
const user = await AdchainSdk.getCurrentUser();
console.log('사용자:', user);  // null이면 로그아웃 상태
```

***

### 기타 메서드

```typescript
// 커스텀 URL로 오퍼월 열기 (고급)
await AdchainSdk.openOfferwallWithUrl('https://...', 'custom_placement');

// 사용자 ID 조회
const userId = await AdchainSdk.getUserId();

// 광고 식별자(IFA) 조회
const ifa = await AdchainSdk.getIFA();

// 배너 정보 조회
const bannerInfo = await AdchainSdk.getBannerInfo(placementId);
```

***

## AdchainOfferwallView 컴포넌트

앱 화면 내부에 임베디드 방식으로 오퍼월을 표시합니다. 탭, 섹션, 프래그먼트 등에 통합할 수 있습니다.

### 기본 사용법

```typescript
import { AdchainOfferwallView } from '@1selfworld/adchain-sdk-core-react-native';

<AdchainOfferwallView
  style={{ flex: 1 }}
  placementId="benefits_tab"
  onOfferwallOpened={() => console.log('오퍼월 로드 완료')}
  onOfferwallError={(error: string) => console.error('오류:', error)}
/>
```

### Props

```typescript
interface AdchainOfferwallViewProps {
  placementId: string;                                          // 오퍼월 식별자 (애드체인 팀과 협의) — 필수
  style?: ViewStyle;                                            // 레이아웃 스타일
  onOfferwallOpened?: () => void;                               // WebView 로드 완료 시
  onOfferwallClosed?: () => void;                               // 오퍼월 닫힘 시
  onOfferwallError?: (error: string) => void;                   // 로딩 실패 시
  onRewardEarned?: (amount: number) => void;                    // 리워드 획득 시
  onCustomEvent?: (eventType: string, payload: any) => void;    // WebView → Native 이벤트
  onDataRequest?: (requestType: string, params: any) => any;    // WebView → Native 데이터 요청
  onBackPressOnFirstPage?: () => void;                          // Android: 첫 페이지에서 백버튼
  onBackNavigated?: () => void;                                 // Android: WebView 뒤로가기 성공
}
```

### WebView ↔ Native 통신

`onCustomEvent`와 `onDataRequest`를 사용하면 WebView와 Native 간 양방향 통신이 가능합니다.

**onCustomEvent** - WebView에서 발생한 이벤트를 Native로 전달:

```typescript
<AdchainOfferwallView
  placementId="main_tab"
  onCustomEvent={(eventType, payload) => {
    console.log('WebView 이벤트:', eventType, payload);

    // 실제 이벤트는 애드체인 팀과 사전 협의하여 정의
    if (eventType === 'navigate') {
      navigation.navigate(payload.screen, payload.params);
    }
  }}
/>
```

**onDataRequest** - WebView가 Native에 데이터를 요청:

```typescript
<AdchainOfferwallView
  placementId="main_tab"
  onDataRequest={(requestType, params) => {
    if (requestType === 'user_points') {
      return { points: 12345, currency: 'KRW' };
    }
    else if (requestType === 'user_profile') {
      return { userId: 'user-123', nickname: 'Player1', level: 42 };
    }
    return null;
  }}
/>
```

**onRewardEarned** - 사용자가 리워드를 획득했을 때:

```typescript
<AdchainOfferwallView
  placementId="main_tab"
  onRewardEarned={(amount) => {
    console.log('리워드 획득:', amount);
    refreshUserPoints();
  }}
/>
```

**onOfferwallClosed** - 오퍼월이 닫혔을 때:

```typescript
<AdchainOfferwallView
  placementId="main_tab"
  onOfferwallClosed={() => {
    console.log('오퍼월 닫힘');
    refreshUI();
  }}
/>
```

**실전 팁**: 이벤트와 데이터 요청 타입은 애드체인 팀과 사전 협의하여 정의합니다. 위 예시는 참고용입니다.

***

### Android 백버튼 처리

Android에서는 하드웨어 백버튼을 직접 처리해야 합니다. 그렇지 않으면 WebView 내부 네비게이션을 무시하고 앱이 종료됩니다.

```typescript
import { BackHandler, findNodeHandle, UIManager } from 'react-native';

const offerwallViewRef = useRef(null);

useEffect(() => {
  const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
    if (offerwallViewRef.current) {
      const viewId = findNodeHandle(offerwallViewRef.current);
      if (viewId) {
        UIManager.dispatchViewManagerCommand(viewId, 'handleBackPress', []);
        return true;  // 앱 종료 방지
      }
    }
    return false;
  });

  return () => backHandler.remove();
}, []);

<AdchainOfferwallView
  ref={offerwallViewRef}
  placementId="main_tab"
  style={{ flex: 1 }}
/>
```

더 자세한 Android 백버튼 처리 방법은 각 고객사 통합 가이드를 참고하세요.

***

## 타입 정의

### AdchainConfig

```typescript
interface AdchainConfig {
  appKey: string;
  appSecret: string;
  environment?: 'PRODUCTION' | 'STAGING' | 'DEVELOPMENT';
  timeout?: number;
}
```

### AdchainUser

```typescript
interface AdchainUser {
  userId: string;
  gender?: 'MALE' | 'FEMALE' | 'OTHER' | 'M' | 'F';
  birthYear?: number;
}
```

### Quiz

```typescript
interface Quiz {
  id: string;
  title: string;
  description: string;
  imageUrl: string;
  reward: number;
  isCompleted: boolean;
}
```

### QuizResponse

```typescript
interface QuizResponse {
  success: boolean;
  titleText?: string;
  completedImageUrl?: string;
  completedImageWidth?: number;
  completedImageHeight?: number;
  events: Quiz[];
  message?: string;
}
```

### Mission

```typescript
interface Mission {
  id: string;
  title: string;
  description: string;
  imageUrl: string;
  reward: number;
  isCompleted: boolean;
  type: string;
  actionUrl: string;
}
```

### MissionListResponse

```typescript
interface MissionListResponse {
  missions: Mission[];
  completedCount: number;
  totalCount: number;
  canClaimReward: boolean;
}
```

***

## 에러 처리

SDK 메서드는 실패 시 예외를 던집니다. try-catch로 처리하세요.

```typescript
try {
  await AdchainSdk.initialize(config);
  console.log('초기화 성공');
} catch (error) {
  if (error instanceof Error) {
    console.error('초기화 실패:', error.message);
    Alert.alert('오류', '네트워크 연결을 확인하거나 설정을 점검하세요');
  }
}
```

**에러 케이스**:

* `SDK_NOT_INITIALIZED` - 초기화 전에 다른 메서드 호출
* `INVALID_CREDENTIALS` - appKey 또는 appSecret이 잘못됨
* `NETWORK_ERROR` - 서버 연결 실패
* `NOT_LOGGED_IN` - 로그인 전에 오퍼월 호출

***

## TypeScript 지원

SDK는 TypeScript 타입 정의를 포함하고 있어서 별도 `@types` 패키지가 필요 없습니다. IDE에서 자동완성과 타입 체크가 지원됩니다.

***

## 다음 단계

* [시작하기](/undefined/react-native.md)
* [문제 해결](/undefined-6/common-issues.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://adchain-doc.1self.world/api/react-native.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
