---
url: /react-native-nitro-device-info/ko/api/device-attestation.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# Device attestation API \{#device-attestation-api}
선택 패키지 `react-native-nitro-device-integrity`는 하드웨어 기반 **device attestation** 토큰을 발급합니다. 기기가 보낸 토큰은 서버에서 검증해야 합니다.
v0.1.0부터
이 페이지의 버전 배지는 integrity 패키지를 기준으로 합니다. npm의 [v0.1.0](https://www.npmjs.com/package/react-native-nitro-device-integrity/v/0.1.0)은 [이 소스](https://github.com/l2hyunwoo/react-native-nitro-device-info/tree/react-native-nitro-device-integrity%400.1.0/packages/react-native-nitro-device-integrity)에 해당합니다.
[지원 여부 배지 설명](/react-native-nitro-device-info/ko/api/index.md#availability-badges)을 읽으세요. Pod의 대상은 iOS 14 이상, Android 모듈의 대상은 API 24 이상입니다. 의존성은 더 높은 최소 버전을 요구할 수 있습니다. 웹용 entry point는 없습니다.
- **Android** → [Play Integrity API](https://developer.android.com/google/play/integrity)
- **iOS** → [App Attest(`DCAppAttestService`)](https://developer.apple.com/documentation/devicecheck/dcappattestservice) + [DeviceCheck(`DCDevice`)](https://developer.apple.com/documentation/devicecheck/dcdevice)
핵심 라이브러리와 **별개의 선택 패키지**이므로 device attestation이 필요할 때만 설치하세요. 설치하면 Play Integrity / App Attest 의존성이 추가됩니다. Google Cloud / Apple 콘솔 설정도 필요합니다.
:::tip Device attestation과 로컬 탐지
이 API는 핵심 [기기 무결성 API](/react-native-nitro-device-info/ko/api/device-integrity.md)를 **보완**합니다.
- **로컬 탐지**([`isDeviceCompromised()`](/react-native-nitro-device-info/ko/api/device-integrity.md)): 빠르고 오프라인에서 동작하지만 쉽게 우회할 수 있습니다. 첫 단계 사전 필터로 사용합니다.
- **device attestation**(이 페이지): 플랫폼이 발급한 결과를 **서버에서 검증**합니다.
서버에서 검증한 attestation과 서비스의 다른 위험 신호를 함께 사용해 접근 정책을 적용하세요.
:::
## 토큰 발급과 검증은 누가 담당하나요? \{#the-responsibility-boundary}
:::warning 라이브러리는 토큰만 발급합니다. 검증은 서버에서 해야 합니다
토큰·attestation·assertion 발급 메서드는 **불투명한 값**을 반환합니다. 이 값만으로 기기가 안전한지 판단할 수는 없습니다. 결과를 백엔드로 보내 검증하고 보호할 작업을 허용할지 결정하세요.
:::
| 작업 | 담당 |
| ------------------------------------------ | -------------------------- |
| 기기에서 토큰 / attestation / assertion 발급 | **라이브러리** |
| `clientDataHash`(SHA-256) 계산과 클라이언트 데이터 구성 | 앱 |
| 토큰을 백엔드로 전송 | 앱 |
| 복호화 / 서명 검증 / 판정 해석 | **서버** |
| App Attest `keyId` 저장 | 앱(라이브러리는 `keyId`를 저장하지 않음) |
| Google Cloud / Apple 콘솔 설정 | 개발자 |
## 설치 \{#installation}
```bash
yarn add react-native-nitro-device-integrity react-native-nitro-modules
cd ios && pod install
```
패키지의 네이티브 최소 버전은 iOS 14.0 이상과 Android API 24 이상입니다. Nitro와 React Native 의존성에 따라 높아질 수 있습니다. Play Integrity에는 Google Play Services가 필요합니다. DeviceCheck는 iOS 11부터 있지만 이 패키지는 iOS 11 설치를 지원하지 않습니다.
## API 레퍼런스 \{#api-reference}
```typescript
import { createDeviceIntegrity } from 'react-native-nitro-device-integrity';
const integrity = createDeviceIntegrity();
```
### 사용 가능 여부 \{#availability}
#### `isSupported` \{#issupported}
v0.1.0부터 iOS 14+ Android API 24+ 웹: 미지원
```typescript
readonly isSupported: boolean
```
확인할 수 있는 범위에서 지원 여부를 반환합니다. Android에서는 Google Play Services를 사용할 수 있으면 `true`를 반환합니다. 이 값이 앱의 Play Integrity API 설정 완료를 **보장하지는 않습니다**. iOS에서는 `DCAppAttestService.shared.isSupported`를 사용합니다. 시뮬레이터에서는 항상 `false`입니다.
#### `providerType` \{#providertype}
v0.1.0부터 iOS 14+ Android API 24+ 웹: 미지원
```typescript
readonly providerType: 'playIntegrity' | 'appAttest' | 'unsupported'
```
기기에서 사용하는 provider를 나타냅니다. 플랫폼 전용 메서드를 호출하기 전에 이 값을 확인해 클라이언트 코드를 분기하세요.
***
### Android — Play Integrity \{#android--play-integrity}
#### `prepareStandardProvider()` \{#preparestandardprovider}
v0.1.0부터 iOS: reject Android API 24+ 웹: 미지원
```typescript
prepareStandardProvider(cloudProjectNumber: string): Promise
```
Play Integrity **Standard** 토큰 provider를 준비합니다. 네이티브에서 provider를 캐시하므로 세션마다 한 번 호출하세요. JavaScript 숫자 정밀도 손실을 막기 위해 `cloudProjectNumber`는 문자열로 전달합니다.
프로젝트 번호가 잘못되면 오류 메시지는 `CLOUD_PROJECT_NUMBER_IS_INVALID`로 시작합니다. SDK 오류는 `STANDARD_INTEGRITY_ERROR_<숫자 코드>`로 시작합니다. 예를 들어 네트워크 오류는 `STANDARD_INTEGRITY_ERROR_-3`입니다. iOS에서는 `UNSUPPORTED_PLATFORM`입니다.
#### `requestIntegrityToken()` \{#requestintegritytoken}
v0.1.0부터 iOS: reject Android API 24+ 웹: 미지원
```typescript
requestIntegrityToken(requestHash: string): Promise
```
Standard 토큰을 요청합니다. 먼저 `prepareStandardProvider`를 호출해야 합니다. 캐시한 provider가 만료됐다면(`INTEGRITY_TOKEN_PROVIDER_INVALID`) 자동으로 한 번 다시 준비하고 요청을 재시도합니다.
`requestHash`는 요청의 핵심 매개변수를 SHA-256으로 해시한 base64 값입니다(최대 500바이트). 서버 nonce가 아니며 호출자가 계산합니다. 불투명한 암호화 토큰 문자열을 반환합니다.
#### `requestClassicIntegrityToken()` \{#requestclassicintegritytoken}
v0.1.0부터 iOS: reject Android API 24+ 웹: 미지원
```typescript
requestClassicIntegrityToken(nonce: string, cloudProjectNumber: string): Promise
```
Play Integrity **Classic** 흐름입니다(일회성, 서버 nonce 기반). 자주 검사할 때는 Standard를 우선 사용하세요. `nonce`는 서버가 생성한 일회용 URL-safe base64 값이어야 하며 길이는 16–500바이트입니다.
***
### iOS — App Attest \{#ios--app-attest}
#### `generateKey()` \{#generatekey}
v0.1.0부터 iOS 14+ Android: reject 웹: 미지원
```typescript
generateKey(): Promise
```
Secure Enclave에서 App Attest 키 쌍을 만들고 `keyId`를 반환합니다.
:::warning keyId를 직접 저장하세요
`keyId`는 이 키에 접근하는 유일한 핸들입니다. Keychain 등에 저장하세요. 라이브러리는 `keyId`를 저장하지 않습니다. App Attest 키는 **앱 재설치 후 유지되지 않습니다**. `DCError.invalidKey`가 발생하면 다시 생성하세요.
:::
#### `attestKey()` \{#attestkey}
v0.1.0부터 iOS 14+ Android: reject 웹: 미지원
```typescript
attestKey(keyId: string, clientDataHash: string): Promise
```
키 attestation을 수행하며 Apple에 네트워크 요청을 보냅니다(설치마다 키당 **한 번**). `clientDataHash`는 `SHA-256(server challenge)`의 base64 값이며, 해독한 길이가 정확히 **32바이트**여야 합니다. 라이브러리는 해시를 계산하지 않습니다. 잘못된 base64는 `INVALID_BASE64`, 해독한 길이가 다르면 `INVALID_INPUT`으로 reject됩니다. 이 검사는 iOS 기기 지원 여부보다 먼저 수행합니다. 불투명한 CBOR attestation 객체를 base64로 인코딩해 반환합니다.
#### `generateAssertion()` \{#generateassertion}
v0.1.0부터 iOS 14+ Android: reject 웹: 미지원
```typescript
generateAssertion(keyId: string, clientDataHash: string): Promise
```
후속 요청용 assertion을 오프라인으로 생성합니다. 요청마다 서버에서 새 일회용 challenge를 받아 요청 payload와 함께 구성한 client data를 해시하세요. 32바이트 SHA-256 해시를 base64로 전달하며, `attestKey`와 같은 입력 검사를 적용합니다. 불투명한 CBOR assertion 객체를 base64로 인코딩해 반환합니다. 서버는 발급한 challenge와 단조 증가 카운터를 확인해 재전송 공격을 탐지합니다.
***
### iOS — DeviceCheck \{#ios--devicecheck}
#### `getDeviceCheckToken()` \{#getdevicechecktoken}
v0.1.0부터 iOS 14+ Android: reject 웹: 미지원
```typescript
getDeviceCheckToken(): Promise
```
Apple DeviceCheck 토큰을 생성합니다(기기 수준이며 App Attest보다 가벼움). 서버는 Apple DeviceCheck API로 기기의 2비트 상태를 조회·갱신합니다.
## 오류 \{#errors}
reject 시 `Error.message` 앞부분에 오류 코드를 포함합니다. JavaScript `error.code` 속성은 별도로 보장하지 않습니다.
| 메시지 앞부분 | 의미 |
| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `UNSUPPORTED_PLATFORM` | 다른 플랫폼 전용 메서드를 호출했거나 iOS 하드웨어가 지원하지 않음. |
| `CLOUD_PROJECT_NUMBER_IS_INVALID` | 프로젝트 번호가 양의 부호 있는 64비트 정수 문자열이 아님. |
| `PROVIDER_NOT_PREPARED` | Standard 토큰 요청 전에 `prepareStandardProvider`를 호출해야 함. |
| `STANDARD_INTEGRITY_ERROR_<숫자 코드>` | Standard SDK 오류. Provider 무효화(`-19`)는 한 번 새로 준비하고 재시도하며, 다른 오류는 그대로 반환함. |
| `CLASSIC_INTEGRITY_ERROR_<숫자 코드>` | Classic SDK 오류. 자동 재시도하지 않음. |
| `INVALID_BASE64` | iOS `clientDataHash`가 올바른 base64가 아님. |
| `INVALID_INPUT` | 해독한 iOS 해시가 32바이트가 아니거나 Apple이 잘못된 입력으로 처리함. |
| `INVALID_KEY`, `SERVER_UNAVAILABLE`, `FEATURE_UNSUPPORTED`, `UNKNOWN_SYSTEM_FAILURE`, `UNKNOWN` | Apple DeviceCheck / App Attest 오류를 변환한 코드. 다른 네이티브 오류는 원래 메시지를 유지함. |
SDK 숫자 코드를 `NETWORK_ERROR` 같은 이름으로 변환하지 않고 유지합니다. [Standard SDK 오류 코드](https://developer.android.com/google/play/integrity/reference/com/google/android/play/core/integrity/model/StandardIntegrityErrorCode)를 참고하세요. reject를 처리하고 이를 신뢰할 수 있는 판정으로 간주하지 마세요.
## 사용법 \{#usage}
```typescript
import { createDeviceIntegrity } from 'react-native-nitro-device-integrity';
const integrity = createDeviceIntegrity();
if (integrity.providerType === 'playIntegrity') {
// Android
await integrity.prepareStandardProvider('123456789012'); // once
const requestHash = base64Sha256('checkout:item-42'); // your request params
const token = await integrity.requestIntegrityToken(requestHash);
await postToYourServer({ token }); // server verifies
} else if (integrity.providerType === 'appAttest') {
// iOS
const keyId = await integrity.generateKey(); // persist this
const clientDataHash = base64Sha256(serverChallenge);
const attestation = await integrity.attestKey(keyId, clientDataHash); // once
await postToYourServer({ keyId, attestation }); // one-time validation
// ...per request:
const challenge = await fetchChallengeFromYourServer(); // fresh, one-time
const clientData = JSON.stringify({ challenge, payload });
const assertion = await integrity.generateAssertion(keyId, base64Sha256(clientData));
await postToYourServer({ keyId, assertion, clientData });
}
```
예제의 해시 함수와 백엔드 통신 함수는 앱에서 구현해야 합니다. 해시한 `clientData` 문자열을 그대로 보내세요. 서버는 같은 바이트로 서명을 검증하고 문자열에 포함된 challenge가 해당 요청에 발급한 값과 일치하는지 확인해야 합니다.
## 서버 검증(개발자 책임) \{#server-verification-your-responsibility}
이 라이브러리는 토큰 발급까지만 담당합니다. 백엔드에서 검증하세요.
### Play Integrity(Android) \{#play-integrity-android}
서버로 토큰을 보낸 뒤 Google의 decode 엔드포인트를 호출하세요(권장).
```http
POST https://playintegrity.googleapis.com/v1/{packageName}:decodeIntegrityToken
```
판정을 확인하기 전에 `requestDetails`를 검증하세요. `requestPackageName`이 예상한 앱과 일치하고 `timestampMillis`가 허용한 유효 기간 안에 있어야 합니다. Standard는 보호할 요청으로 계산한 `requestHash`와, Classic은 서버가 발급한 미사용 `nonce`와 일치하는지 확인하세요. 불일치하거나 만료된 요청은 백엔드에서 거부합니다.
그다음 응답의 판정 값에 서비스 정책을 적용하세요.
- `deviceIntegrity.deviceRecognitionVerdict`에 `MEETS_DEVICE_INTEGRITY` 포함 여부
- `appIntegrity.appRecognitionVerdict === 'PLAY_RECOGNIZED'`
- `deviceRecognitionVerdict`가 비어 있거나 없으면 판정 기준을 충족하지 못한 것입니다. API hooking, 시스템 침해, Google의 검사를 통과하지 못한 에뮬레이터 등이 원인일 수 있습니다.
[Play Integrity 판정](https://developer.android.com/google/play/integrity/verdicts)을 참고하세요.
### App Attest(iOS) \{#app-attest-ios}
1. 키마다 한 번 Apple App Attest Root CA를 기준으로 **attestation**을 검증하세요(인증서 체인, nonce, app-ID 해시, counter = 0). 공개 키와 카운터를 저장하세요.
2. 각 **assertion**을 받으면 client data를 그대로 해시해 저장한 공개 키로 서명을 검증하세요. client data의 challenge가 서버에서 발급한 미사용 값과 일치하는지, 카운터가 이전 값보다 커졌는지 확인하세요.
[서버에 연결하는 앱 검증](https://developer.apple.com/documentation/devicecheck/validating-apps-that-connect-to-your-server)을 참고하세요.
## 필요한 설정 \{#setup-requirements}
### Android(Play Integrity) \{#android-play-integrity}
1. **Google Cloud** 프로젝트를 만들거나 선택하고 Play Integrity API를 켜세요.
2. **Play Console** → _Play Integrity API_에서 연결하세요.
3. **Cloud 프로젝트 번호**를 `prepareStandardProvider` / `requestClassicIntegrityToken`에 전달하세요.
4. 서버에서 Google 서비스 계정 또는 응답 암호화 키를 설정하세요.
### iOS(App Attest / DeviceCheck) \{#ios-app-attest--devicecheck}
1. 앱 타깃에 **App Attest** 기능을 추가하세요(Xcode → Signing & Capabilities). `com.apple.developer.devicecheck.appattest-environment` entitlement를 추가합니다.
2. **소유한 번들 식별자**를 사용하고 Development Team을 설정하세요.
3. DeviceCheck 서버 조회용 `.p8` 키를 Apple Developer 포털에서 만드세요.
:::info 개발자 계정과 앱 타깃 설정이 필요합니다
위 항목은 개발자 계정과 앱 타깃에서 관리합니다. 라이브러리가 대신 설정할 수는 없습니다. 앱 설정을 마친 뒤 토큰을 발급합니다.
:::
## 제한 사항 \{#limitations}
:::warning Device attestation의 범위와 한계
- **App Attest는 탈옥 탐지기가 아닙니다.** 실제 Apple 하드웨어에서 변조하지 않은 정식 앱이 실행 중임을 증명합니다. 긍정적인 신호로 사용하세요.
- **지원 여부와 판정은 다릅니다.** iOS 시뮬레이터에서 `isSupported`는 `false`입니다. Android의 Google Play Services 사용 가능 여부는 토큰 발급 성공이나 특정 무결성 판정을 보장하지 않습니다. 서버에서 [Play Integrity 판정](https://developer.android.com/google/play/integrity/verdicts)을 확인하세요.
- **우회 방법이 존재합니다**(PlayIntegrityFix 등). device attestation은 더 넓은 부정 사용 방지 전략의 한 신호이며 절대적인 보장이 아닙니다.
- **네트워크와 콘솔 설정이 필요합니다.** 없으면 토큰 발급 요청이 reject됩니다. reject를 처리하고 기기가 안전하다고 간주하지 마세요.
- **App Attest 호출 제한**: Apple은 `attestKey` 호출 빈도를 제한합니다. 앱에서 빈도를 제어하세요. App Attest 호출에는 라이브러리가 자동 재시도나 타이머를 추가하지 않습니다.
:::
---
url: /react-native-nitro-device-info/ko/api/device-info.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# DeviceInfo 모듈 \{#deviceinfo-module}
DeviceInfo 모듈의 전체 API 문서입니다. API를 선택하기 전에 [지원 여부 배지 설명](/react-native-nitro-device-info/ko/api/index.md#availability-badges)을 읽으세요.
네이티브 빌드의 최소 버전은 iOS 15.1과 Android API 24입니다. 의존성은 더 높은 최소 버전을 요구할 수 있습니다. 웹용 entry point와 fallback 값은 v1.8.0에서 추가했습니다.
## import \{#import}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
```
***
## 기본 기기 정보(API 9개) \{#core-device-information-9-apis}
기본 기기 정보를 직접 읽는 동기 속성입니다.
### `deviceId: string` \{#deviceid-string}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기 모델 식별자입니다.
```typescript
const deviceId = DeviceInfoModule.deviceId;
// iOS: "iPhone14,2"
// Android: "SM-G998B"
```
### `brand: string` \{#brand-string}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
기기 브랜드 또는 제조사 이름입니다.
```typescript
const brand = DeviceInfoModule.brand;
// iOS: "Apple"
// Android: "Samsung", "Google", "OnePlus", etc.
```
### `model: string` \{#model-string}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
소비자에게 표시하는 기기 모델명입니다. 하드웨어 식별자를 읽기 쉬운 이름으로 변환하고 알 수 없는 기기는 일반 이름으로 표시합니다.
```typescript
const model = DeviceInfoModule.model;
// iOS: "iPhone 18 Pro", "iPhone Duo", "iPad Pro 11-inch (M5)"
// Android: Device-specific model name (e.g., "Pixel 7 Pro", "Galaxy S24")
```
### `systemName: string` \{#systemname-string}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
운영체제 이름입니다.
```typescript
const systemName = DeviceInfoModule.systemName;
// iOS: "iOS" or "iPadOS"
// Android: "Android"
```
### `systemVersion: string` \{#systemversion-string}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
운영체제 버전 문자열입니다.
```typescript
const systemVersion = DeviceInfoModule.systemVersion;
// iOS: "15.0", "16.2.1"
// Android: "12", "13", "14"
```
### `deviceType: DeviceType` \{#devicetype-devicetype}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기 유형입니다.
```typescript
const deviceType = DeviceInfoModule.deviceType;
// "Handset" | "Tablet" | "Tv" | "Desktop" | "GamingConsole" | "unknown"
```
### `uniqueId: string` \{#uniqueid-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기 식별자를 읽습니다.
```typescript
const uniqueId = DeviceInfoModule.uniqueId;
// iOS: IDFV (Identifier for Vendor)
// Android: ANDROID_ID
// Example: "FCDBD8EF-62FC-4ECB-B2F5-92C9E79AC7F9"
```
- **iOS**: 현재 IDFV를 읽으며 조회할 수 없으면 `""`를 반환합니다. 같은 공급업체의 모든 앱을 삭제한 뒤에도 유지된다고 가정하지 마세요.
- **Android**: ANDROID_ID를 읽으며 조회할 수 없으면 `""`를 반환합니다. 범위와 초기화 동작은 Android에 따라 다릅니다.
이 값을 영구 기기 식별자나 계정 식별자로 사용하지 마세요. [Apple IDFV](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor)와 [Android ANDROID_ID](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID)를 참고하세요.
### `manufacturer: string` \{#manufacturer-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
기기 제조사 이름을 읽습니다.
```typescript
const manufacturer = DeviceInfoModule.manufacturer;
// iOS: "Apple"
// Android: "Samsung", "Google", "Xiaomi", etc.
```
### `deviceName: string` \{#devicename-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
사용자가 지정한 기기 이름을 읽습니다.
```typescript
const deviceName = DeviceInfoModule.deviceName;
// Example: "John's iPhone", "My Galaxy S21"
```
***
## 기기 기능(API 7개) \{#device-capabilities-7-apis}
기기 기능과 하드웨어 사용 가능 여부를 불리언으로 확인합니다.
### `isTablet: boolean` \{#istablet-boolean}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
태블릿인지 확인합니다.
```typescript
const isTablet = DeviceInfoModule.isTablet;
// iPad → true
// iPhone → false
```
- **iOS**: UIDevice.userInterfaceIdiom 기준
- **Android**: 최소 화면 너비 >= 600dp 기준
### `isEmulator: boolean` \{#isemulator-boolean}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
시뮬레이터 또는 에뮬레이터에서 실행 중인지 확인합니다.
```typescript
const isEmulator = DeviceInfoModule.isEmulator;
```
### `deviceYearClass: number` \{#deviceyearclass-number}
v1.4.2부터 iOS 15.1+ Android API 24+ 웹: fallback 값
하드웨어 사양으로 추정한 year class를 읽습니다.
```typescript
const yearClass = DeviceInfoModule.deviceYearClass;
if (yearClass >= 2020) {
enableHighEndFeatures();
} else if (yearClass >= 2015) {
enableStandardFeatures();
} else {
enableLowEndFeatures();
}
```
기기의 하드웨어가 플래그십·고급 사양에 해당했을 것으로 추정하는 연도를 반환합니다. 2025년에 맞춰 확장한 Facebook device-year-class 알고리즘을 사용합니다.
**RAM → year class 대응**:
| RAM | year class | 기기 예시 |
| ------ | ---------- | --------------- |
| ≤2 GB | 2013 | 보급형 |
| ≤4 GB | 2015 | 2015-2016년 중급형 |
| ≤6 GB | 2017 | 2017-2018년 플래그십 |
| ≤8 GB | 2019 | 2019-2020년 플래그십 |
| ≤12 GB | 2021 | 2021-2022년 플래그십 |
| ≤16 GB | 2023 | 2023-2024년 플래그십 |
| >16 GB | 2025 | 최신 플래그십 |
### `isCameraPresent: boolean` \{#iscamerapresent-boolean}
v1.2.0부터 iOS 15.1+ (v1.9.0부터) Android API 24+ 웹: fallback 값
iOS 구현은 v1.9.0부터 사용할 수 있습니다. v1.8.3까지의 배포 버전은 항상 `true`를 반환합니다. [구현 변경](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/be976f0)을 참고하세요.
카메라 하드웨어가 있는지 확인합니다. iOS 시뮬레이터나 영상 캡처 기기가 없을 때는 `false`를 반환합니다. 카메라 권한을 요청하지 않으며, `true`라고 해서 앱에 영상 촬영 권한이 있다는 뜻은 아닙니다.
```typescript
const hasCamera = DeviceInfoModule.isCameraPresent;
```
### `isPinOrFingerprintSet: boolean` \{#ispinorfingerprintset-boolean}
v1.2.0부터 iOS 15.1+ (v1.9.0부터) Android API 24+ 웹: fallback 값
iOS 구현은 v1.9.0부터 사용할 수 있습니다. v1.8.3까지의 배포 버전은 항상 `false`를 반환합니다. [구현 변경](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/801903e)을 참고하세요.
PIN, 지문 또는 Face ID를 설정했는지 확인합니다. iOS에서는 기기 소유자를 인증할 수 있는지 확인합니다. 생체 인증을 사용할 수 없거나 잠겨 있어 기기 암호로 인증하는 경우도 포함합니다. 암호를 설정하지 않았으면 `false`를 반환합니다. 사용자를 인증하거나 인증 창을 표시하지 않으며, 읽을 때마다 다시 검사합니다.
```typescript
const isSecure = DeviceInfoModule.isPinOrFingerprintSet;
```
### `isHardwareKeyStoreAvailable: boolean` \{#ishardwarekeystoreavailable-boolean}
v1.2.1부터 iOS 15.1+ Android API 24+: 제한적 지원 웹: fallback 값
플랫폼 키 저장소를 사용할 수 있는지 확인합니다. Android에서는 키를 하드웨어로 보호하는지 검증하지 않습니다.
```typescript
const hasHardwareKeyStore = DeviceInfoModule.isHardwareKeyStoreAvailable;
if (hasHardwareKeyStore) {
console.log('Platform key-storage check passed');
// Apply your key-storage policy; this check alone is not a security guarantee.
} else {
console.log('Platform key storage unavailable');
// Use alternative security measures
}
```
**플랫폼 제한**: iOS는 Secure Enclave 사용 가능 여부를 확인합니다. Android는 `AndroidKeyStore`를 열 수 있는지만 확인하므로 키가 하드웨어로 보호된다는 증거가 아닙니다.
### `isLowRamDevice: boolean` \{#islowramdevice-boolean}
v1.2.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
RAM이 적은 기기로 분류되는지 확인합니다.
```typescript
const isLowRam = DeviceInfoModule.isLowRamDevice;
// Android API 19+: true/false
// iOS: false
```
**플랫폼**: Android. OS 분류 API는 API 19부터 있지만 이 패키지는 API 24 이상이 필요합니다.
***
## 디스플레이와 화면(API 7개) \{#display--screen-7-apis}
화면과 디스플레이 정보입니다.
### `getHasNotch(): boolean` \{#gethasnotch-boolean}
v1.3.0부터 iOS 15.1+ Android: fallback 값 웹: fallback 값
화면에 노치가 있는지 확인합니다.
```typescript
const hasNotch = DeviceInfoModule.getHasNotch();
// iPhone X, 11, 12, 13 → true
// iPhone SE, 8 → false
```
- **iOS 전용**: iPhone X 이후 모델을 감지합니다.
- **Android**: 항상 `false`를 반환합니다.
### `getHasDynamicIsland(): boolean` \{#gethasdynamicisland-boolean}
v1.3.0부터 iOS 16+ Android: fallback 값 웹: fallback 값
Dynamic Island가 있는지 확인합니다.
```typescript
const hasDynamicIsland = DeviceInfoModule.getHasDynamicIsland();
// iPhone 14 Pro, 15 Pro → true
// iPhone 14, 13 → false
```
- **iOS 16 이상 전용**: iPhone 14 Pro 이후
- **Android**: 항상 `false`를 반환합니다.
### `isDisplayZoomed: boolean` \{#isdisplayzoomed-boolean}
v1.2.0부터 iOS 15.1+ Android: fallback 값 웹: fallback 값
iOS 디스플레이 확대가 켜져 있는지 확인합니다.
```typescript
const isZoomed = DeviceInfoModule.isDisplayZoomed;
// iOS: true/false based on display zoom setting
// Android: false
```
**플랫폼**: iOS 전용
### `getIsLandscape(): boolean` \{#getislandscape-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
기기가 가로 방향인지 확인합니다.
```typescript
const isLandscape = DeviceInfoModule.getIsLandscape();
```
### `getBrightness(): number` \{#getbrightness-number}
v1.1.0부터 iOS 15.1+ Android: fallback 값 웹: fallback 값
현재 화면 밝기를 읽습니다(0.0\~1.0).
```typescript
const brightness = DeviceInfoModule.getBrightness();
console.log(`Brightness: ${(brightness * 100).toFixed(0)}%`);
// iOS: 0.0 to 1.0
// Android: -1
```
**플랫폼**: iOS 전용
### `getFontScale(): number` \{#getfontscale-number}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
현재 글꼴 배율을 읽습니다.
```typescript
const fontScale = DeviceInfoModule.getFontScale();
// Example: 1.0 (normal), 1.2 (large), 0.85 (small)
```
### `isLiquidGlassAvailable: boolean` \{#isliquidglassavailable-boolean}
v1.2.1부터 iOS 26+ Android: fallback 값 웹: fallback 값
기기에서 Liquid Glass 효과를 사용할 수 있는지 확인합니다.
```typescript
const hasLiquidGlass = DeviceInfoModule.isLiquidGlassAvailable;
if (hasLiquidGlass) {
console.log('Liquid glass effect available');
// Can use new iOS 26+ design features
} else {
console.log('Liquid glass not available');
// Fallback to standard UI
}
```
**플랫폼**: iOS 26.0 이상
Swift 6.2 이상 컴파일러가 필요합니다. 이전 컴파일러로 빌드하거나 `UIDesignRequiresCompatibility`를 켜면 `false`를 반환합니다.
***
## 시스템 리소스(API 7개) \{#system-resources-7-apis}
메모리, 저장 공간, 가동 시간 정보입니다.
### `totalMemory: number` \{#totalmemory-number}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
기기 전체 RAM을 바이트로 읽습니다.
```typescript
const totalMemory = DeviceInfoModule.totalMemory;
// Example: 6442450944 (6 GB)
console.log(`Total RAM: ${(totalMemory / 1024 / 1024 / 1024).toFixed(1)}GB`);
```
### `getUsedMemory(): number` \{#getusedmemory-number}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
현재 앱의 메모리 사용량을 바이트로 읽습니다.
```typescript
const usedMemory = DeviceInfoModule.getUsedMemory();
// Example: 134217728 (128 MB)
console.log(`Used Memory: ${(usedMemory / 1024 / 1024).toFixed(0)}MB`);
```
### `maxMemory: number` \{#maxmemory-number}
v1.2.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
앱이 사용할 수 있는 최대 메모리를 바이트로 읽습니다.
```typescript
const maxMemory = DeviceInfoModule.maxMemory;
// Android: max heap size
// iOS: -1
```
**플랫폼**: Android 전용
### `totalDiskCapacity: number` \{#totaldiskcapacity-number}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
전체 내부 저장 공간을 바이트로 읽습니다.
```typescript
const totalDisk = DeviceInfoModule.totalDiskCapacity;
// Example: 128849018880 (120 GB)
console.log(`Total Storage: ${(totalDisk / 1024 / 1024 / 1024).toFixed(0)}GB`);
```
### `getFreeDiskStorage(): number` \{#getfreediskstorage-number}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
남은 저장 공간을 바이트로 읽습니다.
```typescript
const freeDisk = DeviceInfoModule.getFreeDiskStorage();
// Example: 51539607552 (48 GB)
console.log(`Free Storage: ${(freeDisk / 1024 / 1024 / 1024).toFixed(1)}GB`);
```
### `getUptime(): number` \{#getuptime-number}
v1.4.2부터 iOS 15.1+ Android API 24+ 웹: fallback 값
깊은 절전 시간을 제외한 부팅 후 기기 가동 시간을 밀리초로 읽습니다.
iOS에서는 앱 이벤트의 시간 측정에만 사용하세요. 경과 시간이나 타이머(`35F9.1`), 또는 `startupTime`으로 앱 이벤트의 uptime을 절대 타임스탬프로 변환하는 용도(`8FFB.1`)입니다. 원시 가동 시간을 일반 기기 정보로 표시·수집하거나 기기 밖으로 전송하거나 핑거프린팅에 사용하지 마세요. 앱 이벤트 사이의 경과 시간 또는 변환한 앱 이벤트의 절대 타임스탬프만 기기 밖으로 전송할 수 있습니다.
```typescript
const startedAt = DeviceInfoModule.getUptime();
const usedMemory = DeviceInfoModule.getUsedMemory();
const elapsedMs = DeviceInfoModule.getUptime() - startedAt;
console.log({ usedMemory, elapsedMs });
```
**플랫폼 동작**:
- **iOS**: `systemUptime` 사용(깊은 절전 제외)
- **Android**: `uptimeMillis()` 사용(깊은 절전 제외)
두 플랫폼 모두 부팅 후의 활성 시간을 반환하며 `expo-device.getUptimeAsync()`의 동작과 같습니다.
### `startupTime: number` \{#startuptime-number}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기 부팅 시각을 읽습니다(epoch 이후 밀리초).
iOS에서는 앱 이벤트의 uptime을 절대 타임스탬프로 변환하는 기준 시각으로만 사용하세요(`8FFB.1`). 원시 부팅 타임스탬프를 일반 기기 정보로 표시·수집하거나 기기 밖으로 전송하거나 핑거프린팅에 사용하지 마세요. 변환한 앱 내 이벤트의 절대 타임스탬프만 기기 밖으로 전송할 수 있습니다.
```typescript
// iOS: capture an event occurring in the app using the same uptime clock.
const eventUptime = DeviceInfoModule.getUptime();
const eventTimestamp = DeviceInfoModule.startupTime + eventUptime;
console.log(`App event at: ${new Date(eventTimestamp).toISOString()}`);
```
앱 시작 시각이 아니라 기기 부팅 시각입니다. 지원 목적과 Apple의 사용 제한은 [iOS privacy info manifest](/react-native-nitro-device-info/ko/guide/getting-started.md#ios-privacy-manifest)를 참고하세요.
***
## 배터리와 전원(API 4개) \{#battery--power-4-apis}
배터리와 전원 상태 정보입니다.
### `getBatteryLevel(): number` \{#getbatterylevel-number}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
현재 배터리 잔량(0.0\~1.0)을 읽으며 조회할 수 없으면 `-1`을 반환합니다. 배터리가 빈 상태임을 확인하면 `0`을 반환합니다.
웹에서는 첫 비동기 요청이 resolve된 뒤 배터리 getter가 같은 BatteryManager 객체에서 현재 값을 읽습니다.
요청이 resolve되기 전이거나 API가 없거나 요청이 reject된 경우,
잔량은 `-1`, 충전 여부는 `false`, 배터리 상태는 `"unknown"`이며
`isLowBatteryLevel()`은 `false`를 반환합니다.
```typescript
const batteryLevel = DeviceInfoModule.getBatteryLevel();
console.log(batteryLevel < 0
? 'Battery: unavailable'
: `Battery: ${(batteryLevel * 100).toFixed(0)}%`);
// Output: "Battery: 75%"
```
### `getPowerState(): PowerState` \{#getpowerstate-powerstate}
v0.1.0부터 iOS 15.1+ Android API 24+: 제한적 지원 웹: 제한적 지원
Android에서 `lowPowerMode`는 항상 `false`입니다. 배터리 잔량과 충전 상태는 실제 값을 읽습니다.
전체 전원 상태를 읽습니다.
```typescript
const powerState = DeviceInfoModule.getPowerState();
console.log(powerState.batteryLevel < 0
? 'Battery: unavailable'
: `Battery: ${(powerState.batteryLevel * 100).toFixed(0)}%`);
console.log(`Status: ${powerState.batteryState}`);
console.log(`Low Power Mode: ${powerState.lowPowerMode}`); // iOS only
```
**PowerState** 인터페이스:
```typescript
interface PowerState {
batteryLevel: number; // 0.0 to 1.0, or -1 if unavailable
batteryState: BatteryState; // 'unknown' | 'unplugged' | 'charging' | 'full'
lowPowerMode: boolean; // iOS only
}
```
### `getIsBatteryCharging(): boolean` \{#getisbatterycharging-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
배터리를 충전 중인지 확인합니다.
```typescript
const isCharging = DeviceInfoModule.getIsBatteryCharging();
```
### `isLowBatteryLevel(threshold: number): boolean` \{#islowbatterylevelthreshold-number-boolean}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
유효한 배터리 잔량이 임계값보다 낮은지 확인합니다. 조회할 수 없으면 `false`를 반환합니다. 확인한 잔량이 `0%`라면 부족한 상태로 판단합니다.
```typescript
const isLowBattery = DeviceInfoModule.isLowBatteryLevel(0.2); // 20%
if (isLowBattery) {
console.log('Battery is low, please charge');
}
```
***
## 앱 메타데이터(API 9개) \{#application-metadata-9-apis}
앱 번들과 버전 정보입니다.
### `version: string` \{#version-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
앱 버전 문자열을 읽습니다.
```typescript
const version = DeviceInfoModule.version;
// Example: "1.2.3"
```
### `buildNumber: string` \{#buildnumber-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
앱 빌드 번호를 읽습니다.
```typescript
const buildNumber = DeviceInfoModule.buildNumber;
// Example: "42" or "20231025"
```
### `bundleId: string` \{#bundleid-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
번들 ID(iOS) 또는 패키지 이름(Android)을 읽습니다.
```typescript
const bundleId = DeviceInfoModule.bundleId;
// Example: "com.company.app"
```
### `applicationName: string` \{#applicationname-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
앱 표시 이름을 읽습니다.
```typescript
const appName = DeviceInfoModule.applicationName;
// Example: "My Awesome App"
```
### `readableVersion: string` \{#readableversion-string}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
읽기 쉬운 버전 문자열(version.buildNumber)을 읽습니다.
```typescript
const readableVersion = DeviceInfoModule.readableVersion;
// Example: "1.2.3.42"
```
### `getFirstInstallTime(): Promise` \{#getfirstinstalltime-promisenumber}
v0.1.0부터 iOS 15.1+: 제한적 지원 Android API 24+ 웹: fallback 값
iOS에서는 Documents 디렉터리 생성 시각으로 설치 시각을 추정합니다. 조회할 수 없으면 `0`을 반환합니다.
앱 최초 설치 시각을 읽습니다(epoch 이후 밀리초).
```typescript
const installTime = await DeviceInfoModule.getFirstInstallTime();
const installDate = new Date(installTime);
console.log(`Installed: ${installDate.toLocaleDateString()}`);
```
### `getLastUpdateTime(): Promise` \{#getlastupdatetime-promisenumber}
v0.1.0부터 iOS 15.1+: 제한적 지원 Android API 24+ 웹: fallback 값
가장 최근 앱 갱신 시각을 읽습니다(epoch 이후 밀리초).
```typescript
const updateTime = await DeviceInfoModule.getLastUpdateTime();
const updateDate = new Date(updateTime);
console.log(`Last Updated: ${updateDate.toLocaleDateString()}`);
```
**iOS 제한**: App Store 업데이트 시각이 아닌 Documents 디렉터리 수정 시각을 읽습니다. 조회할 수 없으면 `0`을 반환합니다.
### `firstInstallTimeSync: number` \{#firstinstalltimesync-number}
v1.1.0부터 iOS 15.1+: 제한적 지원 Android API 24+ 웹: fallback 값
iOS에서는 처음 접근할 때 Documents 디렉터리 생성 시각을 캐시합니다. 조회할 수 없으면 `0`을 반환합니다.
`getFirstInstallTime()`의 동기 버전입니다.
```typescript
const firstInstallTimeSync = DeviceInfoModule.firstInstallTimeSync;
```
### `lastUpdateTimeSync: number` \{#lastupdatetimesync-number}
v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
동기 버전입니다(iOS에서는 -1 반환).
```typescript
const lastUpdateTimeSync = DeviceInfoModule.lastUpdateTimeSync;
```
***
## 네트워크(API 6개) \{#network-6-apis}
통신사를 제외한 네트워크 연결 API입니다.
### `getIpAddress(): Promise` \{#getipaddress-promisestring}
v0.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기의 로컬 IP 주소를 읽습니다.
```typescript
const ipAddress = await DeviceInfoModule.getIpAddress();
// Example: "192.168.1.100", "10.0.0.5"
```
### `getIpAddressSync(): string` \{#getipaddresssync-string}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
동기 버전입니다(5초 캐시 사용).
```typescript
const ipAddressSync = DeviceInfoModule.getIpAddressSync();
```
### `getMacAddress(): Promise` \{#getmacaddress-promisestring}
v0.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Android에서 접근을 허용하면 Wi-Fi MAC 주소를 읽습니다. `getMacAddressSync()`와 같은 5초 캐시를 사용하며 조회할 수 없으면 `"unknown"`을 반환합니다. 최신 Android에서 [일반 앱은 대개 하드웨어 MAC 주소에 접근할 수 없습니다](https://developer.android.com/reference/java/net/NetworkInterface#getHardwareAddress\(\)). 이 API는 제한을 우회하지 않습니다.
```typescript
const macAddress = await DeviceInfoModule.getMacAddress();
// iOS: "02:00:00:00:00:00" (hardcoded since iOS 7 for privacy)
// Android: "unknown" when restricted, otherwise the available wlan0 MAC
```
### `getMacAddressSync(): string` \{#getmacaddresssync-string}
v1.3.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Android에서 같은 방식으로 조회하는 동기 버전입니다. 5초 캐시와 `"unknown"` fallback 값도 공유합니다.
```typescript
const macAddressSync = DeviceInfoModule.getMacAddressSync();
```
### `getUserAgent(): Promise` \{#getuseragent-promisestring}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
HTTP User-Agent 문자열을 읽습니다.
```typescript
const userAgent = await DeviceInfoModule.getUserAgent();
// Example: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) ..."
```
iOS는 WebView를 초기화하고 처음 성공한 결과를 캐시합니다. Android는 `WebSettings`를 비동기로 조회합니다. 두 플랫폼 모두 `Promise`을 반환합니다.
### `getIsAirplaneMode(): boolean` \{#getisairplanemode-boolean}
v1.3.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
비행기 모드가 켜져 있는지 확인합니다.
웹에서는 브라우저가 비행기 모드를 판단할 수 없으므로 항상 `false`를 반환합니다.
오프라인이라는 사실만으로 비행기 모드가 켜졌다고 판단할 수는 없습니다.
```typescript
const isAirplaneMode = DeviceInfoModule.getIsAirplaneMode();
// Android: true/false
// iOS and web: false (not available)
```
**플랫폼**: Android 전용
***
## 통신사 정보(API 7개) \{#carrier-information-7-apis}
통신 앱, 분석, 지역 판단에 사용하는 이동통신사 정보입니다.
### `getCarrier(): Promise` \{#getcarrier-promisestring}
v0.1.0부터 iOS 15.1+ (v1.8.0부터) Android API 24+ 웹: fallback 값
iOS에서 실제 값을 반환하는 구현은 v1.8.0부터 제공합니다. 이전 버전에서는 대응하는 동기 API가 구현되어 있어도 이 비동기 API는 고정 fallback 값을 반환합니다. [iOS 구현 변경](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/cb6eb026)을 참고하세요.
이동통신사 이름을 읽습니다.
```typescript
const carrier = await DeviceInfoModule.getCarrier();
// Example: "Verizon", "AT&T", "T-Mobile"
```
### `getCarrierSync(): string` \{#getcarriersync-string}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
동기 버전입니다(5초 캐시 사용).
```typescript
const carrierSync = DeviceInfoModule.getCarrierSync();
```
### `carrierAllowsVOIP: boolean` \{#carrierallowsvoip-boolean}
v1.5.0부터 iOS 15.1+ Android: fallback 값 웹: fallback 값
통신사가 네트워크에서 VoIP 통화를 허용하는지 확인합니다.
```typescript
const allowsVOIP = DeviceInfoModule.carrierAllowsVOIP;
// iOS: true/false based on carrier policy
// Android: always true (no equivalent API)
```
**플랫폼**: iOS 전용(Android에서는 항상 `true` 반환)
### `carrierIsoCountryCode: string` \{#carrierisocountrycode-string}
v1.5.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
통신사의 ISO 3166-1 alpha-2 국가 코드를 읽습니다.
```typescript
const countryCode = DeviceInfoModule.carrierIsoCountryCode;
// Example: "US", "KR", "JP", "DE"
// Returns "" if no SIM card
```
### `mobileCountryCode: string` \{#mobilecountrycode-string}
v1.5.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
ITU-T 권고 E.212에 따른 이동통신 국가 코드(MCC)를 읽습니다.
```typescript
const mcc = DeviceInfoModule.mobileCountryCode;
// Example: "310" (USA), "450" (Korea), "440" (Japan)
// Returns "" if no carrier
```
**주요 MCC 값**:
| 국가 | MCC |
| -- | ------- |
| 미국 | 310-316 |
| 한국 | 450 |
| 일본 | 440-441 |
| 중국 | 460 |
| 독일 | 262 |
### `mobileNetworkCode: string` \{#mobilenetworkcode-string}
v1.5.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
국가 내 통신사를 구별하는 이동통신 네트워크 코드(MNC)를 읽습니다.
```typescript
const mnc = DeviceInfoModule.mobileNetworkCode;
// Example: "260" (T-Mobile US), "05" (SKT Korea)
// Returns "" if no carrier
```
### `mobileNetworkOperator: string` \{#mobilenetworkoperator-string}
v1.5.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
MCC + MNC를 합친 문자열을 읽습니다.
```typescript
const operator = DeviceInfoModule.mobileNetworkOperator;
// Example: "310260" (T-Mobile US), "45005" (SKT Korea)
// Equivalent to: mobileCountryCode + mobileNetworkCode
// Returns "" if no carrier
```
**활용 예**:
- 통신사별 기능 설정
- 지역별 콘텐츠 제공
- 통신 분석
- 부정 사용 탐지(지역 확인)
***
## 오디오 기기(API 4개) \{#audio-accessories-4-apis}
오디오 기기를 감지합니다.
### `isHeadphonesConnected(): Promise` \{#isheadphonesconnected-promiseboolean}
v0.1.0부터 iOS 15.1+ (v1.8.0부터) Android API 24+ 웹: fallback 값
iOS에서 실제 값을 반환하는 구현은 v1.8.0부터 제공합니다. 이전 버전에서는 대응하는 동기 API가 구현되어 있어도 이 비동기 API는 고정 fallback 값을 반환합니다. [iOS 구현 변경](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/cb6eb026)을 참고하세요.
헤드폰 연결 여부를 확인합니다(유선 또는 Bluetooth). Android에서는 동기 getter와 같은 방식으로 출력 기기를 감지합니다.
```typescript
const hasHeadphones = await DeviceInfoModule.isHeadphonesConnected();
```
### `getIsHeadphonesConnected(): boolean` \{#getisheadphonesconnected-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
동기 버전입니다.
```typescript
const isHeadphonesConnected = DeviceInfoModule.getIsHeadphonesConnected();
```
### `getIsWiredHeadphonesConnected(): boolean` \{#getiswiredheadphonesconnected-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
유선 헤드폰 연결 여부를 확인합니다. Android에서는 유선 헤드폰·헤드셋과 [API 26 이상의 USB 헤드셋](https://developer.android.com/reference/android/media/AudioDeviceInfo#TYPE_USB_HEADSET)을 포함합니다. 내장 스피커와 Bluetooth 기기는 유선 헤드폰에 포함하지 않습니다.
```typescript
const hasWiredHeadphones = DeviceInfoModule.getIsWiredHeadphonesConnected();
```
### `getIsBluetoothHeadphonesConnected(): boolean` \{#getisbluetoothheadphonesconnected-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
Bluetooth 헤드폰 연결 여부를 확인합니다.
```typescript
const hasBluetoothHeadphones = DeviceInfoModule.getIsBluetoothHeadphonesConnected();
```
***
## 위치 서비스(API 3개) \{#location-services-3-apis}
위치 provider 정보입니다.
### `isLocationEnabled(): Promise` \{#islocationenabled-promiseboolean}
v0.1.0부터 iOS 15.1+ (v1.8.0부터) Android API 24+ 웹: fallback 값
iOS에서 실제 값을 반환하는 구현은 v1.8.0부터 제공합니다. 이전 버전에서는 대응하는 동기 API가 구현되어 있어도 이 비동기 API는 고정 fallback 값을 반환합니다. [iOS 구현 변경](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/cb6eb026)을 참고하세요.
위치 서비스가 켜져 있는지 확인합니다.
```typescript
const isLocationEnabled = await DeviceInfoModule.isLocationEnabled();
```
### `getIsLocationEnabled(): boolean` \{#getislocationenabled-boolean}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
동기 버전입니다.
```typescript
const isLocationEnabled = DeviceInfoModule.getIsLocationEnabled();
```
### `getAvailableLocationProviders(): string[]` \{#getavailablelocationproviders-string}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
활성화된 위치 provider 목록을 읽습니다.
```typescript
const providers = DeviceInfoModule.getAvailableLocationProviders();
// ["gps", "network"]
```
***
## 언어와 지역(API 1개) \{#localization-1-api}
언어와 지역 설정입니다.
### `systemLanguage: string` \{#systemlanguage-string}
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
기기 시스템 언어를 BCP 47 형식으로 읽습니다.
```typescript
const language = DeviceInfoModule.systemLanguage;
// iOS: "en-US", "ko-KR", "ja-JP", "zh-Hans-CN"
// Android: "en-US", "ko-KR", "ja-JP", "zh-Hans-CN"
```
**예시**:
| 언어 | 코드 |
| --------- | ------------ |
| 영어(미국) | `en-US` |
| 한국어 | `ko-KR` |
| 일본어 | `ja-JP` |
| 중국어 간체 | `zh-Hans-CN` |
| 프랑스어(프랑스) | `fr-FR` |
| 독일어 | `de-DE` |
**활용 예**:
```typescript
const language = DeviceInfoModule.systemLanguage;
if (language.startsWith('ko')) {
console.log('Korean device detected');
} else if (language.startsWith('ja')) {
console.log('Japanese device detected');
}
```
***
## CPU와 아키텍처(API 3개) \{#cpu--architecture-3-apis}
프로세서와 ABI 정보입니다.
### `supportedAbis: string[]` \{#supportedabis-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
지원 CPU 아키텍처를 읽습니다.
```typescript
const abis = DeviceInfoModule.supportedAbis;
// iOS: ["arm64"]
// Android: ["arm64-v8a", "armeabi-v7a"]
```
### `supported32BitAbis: string[]` \{#supported32bitabis-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
지원하는 32비트 ABI 목록을 읽습니다.
```typescript
const abis32 = DeviceInfoModule.supported32BitAbis;
// iOS: []
// Android API 21+: ["armeabi-v7a", "x86"]
```
**플랫폼**: Android API 21 이상. iOS에서는 `[]` 반환
### `supported64BitAbis: string[]` \{#supported64bitabis-string}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
지원하는 64비트 ABI 목록을 읽습니다.
```typescript
const abis64 = DeviceInfoModule.supported64BitAbis;
// iOS: ["arm64"]
// Android API 21+: ["arm64-v8a", "x86_64"]
```
***
## Android 플랫폼(API 20개 이상) \{#android-platform-20-apis}
Android 전용 API와 빌드 정보입니다.
### `apiLevel: number` \{#apilevel-number}
v1.2.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Android API 수준을 읽습니다.
```typescript
const apiLevel = DeviceInfoModule.apiLevel;
// Android 12 → 31
// Android 13 → 33
// iOS → -1
```
**플랫폼**: Android 전용
### `navigationMode: NavigationMode` \{#navigationmode-navigationmode}
v1.3.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Android 내비게이션 방식을 읽습니다.
```typescript
const navMode = DeviceInfoModule.navigationMode;
// Android with gesture nav → "gesture"
// Android with 3-button nav → "buttons"
// Android with 2-button nav → "twobuttons"
// iOS → "unknown"
```
**타입**: `'gesture' | 'buttons' | 'twobuttons' | 'unknown'`
**플랫폼**: Android 전용(iOS에서는 "unknown" 반환)
**값**:
| 값 | 설명 |
| ------------ | -------------------------- |
| `gesture` | 제스처 내비게이션(스와이프 기반) |
| `buttons` | 기존 3버튼 내비게이션(뒤로, 홈, 최근 앱) |
| `twobuttons` | 2버튼 내비게이션(뒤로, 위로 스와이프하는 홈) |
| `unknown` | 판단 불가(iOS에서는 항상 이 값) |
**활용 예**:
```typescript
const navMode = DeviceInfoModule.navigationMode;
if (navMode === 'gesture') {
// Avoid bottom gesture conflicts
// Add extra bottom padding for bottom sheets
console.log('Using gesture navigation - add extra padding');
} else if (navMode === 'buttons') {
// Traditional navigation bar is present
console.log('Using button navigation');
}
```
**참고**: 내비게이션 방식 감지는 Android 10(API 29) 이상이 필요합니다. 이전 Android에서는 제스처 내비게이션을 지원하지 않았으므로 `"buttons"`를 반환합니다.
### `getHasGms(): boolean` \{#gethasgms-boolean}
v1.3.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Google Mobile Services 사용 가능 여부를 확인합니다.
```typescript
const hasGms = DeviceInfoModule.getHasGms();
// Android with Play Services → true
// Huawei devices without GMS → false
// iOS → false
```
**플랫폼**: Android 전용
### `getHasHms(): boolean` \{#gethashms-boolean}
v1.3.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
Huawei Mobile Services 사용 가능 여부를 확인합니다.
```typescript
const hasHms = DeviceInfoModule.getHasHms();
// Huawei devices → true
// Other Android/iOS → false
```
**플랫폼**: Android(Huawei 기기) 전용
### `hasSystemFeature(feature: string): boolean` \{#hassystemfeaturefeature-string-boolean}
v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
특정 시스템 기능의 사용 가능 여부를 확인합니다.
```typescript
const hasNfc = DeviceInfoModule.hasSystemFeature('android.hardware.nfc');
// Android → true/false based on hardware
// iOS → false
```
**플랫폼**: Android 전용
**주요 기능**:
- `android.hardware.camera`
- `android.hardware.nfc`
- `android.hardware.bluetooth`
- `android.hardware.wifi`
### `systemAvailableFeatures: string[]` \{#systemavailablefeatures-string}
v1.2.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
사용 가능한 모든 시스템 기능 목록을 읽습니다.
```typescript
const features = DeviceInfoModule.systemAvailableFeatures;
// Android: ["android.hardware.camera", "android.hardware.nfc", ...]
// iOS: []
```
**플랫폼**: Android 전용
### `supportedMediaTypeList: string[]` \{#supportedmediatypelist-string}
v1.2.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
지원하는 미디어·코덱 타입 목록을 읽습니다.
```typescript
const mediaTypes = DeviceInfoModule.supportedMediaTypeList;
// Android: ["video/avc", "audio/mp4a-latm", ...]
// iOS: []
```
**플랫폼**: Android 전용
### Android 빌드 정보 \{#android-build-information}
Android 시스템 빌드 정보를 읽는 동기 속성입니다.
**플랫폼**: Android 전용(iOS에서는 모두 "unknown" 또는 기본값 반환)
```typescript
const serialNumber = DeviceInfoModule.serialNumber; // Android 8–9 needs granted READ_PHONE_STATE; Android 10+ is restricted
const androidId = DeviceInfoModule.androidId;
const previewSdkInt = DeviceInfoModule.previewSdkInt; // Android API 23+, 0 for release
const securityPatch = DeviceInfoModule.securityPatch; // Android API 23+, "YYYY-MM-DD"
const codename = DeviceInfoModule.codename; // "REL" for release
const incremental = DeviceInfoModule.incremental;
const board = DeviceInfoModule.board;
const bootloader = DeviceInfoModule.bootloader;
const device = DeviceInfoModule.device; // Board/platform name
const display = DeviceInfoModule.display; // Build display ID
const fingerprint = DeviceInfoModule.fingerprint; // Unique build identifier
const hardware = DeviceInfoModule.hardware;
const host = DeviceInfoModule.host; // Build host machine
const product = DeviceInfoModule.product;
const tags = DeviceInfoModule.tags; // Comma-separated
const type = DeviceInfoModule.type; // "user", "userdebug", "eng"
const baseOs = DeviceInfoModule.baseOs; // Android API 23+
const radioVersion = DeviceInfoModule.radioVersion;
const buildId = DeviceInfoModule.buildId;
```
| 속성 | 지원 여부 |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `serialNumber` | v1.1.0부터 iOS: fallback 값 Android API 24+: 제한적 지원 웹: fallback 값 |
| `androidId` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `previewSdkInt` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `securityPatch` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `codename` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `incremental` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `board` | v1.5.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `bootloader` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `device` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `display` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `fingerprint` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `hardware` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `host` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `product` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `tags` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `type` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `baseOs` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `radioVersion` | v1.5.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
| `buildId` | v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값 |
`serialNumber`는 처음 접근할 때 캐시합니다. Android 8–9에서는 `READ_PHONE_STATE` 권한을 받아야 합니다. Android 10 이상은 권한을 받아도 일반 앱의 접근을 제한합니다.
***
## iOS 플랫폼(API 2개) \{#ios-platform-2-apis}
iOS 전용 API입니다.
### `getDeviceToken(): Promise` \{#getdevicetoken-promisestring}
v1.1.0부터 iOS 15.1+ Android: reject 웹: reject
Apple DeviceCheck 토큰을 읽습니다.
```typescript
try {
const deviceToken = await DeviceInfoModule.getDeviceToken();
console.log('DeviceCheck token:', deviceToken);
} catch (error) {
console.error('DeviceCheck error:', error);
}
```
**플랫폼**: iOS. DeviceCheck는 iOS 11부터 있지만 이 패키지는 iOS 15.1 이상이 필요합니다. Android에서는 reject됩니다.
### `syncUniqueId(): Promise` \{#syncuniqueid-promisestring}
v1.1.0부터 iOS 15.1+ Android: ID만 반환 웹: fallback 값
iOS에서 현재 IDFV를 앱 전용 Keychain 항목에 기록합니다. iCloud Keychain 동기화를 켜거나 이전 IDFV를 복원하지는 않습니다.
```typescript
const uniqueId = await DeviceInfoModule.syncUniqueId();
// iOS: Writes and returns the current IDFV.
// Android: Returns uniqueId without a Keychain operation.
```
**플랫폼**: iOS(Android에서는 기록 작업 없음)
***
## 설치와 배포(API 3개) \{#installation--distribution-3-apis}
앱 설치와 배포 메타데이터입니다.
### `installerPackageName: string` \{#installerpackagename-string}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
앱을 설치한 앱 스토어의 패키지 이름을 읽습니다.
```typescript
const installer = DeviceInfoModule.installerPackageName;
// iOS: "com.apple.AppStore", "com.apple.TestFlight"
// Android: "com.android.vending" (Play Store)
```
### `getInstallReferrer(): Promise` \{#getinstallreferrer-promisestring}
v1.1.0부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
설치 리퍼러 정보를 읽습니다(Android Play Store).
```typescript
const referrer = await DeviceInfoModule.getInstallReferrer();
// Android with Play Services: referrer data
// iOS: "unknown"
```
**플랫폼**: Android 전용(Google Play Services 필요)
### `isSideLoadingEnabled(): boolean` \{#issideloadingenabled-boolean}
v1.4.2부터 iOS: fallback 값 Android API 24+ 웹: fallback 값
사이드로딩(알 수 없는 출처의 설치)이 켜져 있는지 확인합니다.
```typescript
const canSideload = DeviceInfoModule.isSideLoadingEnabled();
if (canSideload) {
console.warn('Device allows sideloading - potential security risk');
}
```
**플랫폼별 동작 차이**:
- **Android 7 이하**: 기기 전체에서 알 수 없는 출처를 허용하는지 반환합니다(`Settings.Global.INSTALL_NON_MARKET_APPS` 확인).
- **Android 8.0 이상**: 이 앱에 다른 앱을 설치할 권한이 있는지 반환합니다(`canRequestPackageInstalls()`로 앱별 권한 확인).
- **iOS**: 이 API는 항상 `false`를 반환하며 사이드로딩을 감지하지 않습니다.
**중요**: Android 8.0 이상에서는 다른 앱에 "알 수 없는 앱 설치"를 허용했더라도 이 앱에 별도로 허용하지 않았다면 `false`를 반환합니다.
**활용 예**:
- 보안 정책 적용
- 배포 경로 확인
- 기업 배포 확인
**플랫폼**: Android(iOS에서는 `false` 반환)
***
## 레거시 호환(API 2개) \{#legacy-compatibility-2-apis}
이전 버전과의 호환을 위한 사용 중단 예정 API입니다.
### `totalDiskCapacityOld: number` \{#totaldiskcapacityold-number}
v1.2.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
레거시 Android API로 전체 디스크 용량을 읽습니다.
```typescript
const totalDiskOld = DeviceInfoModule.totalDiskCapacityOld;
// Android: Uses old StatFs API (pre-Jelly Bean compatibility)
// iOS: Alias to totalDiskCapacity
```
### `getFreeDiskStorageOld(): number` \{#getfreediskstorageold-number}
v1.1.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
레거시 Android API로 남은 디스크 공간을 읽습니다.
```typescript
const freeDiskOld = DeviceInfoModule.getFreeDiskStorageOld();
// Android: Uses old StatFs API (pre-Jelly Bean compatibility)
// iOS: Alias to getFreeDiskStorage()
```
***
### 지원하지 않는 호환 속성 \{#unsupported-compatibility-properties}
API 호환성을 위해 유지하는 속성입니다. 이 패키지에는 Windows 네이티브 타깃이 없습니다. iOS, Android, 웹에서 고정 기본값을 반환합니다.
| 속성 | 지원 여부 | 기본값 |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| `isMouseConnected` | v1.2.0부터 iOS: fallback 값 Android: fallback 값 웹: fallback 값 | `false` |
| `isKeyboardConnected` | v1.2.0부터 iOS: fallback 값 Android: fallback 값 웹: fallback 값 | `false` |
| `hostNames` | v1.2.0부터 iOS: fallback 값 Android: fallback 값 웹: fallback 값 | `[]` |
| `isTabletMode` | v1.2.0부터 iOS: fallback 값 Android: fallback 값 웹: fallback 값 | `false` |
***
## 성능 참고 사항 \{#performance-notes}
동기 속성과 메서드는 호출한 스레드에서 실행합니다. 일부 API는 OS를 조회하거나 캐시를 초기화하므로 동기 호출이 즉시 완료된다는 뜻은 아닙니다.
Promise 메서드는 완료 시간을 보장하지 않습니다. iOS의 `getUserAgent()`는 처음 성공하는 호출에서 WebView를 초기화하고 결과를 캐시합니다. 렌더링 중 비용이 큰 API를 반복 호출하지 마세요.
### 캐시 \{#caching}
다음 동기 메서드는 5초 캐시를 사용합니다.
- `getIpAddressSync()`
- `getMacAddressSync()`
- `getCarrierSync()`
캐시를 갱신할 때 OS를 조회합니다. 만료 후 다음 호출까지 이전 값이 남을 수 있습니다. 계속 바뀌는 배터리·오디오 상태에는 [React 훅](/react-native-nitro-device-info/ko/api/hooks.md)을 사용하세요.
실제 앱의 기기, OS, 빌드 모드, 캐시 상태에서 지연 시간을 측정하세요.
***
## 플랫폼 호환성 \{#platform-compatibility-matrix}
같은 범주에 있는 속성·메서드도 지원 여부가 다릅니다. 각 API나 속성 묶음 옆의 배지를 확인하세요. [배지 정의](/react-native-nitro-device-info/ko/api/index.md#availability-badges)와 [웹 제한](/react-native-nitro-device-info/ko/guide/web-support.md)을 참고하세요.
***
## 다음 단계 \{#next-steps}
- [타입 정의](/react-native-nitro-device-info/ko/api/types.md)에서 TypeScript 타입 확인
- [사용 예제](/react-native-nitro-device-info/ko/examples/basic-usage.md) 확인
- `react-native-device-info`에서 전환하려면 [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md) 확인
---
url: /react-native-nitro-device-info/ko/api/device-integrity.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 기기 무결성 API \{#device-integrity-api}
Android 루팅 또는 iOS 탈옥 기기를 탐지하는 **로컬 전용** 무결성 검사 API입니다.
:::tip 서버에서 검증하는 device attestation이 필요한가요?
이 로컬 검사는 우회할 수 있습니다. 하드웨어 기반 토큰을 서버에서 검증하는 device attestation(Play Integrity / App Attest)이 필요하면 [device attestation API](/react-native-nitro-device-info/ko/api/device-attestation.md)를 참고하세요. 별도 선택 패키지로 로컬 검사를 보완합니다. 로컬 검사는 빠른 오프라인 사전 필터로, attestation은 서버가 신뢰 여부를 판단하는 기준으로 사용하세요.
:::
## 개요 \{#overview}
이 API는 서버에서 검증하지 않고 파일 시스템 검사, 패키지 감지 같은 **로컬 탐지만** 수행합니다. 다음과 같은 앱에서 다층 방어의 한 수단으로 사용할 수 있습니다.
- 금융·은행 앱
- 민감한 데이터를 다루는 의료 앱
- 기업용 MDM 솔루션
- DRM이 필요한 앱
:::warning 제한 사항
**모든 탐지 방식은 로컬 전용이며** Magisk + Shamiko, RootHide, PlayIntegrityFix 같은 도구로 **우회할 수 있습니다**.
- **탐지하지 못했다고 기기가 안전하다는 뜻은 아닙니다.**
- Play Integrity API나 iOS App Attest를 사용하지 않습니다.
- 유일한 보안 수단이 아니라 다층 방어의 한 수단으로 사용하세요.
:::
[지원 여부 배지 설명](/react-native-nitro-device-info/ko/api/index.md#availability-badges)을 읽으세요. 두 API는 핵심 패키지에 속하며 웹에서는 fallback 값만 반환합니다.
## API 레퍼런스 \{#api-reference}
### `isDeviceCompromised()` \{#isdevicecompromised}
v1.4.2부터 iOS 15.1+ Android API 24+ 웹: fallback 값
루팅(Android) 또는 탈옥(iOS) 여부를 동기로 검사합니다.
```typescript
isDeviceCompromised(): boolean
```
**반환값:** 루팅·탈옥 등 보안 침해 징후를 탐지하면 `true`, 그 외 `false`
**성능:** \<50ms
**에뮬레이터 정책:** 개발 편의를 위해 에뮬레이터·시뮬레이터에서는 `false`를 반환합니다.
***
### `verifyDeviceIntegrity()` \{#verifydeviceintegrity}
v1.4.2부터 iOS 15.1+ Android API 24+ 웹: fallback 값
기기 무결성 검사의 비동기 래퍼입니다.
```typescript
verifyDeviceIntegrity(): Promise
```
**반환값:** 루팅·탈옥을 탐지하면 `true`로 resolve되는 Promise
**성능:**
- iOS: 최대 200ms(SSH 포트 검사 포함)
- Android: \<50ms(`isDeviceCompromised()`의 비동기 래퍼)
**플랫폼 차이:**
- **iOS:** `isDeviceCompromised()`의 모든 검사에 SSH 포트 검사(22, 44)를 추가합니다. 탈옥 도구가 설치한 OpenSSH를 탐지할 수 있습니다.
- **Android:** API 형태를 맞추기 위해 비동기 래퍼로 제공하며 검사는 `isDeviceCompromised()`와 같습니다.
**에뮬레이터 정책:** 에뮬레이터·시뮬레이터에서는 `false`를 반환합니다.
## 탐지 방식 \{#detection-methods}
### Android \{#android}
| 방식 | 우선순위 | 설명 |
| ----------- | ---- | ------------------------------------------------- |
| su 바이너리 | 높음 | `/system/xbin/su`, `/system/bin/su`, `/sbin/su` 등 |
| Magisk | 높음 | `/data/adb/magisk`, Magisk Manager 패키지 |
| KernelSU | 높음 | `/data/adb/ksu`, KernelSU Manager 패키지 |
| APatch | 높음 | `/data/adb/apatch`, APatch Manager 패키지 |
| Busybox | 중간 | `/system/xbin/busybox` |
| 빌드 속성 | 중간 | `ro.debuggable=1`, `ro.secure=0`, test-keys |
| Superuser 앱 | 낮음 | 기존 SuperSU, Superuser.apk |
### iOS \{#ios}
| 방식 | 설명 |
| --------- | --------------------------------------------- |
| 탈옥 앱 | Cydia, Sileo, Zebra, Installer 5 |
| URL 스킴 | `cydia://`, `sileo://`, `zbra://`, `filza://` |
| 시스템 파일 쓰기 | `/private/jailbreak.txt` 쓰기 검사 |
| DYLD 주입 | MobileSubstrate, libhooker, TweakInject |
| 심볼릭 링크 | `/Applications`, `/Library/Ringtones` |
| SSH 포트 | 포트 22(OpenSSH), 포트 44(checkra1n) |
## 사용 예제 \{#usage-examples}
### 기본 검사 \{#basic-check}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function SecurityCheck() {
const isCompromised = DeviceInfoModule.isDeviceCompromised();
if (isCompromised) {
return ;
}
return ;
}
```
### 금융 앱 보호 \{#financial-app-protection}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
async function performTransaction(amount: number) {
// Use async API for enhanced verification
const isCompromised = await DeviceInfoModule.verifyDeviceIntegrity();
if (isCompromised) {
throw new Error('Transaction blocked: Device integrity check failed');
}
// Proceed with transaction
return processPayment(amount);
}
```
### 조건에 따른 기능 접근 \{#conditional-feature-access}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function DeviceAuthenticationLogin() {
const isSecure = !DeviceInfoModule.isDeviceCompromised();
const hasDeviceAuthentication = DeviceInfoModule.isPinOrFingerprintSet;
if (!isSecure) {
// Fall back to password-only login on compromised devices
return ;
}
if (hasDeviceAuthentication) {
return ;
}
return ;
}
```
## 플랫폼 지원 \{#platform-support}
| API | iOS | Android |
| ------------------------- | ------------- | ---------- |
| `isDeviceCompromised()` | ✅ | ✅ |
| `verifyDeviceIntegrity()` | ✅ (SSH 검사 추가) | ✅ (비동기 래퍼) |
## 권장 사용법 \{#best-practices}
1. **탐지에만 의존하지 마세요.** 다층 방어의 한 수단으로 사용하세요.
2. **실패를 처리하세요.** 앱을 강제 종료하지 말고 대체 흐름을 제공하세요.
3. **분석할 수 있도록 기록하세요.** 보안 분석에 사용할 탐지율을 확인하세요.
4. **실제 기기에서 테스트하세요.** 에뮬레이터는 항상 `false`를 반환합니다.
5. **정기적으로 갱신하세요.** 새로운 루팅 도구가 계속 등장합니다.
## 관련 문서 \{#see-also}
- [device attestation](/react-native-nitro-device-info/ko/api/device-attestation.md)
- [isEmulator](/react-native-nitro-device-info/ko/api/device-info.md#isemulator-boolean)
- [isPinOrFingerprintSet](/react-native-nitro-device-info/ko/api/device-info.md#ispinorfingerprintset-boolean)
---
url: /react-native-nitro-device-info/ko/api/hooks.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# React 훅 \{#react-hooks}
앱 실행 중 기기 속성의 변화를 관찰하는 React 훅입니다. 네이티브 getter를 폴링하고 읽은 값이 바뀌면 다시 렌더링합니다. [갱신 간격과 초기값](/react-native-nitro-device-info/ko/guide/react-hooks.md#update-intervals-and-initial-values)을 참고하세요.
7개 훅 모두 v1.4.0에 도입했습니다. 네이티브 최소 버전은 iOS 15.1과 Android API 24입니다. 웹은 v1.8.0 이상이 필요합니다. [지원 여부 배지](/react-native-nitro-device-info/ko/api/index.md#availability-badges)를 참고하세요.
이 페이지는 패키지 루트에서 export하는 훅을 설명합니다. `/compat`의 헤드폰 훅은 `boolean` 대신 `{ loading, result }`를 반환합니다.
## import \{#import}
```typescript
import {
useBatteryLevel,
useBatteryLevelIsLow,
usePowerState,
useIsHeadphonesConnected,
useIsWiredHeadphonesConnected,
useIsBluetoothHeadphonesConnected,
useBrightness,
} from 'react-native-nitro-device-info';
```
***
## 배터리 훅 \{#battery-hooks}
### `useBatteryLevel()` \{#usebatterylevel}
v1.4.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
마운트 후 배터리 잔량을 읽고 5초마다 폴링합니다.
```typescript
function useBatteryLevel(): number | null
```
**반환값**: 배터리 잔량(0.0\~1.0). 초기 로딩 중이거나 조회할 수 없으면 `null`입니다.
**예제**:
```tsx
import { useBatteryLevel } from 'react-native-nitro-device-info';
function BatteryIndicator() {
const batteryLevel = useBatteryLevel();
if (batteryLevel === null) {
return Loading...;
}
return Battery: {Math.round(batteryLevel * 100)}%;
}
```
***
### `useBatteryLevelIsLow()` \{#usebatterylevelislow}
v1.4.0부터 iOS 15.1+ Android API 24+ 웹: 제한적 지원
플랫폼별 임계값으로 배터리 부족 상태를 관찰합니다.
```typescript
function useBatteryLevelIsLow(): number | null
```
**반환값**: 임계값보다 낮으면 배터리 잔량을 반환합니다. 부족하지 않거나 조회할 수 없으면 `null`입니다. 배터리 잔량을 읽을 수 없을 때는 배터리 부족 경고를 발생시키지 않습니다.
**임계값**:
- **iOS**: 20%(iOS 저전력 모드 기준과 동일)
- **Android**: 15%(Android 배터리 부족 경고 기준과 동일)
**예제**:
```tsx
import { useBatteryLevelIsLow } from 'react-native-nitro-device-info';
function LowBatteryWarning() {
const lowBattery = useBatteryLevelIsLow();
if (lowBattery !== null) {
return (
Low Battery: {Math.round(lowBattery * 100)}%
);
}
return null;
}
```
***
### `usePowerState()` \{#usepowerstate}
v1.4.0부터 iOS 15.1+ Android API 24+: 제한적 지원 웹: 제한적 지원
배터리 잔량, 충전 상태, 저전력 모드 등 전체 전원 상태를 관찰합니다.
```typescript
function usePowerState(): Partial
```
Android에서 `lowPowerMode`는 항상 `false`입니다.
**반환값**: `Partial` 객체입니다. 모든 속성은 선택 사항이며 초기 로딩 중이거나 플랫폼에서 지원하지 않으면 `undefined`일 수 있습니다.
- `batteryLevel?: number`: 배터리 잔량(0.0\~1.0). 조회 불가 시 `-1`
- `batteryState?: BatteryState`: 충전 상태('unknown', 'unplugged', 'charging', 'full')
- `lowPowerMode?: boolean`: 저전력 모드가 켜져 있는지 여부(iOS 전용)
**예제**:
```tsx
import { usePowerState } from 'react-native-nitro-device-info';
function PowerStatus() {
const powerState = usePowerState();
const level = powerState.batteryLevel;
return (
Level: {level === undefined || level < 0
? 'Loading or unavailable'
: Math.round(level * 100) + '%'}
Status: {powerState.batteryState ?? 'unknown'}
Low Power: {powerState.lowPowerMode ? 'Yes' : 'No'}
);
}
```
***
## 헤드폰 훅 \{#headphone-hooks}
### `useIsHeadphonesConnected()` \{#useisheadphonesconnected}
v1.4.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
헤드폰 연결 상태를 관찰합니다(유선 또는 Bluetooth).
```typescript
function useIsHeadphonesConnected(): boolean
```
**반환값**: 헤드폰이 연결됐으면 `true`, 그 외 `false`입니다.
**예제**:
```tsx
import { useIsHeadphonesConnected } from 'react-native-nitro-device-info';
function AudioOutput() {
const headphonesConnected = useIsHeadphonesConnected();
return (
Audio: {headphonesConnected ? 'Headphones' : 'Speaker'}
);
}
```
***
### `useIsWiredHeadphonesConnected()` \{#useiswiredheadphonesconnected}
v1.4.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
유선 헤드폰 연결 상태를 관찰합니다.
```typescript
function useIsWiredHeadphonesConnected(): boolean
```
**반환값**: 유선 헤드폰이 연결됐으면 `true`, 그 외 `false`입니다.
**예제**:
```tsx
import { useIsWiredHeadphonesConnected } from 'react-native-nitro-device-info';
function WiredAudioStatus() {
const wiredConnected = useIsWiredHeadphonesConnected();
return (
);
}
```
***
### `useIsBluetoothHeadphonesConnected()` \{#useisbluetoothheadphonesconnected}
v1.4.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
Bluetooth 헤드폰·오디오 기기의 연결 상태를 관찰합니다.
```typescript
function useIsBluetoothHeadphonesConnected(): boolean
```
**반환값**: Bluetooth 오디오 기기가 연결됐으면 `true`, 그 외 `false`입니다.
**예제**:
```tsx
import { useIsBluetoothHeadphonesConnected } from 'react-native-nitro-device-info';
function BluetoothAudioStatus() {
const bluetoothConnected = useIsBluetoothHeadphonesConnected();
return (
);
}
```
***
## 디스플레이 훅 \{#display-hooks}
### `useBrightness()` \{#usebrightness}
v1.4.0부터 iOS 15.1+ Android: fallback 값 웹: fallback 값
화면 밝기 변화를 관찰합니다(iOS 전용).
```typescript
function useBrightness(): number | null
```
**반환값**:
- **iOS**: 밝기(0.0\~1.0). 초기 로딩 중에는 `null`
- **Android**: `-1`(미지원)
**예제**:
```tsx
import { useBrightness } from 'react-native-nitro-device-info';
import { Platform } from 'react-native';
function BrightnessIndicator() {
const brightness = useBrightness();
if (Platform.OS === 'android') {
return Brightness monitoring is iOS only;
}
if (brightness === null) {
return Loading...;
}
return Brightness: {Math.round(brightness * 100)}%;
}
```
***
## 플랫폼 지원 요약 \{#platform-support-summary}
| 훅 | iOS | Android |
| ----------------------------------- | --- | ------- |
| `useBatteryLevel` | ✅ | ✅ |
| `useBatteryLevelIsLow` | ✅ | ✅ |
| `usePowerState` | ✅ | ✅ |
| `useIsHeadphonesConnected` | ✅ | ✅ |
| `useIsWiredHeadphonesConnected` | ✅ | ✅ |
| `useIsBluetoothHeadphonesConnected` | ✅ | ✅ |
| `useBrightness` | ✅ | ❌ (-1) |
***
## 권장 사용법 \{#best-practices}
### 로딩 상태 처리 \{#handle-loading-states}
```tsx
const batteryLevel = useBatteryLevel();
if (batteryLevel === null) {
return ;
}
```
### 훅 값을 사용하는 컴포넌트에 React.memo 적용 \{#memoize-dependent-components}
```tsx
const BatteryIcon = React.memo(({ level }: { level: number }) => {
return ;
});
function Parent() {
const level = useBatteryLevel();
return level !== null && ;
}
```
### 플랫폼별 처리 \{#platform-specific-handling}
```tsx
import { Platform } from 'react-native';
function BrightnessControl() {
const brightness = useBrightness();
if (Platform.OS === 'android') {
return null; // Not supported on Android
}
return ;
}
```
***
## react-native-device-info에서 마이그레이션 \{#migration-from-react-native-device-info}
`react-native-device-info` 훅의 결과 형태를 유지하려면 `/compat`을 사용하세요.
```tsx
// Before (react-native-device-info)
import { useBatteryLevel } from 'react-native-device-info';
// After (compatibility entry point)
import { useBatteryLevel } from 'react-native-nitro-device-info/compat';
// Usage remains identical
const batteryLevel = useBatteryLevel();
```
자세한 내용은 [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md)를 참고하세요.
---
url: /react-native-nitro-device-info/ko/api/index.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# API 레퍼런스 개요 \{#api-reference-overview}
예제를 복사하기 전에 패키지 루트와 `/compat` 중 어떤 API를 사용할지 선택하세요. 두 API는 이름과 반환 타입이 다릅니다.
## 어떤 API를 import해야 하나요? \{#entry-points}
| import | 용도 | 예시 |
| ----------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------- |
| `react-native-nitro-device-info`의 `{ DeviceInfoModule }` | 네이티브 속성과 메서드 | `DeviceInfoModule.model` |
| `react-native-nitro-device-info/compat`의 `DeviceInfo` | `react-native-device-info` 15.x 형식의 함수 | `DeviceInfo.getModel()` |
| `react-native-nitro-device-info`의 `{ useBatteryLevel }` | 값을 반환하는 React 훅 | `number \| null` |
| `react-native-nitro-device-info/compat`의 `{ useIsHeadphonesConnected }` | 호환 훅 결과 | `{ loading, result }` |
| `react-native-nitro-device-integrity`의 `{ DeviceIntegrityModule }` | 백엔드에서 검증하는 device attestation | [device attestation](/react-native-nitro-device-info/ko/api/device-attestation.md) 참고 |
루트의 `DeviceInfo`는 TypeScript 타입이며 런타임에 사용하는 기본 객체가 아닙니다. 호환성 주의 사항은 [마이그레이션](/react-native-nitro-device-info/ko/api/migration.md)을 참고하세요.
## 지원 여부 배지 \{#availability-badges}
각 API 섹션에는 최초 도입 버전과 현재 플랫폼 동작을 표시합니다. 속성을 묶어 설명하는 표에는 각 행에 배지를 표시합니다.
v1.3.0부터 iOS 15.1+ Android API 24+ 웹: fallback 값
- **v…부터(Since)**: 이 멤버 이름과 속성·메서드 형태를 처음 배포한 버전입니다. 이전 릴리스는 반환 타입이나 동작이 다를 수 있습니다. 모든 플랫폼이 같은 릴리스에서 기능을 구현했다는 뜻은 아닙니다.
- **iOS / Android**: 동작하는 네이티브 구현을 뜻합니다. 숫자는 패키지 버전이 아닌 최소 OS 버전입니다. 플랫폼 배지 안의 별도 `v…부터(since v…)`는 실제 구현을 나중에 도입한 버전입니다. 현재 핵심 패키지는 iOS 15.1 이상과 Android API 24 이상이 필요합니다. 의존성에 따라 더 높은 최소 버전이 필요할 수 있습니다.
- **제한적 지원(Limited)**: 추정값, 제한된 구현, 브라우저 API 의존성을 뜻합니다. 사용 전에 해당 섹션의 제한을 읽으세요.
- **fallback**: 지원하지 않는 작업에서 고정 기본값을 반환합니다. **reject**는 해당 플랫폼에서 메서드의 Promise가 reject된다는 뜻입니다.
- **미배포(Unreleased)**: `main`에는 있지만 npm에 배포하지 않은 구현입니다. 버전 번호가 아닙니다.
웹용 entry point와 fallback 값은 **v1.8.0**부터 사용할 수 있습니다. `웹: 제한적 지원` 배지는 브라우저에서 값을 읽는다는 뜻입니다. 브라우저 권한, API 지원 여부, SSR에 따라 fallback 값을 반환할 수 있습니다. fallback 값이 네이티브 기능을 제공하지는 않습니다.
iOS의 카메라 감지와 기기 인증 구현은 v1.9.0부터 사용할 수 있습니다. v1.8.3까지의 핵심 패키지 릴리스에도 이름은 있지만 iOS에서는 상수를 반환합니다.
### 버전 근거 \{#version-evidence}
도입 버전은 [배포된 npm 버전과 `gitHead` 값](https://registry.npmjs.org/react-native-nitro-device-info)을 대조했습니다. 다음 소스 스냅샷에서 멤버 선언을 확인할 수 있습니다.
| 배포 버전 | 소스 |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| v0.1.0 | [초기 인터페이스](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/0.1.0/src/DeviceInfo.nitro.ts) |
| v1.1.0 | [확장 인터페이스](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.1.0/src/DeviceInfo.nitro.ts) |
| v1.2.0 | [속성 기반 인터페이스](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.2.0/src/DeviceInfo.nitro.ts) |
| v1.2.1 | [키 저장소와 Liquid Glass 선언](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.2.1/src/DeviceInfo.nitro.ts) |
| v1.3.0 | [런타임 getter 인터페이스](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.3.0/src/DeviceInfo.nitro.ts) |
| v1.4.0 | [React 훅 export](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.4.0/src/hooks/index.ts) |
| v1.4.2 | [로컬 무결성과 Expo Device 대응 선언](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.4.2/src/DeviceInfo.nitro.ts) |
| v1.5.0 | [통신사와 빌드 필드 선언](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.5.0/packages/react-native-nitro-device-info/src/DeviceInfo.nitro.ts) |
| v1.8.0 | [동작하는 iOS 비동기 래퍼](https://github.com/l2hyunwoo/react-native-nitro-device-info/commit/cb6eb026)와 [웹용 entry point](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/v1.8.0/packages/react-native-nitro-device-info/src/index.web.ts) |
## 작업별 네이티브 API \{#native-api-by-task}
다음 멤버는 `DeviceInfoModule`에 속합니다. 괄호가 있으면 메서드, 없으면 속성입니다.
| 작업 | 주요 멤버 | 레퍼런스 |
| --------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| 모델과 OS 확인 | `deviceId`, `model`, `systemVersion`, `deviceType` | [기본 기기 정보](/react-native-nitro-device-info/ko/api/device-info.md#core-device-information-9-apis) |
| 식별자 읽기 | `uniqueId`, `manufacturer`, `deviceName` | [기본 기기 정보](/react-native-nitro-device-info/ko/api/device-info.md#core-device-information-9-apis) |
| 하드웨어 확인 | `isTablet`, `isEmulator`, `isCameraPresent`, `isPinOrFingerprintSet` | [기기 기능](/react-native-nitro-device-info/ko/api/device-info.md#device-capabilities-7-apis) |
| 디스플레이 정보 읽기 | `getHasNotch()`, `getHasDynamicIsland()`, `getIsLandscape()`, `getBrightness()` | [디스플레이와 화면](/react-native-nitro-device-info/ko/api/device-info.md#display--screen-7-apis) |
| 메모리와 저장 공간 읽기 | `totalMemory`, `getUsedMemory()`, `totalDiskCapacity`, `getFreeDiskStorage()` | [시스템 리소스](/react-native-nitro-device-info/ko/api/device-info.md#system-resources-7-apis) |
| 배터리 상태 읽기 | `getBatteryLevel()`, `getPowerState()`, `getIsBatteryCharging()` | [배터리와 전원](/react-native-nitro-device-info/ko/api/device-info.md#battery--power-4-apis) |
| 앱 메타데이터 읽기 | `version`, `buildNumber`, `bundleId`, `getFirstInstallTime()` | [앱 메타데이터](/react-native-nitro-device-info/ko/api/device-info.md#application-metadata-9-apis) |
| 네트워크 정보 읽기 | `getIpAddress()`, `getIpAddressSync()`, `getMacAddress()` | [네트워크](/react-native-nitro-device-info/ko/api/device-info.md#network-6-apis) |
| 통신사 정보 읽기 | `getCarrier()`, `getCarrierSync()`, `mobileCountryCode` | [통신사 정보](/react-native-nitro-device-info/ko/api/device-info.md#carrier-information-7-apis) |
| 오디오 출력 확인 | `isHeadphonesConnected()`, `getIsWiredHeadphonesConnected()` | [오디오 기기](/react-native-nitro-device-info/ko/api/device-info.md#audio-accessories-4-apis) |
| 위치 서비스 확인 | `isLocationEnabled()`, `getIsLocationEnabled()`, `getAvailableLocationProviders()` | [위치 서비스](/react-native-nitro-device-info/ko/api/device-info.md#location-services-3-apis) |
| Android 기능 확인 | `apiLevel`, `getHasGms()`, `getHasHms()`, `hasSystemFeature(feature)` | [Android 플랫폼](/react-native-nitro-device-info/ko/api/device-info.md#android-platform-20-apis) |
| Apple DeviceCheck 요청 또는 Keychain에 ID 기록 | `getDeviceToken()`, `syncUniqueId()` | [iOS 플랫폼](/react-native-nitro-device-info/ko/api/device-info.md#ios-platform-2-apis) |
| 설치 정보 읽기 | `installerPackageName`, `getInstallReferrer()`, `isSideLoadingEnabled()` | [설치와 배포](/react-native-nitro-device-info/ko/api/device-info.md#installation--distribution-3-apis) |
나머지 멤버는 [전체 DeviceInfo 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md)를 참고하세요.
## 속성·메서드·훅은 어떻게 사용하나요? \{#call-and-return-contracts}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
const model: string = DeviceInfoModule.model;
const battery: number = DeviceInfoModule.getBatteryLevel();
async function readIpAddress(): Promise {
return await DeviceInfoModule.getIpAddress();
}
```
- **속성**: 괄호 없이 읽습니다. 속성도 OS를 조회할 수 있습니다. `readonly`가 상수라는 뜻은 아닙니다.
- **동기 메서드**: 직접 호출합니다. 동기 실행이 고정 지연 시간을 보장하지는 않습니다.
- **Promise 메서드**: 비동기 함수에서 await로 결과를 기다리고 실패할 수 있는 API의 reject를 처리하세요.
- **React 훅**: React 컴포넌트 또는 커스텀 훅 안에서 호출하세요. 초기값과 폴링 간격은 [훅 API](/react-native-nitro-device-info/ko/api/hooks.md)를 참고하세요.
메모리와 저장 공간 단위는 바이트입니다. 배터리와 밝기는 조회할 수 있을 때 `0`\~`1`의 비율입니다. 예를 들어 배터리 잔량을 읽을 수 없으면 `getBatteryLevel()`은 `-1`, `useBatteryLevel()`은 `null`을 반환합니다.
## 플랫폼과 보안 제한 \{#platform-and-security-limits}
지원하지 않는 API는 fallback 값을 반환하거나 reject될 수 있습니다. `false`는 플랫폼에 구현이 없다는 뜻일 수도 있습니다. 개별 API와 [웹 지원 가이드](/react-native-nitro-device-info/ko/guide/web-support.md)를 확인하세요.
이 패키지의 [로컬 기기 무결성 검사](/react-native-nitro-device-info/ko/api/device-integrity.md)는 특정 징후로 판단하는 검사이며 우회할 수 있습니다. [device attestation](/react-native-nitro-device-info/ko/api/device-attestation.md)은 별도 `react-native-nitro-device-integrity` 패키지와 백엔드 검증이 필요합니다.
## 타입과 소스 \{#types-and-source}
`DeviceInfo`, `PowerState`, `BatteryState`, `DeviceType`, `NavigationMode`는 `import type`으로 import하세요. [타입 정의](/react-native-nitro-device-info/ko/api/types.md)를 참고하세요.
현재 웹사이트는 레포지터리의 `main` 브랜치를 기준으로 작성합니다. 이전 릴리스를 설치했다면 해당 릴리스의 선언을 확인하세요. API 시그니처의 원본은 [`DeviceInfo.nitro.ts`](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/main/packages/react-native-nitro-device-info/src/DeviceInfo.nitro.ts)이며 네이티브 구현이 플랫폼 동작을 정의합니다.
---
url: /react-native-nitro-device-info/ko/api/migration.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 마이그레이션 가이드 \{#migration-guide}
`react-native-device-info`에서 `react-native-nitro-device-info`로 전환하는 방법입니다.
## 개요 \{#overview}
`react-native-nitro-device-info`는 `react-native-device-info`(RNDI) 15.x와 같은 함수 이름, 시그니처, 기본 `DeviceInfo` 객체, 훅을 제공하는 **호환 계층**이 있습니다. `react-native-device-info` 대신 `react-native-nitro-device-info/compat`에서 import하면 **호출 코드는 유지할 수 있습니다**.
어디까지 바꿀지에 따라 호환 API와 네이티브 API 중 하나를 선택하세요.
| 경로 | 작업량 | 결과 |
| ---------------- | -------------------- | --------------------------------------- |
| **호환 API(권장)** | 명령 하나로 import 경로만 변경 | 호출 코드 유지. fallback 값과 플랫폼 차이는 확인해야 합니다. |
| **네이티브 API(선택)** | 호출 코드 수동 변경 | 속성을 직접 읽고 동기 getter 사용 |
호환 API부터 사용하세요. 필요하면 나중에 개별 호출을 네이티브 API로 옮길 수 있습니다. 두 API를 함께 사용할 수 있습니다.
## 호환 API로 마이그레이션하기(권장) \{#drop-in-migration-recommended}
### 1. 설치 \{#1-install}
```bash
# Install the new library + its peer dependency
npm install react-native-nitro-device-info react-native-nitro-modules
# (or: yarn add react-native-nitro-device-info react-native-nitro-modules)
# iOS
cd ios && pod install && cd ..
```
### 2. codemod 실행 \{#2-run-the-codemod}
라이브러리에 포함된 codemod는 모든 `react-native-device-info` import를 `react-native-nitro-device-info/compat`으로 바꿉니다. **import 경로만 수정**하며 호출 코드는 바꾸지 않습니다.
```bash
npx react-native-nitro-device-info migrate
# or target a specific directory:
npx react-native-nitro-device-info migrate src
```
ES import(default, named, namespace), re-export, CommonJS `require()`를 바꿉니다.
```typescript
// Before
import DeviceInfo from 'react-native-device-info';
import { getModel, useBatteryLevel } from 'react-native-device-info';
// After (rewritten automatically — call sites unchanged)
import DeviceInfo from 'react-native-nitro-device-info/compat';
import { getModel, useBatteryLevel } from 'react-native-nitro-device-info/compat';
```
수동으로 작업한다면 프로젝트 전체에서 import 문자열 `'react-native-device-info'`를 `'react-native-nitro-device-info/compat'`으로 바꿔도 같은 결과를 얻습니다.
### 3. 이전 의존성 제거 \{#3-remove-the-old-dependency}
```bash
npm uninstall react-native-device-info
```
### 4. 문서의 주의 사항 확인 \{#4-review-the-documented-caveats}
호환 계층은 **RNDI 15.x API**를 대상으로 합니다. 이 라이브러리에 네이티브 대응 기능이 없는 일부 API는 fallback 값을 반환합니다. 아래 [호환 계층 주의 사항](#compat-layer-caveats)을 확인하세요. 앱에서 이 API를 쓰지 않으면 전환이 완료됩니다.
호출 코드를 바꾸거나 `await`를 추가·제거할 필요가 없습니다.
## 호환 계층 주의 사항 \{#compat-layer-caveats}
호환 계층은 다음 예외를 포함해 RNDI 전체 API의 시그니처에 맞춥니다.
| API | 호환 계층 동작 | 이유 |
| ----------------------------------------- | --------------------------------- | --------------------------------------------------------------------- |
| `getInstanceId()` / `getInstanceIdSync()` | `'unknown'` 반환 | RNDI에서 사용 중단 예정입니다(Firebase/GMS Instance ID 제거 예정). 네이티브 대응 기능이 없습니다. |
| `getAppSetId()` | `{ id: 'unknown', scope: -1 }` 반환 | 선택 의존성 Play Services App Set이 없을 때 RNDI가 반환하는 값과 같습니다. |
| `getUserAgentSync()` | `''` 반환 | 사용자 에이전트를 비동기로 계산합니다(iOS WebView). 실제 값은 비동기 `getUserAgent()`를 사용하세요. |
| `getInstallReferrerSync()` | `'unknown'` 반환 | 설치 리퍼러는 비동기로만 읽을 수 있습니다. `getInstallReferrer()`를 사용하세요. |
다른 API는 이 라이브러리의 네이티브 구현에 위임합니다. 플랫폼별 fallback 값을 반환하거나 RNDI와 다르게 동작할 수 있습니다. 일부 결과 형태는 자동 변환합니다. 예를 들어 `getAvailableLocationProviders()`는 RNDI의 `{ gps: true, network: true }` 맵을 반환합니다. `getFreeDiskStorage(storageType?)`는 iOS 저장 공간 타입 인자를 받지만 무시합니다. 비동기 오디오 기기 훅은 RNDI의 `{ loading, result }` 형태를 반환합니다.
## 네이티브 API로 전환하기(선택사항) \{#native-migration-optional-for-maximum-performance}
호환 계층 대신 속성을 직접 읽고 동기 getter를 사용하려면 패키지 루트에서 `DeviceInfoModule`을 import하고 아래 표에 따라 호출 코드를 바꾸세요.
### 주요 차이 \{#key-differences}
**구조**
- **react-native-device-info**: 설치한 릴리스에 따라 API와 구현이 다릅니다.
- **react-native-nitro-device-info**: Nitro HybridObject(JSI)를 사용합니다.
**속성과 메서드**: 대부분의 RNDI 메서드는 직접 읽는 속성으로 바뀝니다.
```typescript
// react-native-device-info // native API
const deviceId = DeviceInfo.getDeviceId(); const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfo.getBrand(); const brand = DeviceInfoModule.brand;
```
**기본 동기 호출**: RNDI에서 비동기였던 값이 동기로 바뀝니다.
```typescript
const uniqueId = DeviceInfoModule.uniqueId; // sync property
const totalMemory = DeviceInfoModule.totalMemory; // sync property
const batteryLevel = DeviceInfoModule.getBatteryLevel(); // sync method
const isTablet = DeviceInfoModule.isTablet; // sync property
```
**Promise 메서드는 여전히 `await`가 필요합니다**.
```typescript
const ipAddress = await DeviceInfoModule.getIpAddress();
const carrier = await DeviceInfoModule.getCarrier();
const installTime = await DeviceInfoModule.getFirstInstallTime();
```
### 빠른 대응표 \{#quick-migration-reference}
### 기기 정보 \{#device-information}
| react-native-device-info | `react-native-nitro-device-info` | 참고 |
| -------------------------------- | -------------------------------- | ---------- |
| `DeviceInfo.getDeviceId()` | `DeviceInfoModule.deviceId` | 속성으로 변경 |
| `DeviceInfo.getBrand()` | `DeviceInfoModule.brand` | 속성으로 변경 |
| `DeviceInfo.getModel()` | `DeviceInfoModule.model` | 속성으로 변경 |
| `DeviceInfo.getSystemName()` | `DeviceInfoModule.systemName` | 속성으로 변경 |
| `DeviceInfo.getSystemVersion()` | `DeviceInfoModule.systemVersion` | 속성으로 변경 |
| `await DeviceInfo.getUniqueId()` | `DeviceInfoModule.uniqueId` | 동기 속성으로 변경 |
| `DeviceInfo.getManufacturer()` | `DeviceInfoModule.manufacturer` | 속성으로 변경 |
| `DeviceInfo.isTablet()` | `DeviceInfoModule.isTablet` | 속성으로 변경 |
### 시스템 리소스 \{#system-resources}
| react-native-device-info | `react-native-nitro-device-info` | 참고 |
| ----------------------------------------- | --------------------------------------- | ---------- |
| `await DeviceInfo.getTotalMemory()` | `DeviceInfoModule.totalMemory` | 동기 속성으로 변경 |
| `await DeviceInfo.getUsedMemory()` | `DeviceInfoModule.getUsedMemory()` | 동기 메서드로 변경 |
| `await DeviceInfo.getTotalDiskCapacity()` | `DeviceInfoModule.totalDiskCapacity` | 동기 속성으로 변경 |
| `await DeviceInfo.getFreeDiskStorage()` | `DeviceInfoModule.getFreeDiskStorage()` | 동기 메서드로 변경 |
### 배터리 정보 \{#battery-information}
| react-native-device-info | `react-native-nitro-device-info` | 참고 |
| -------------------------------------- | ----------------------------------------- | ---------- |
| `await DeviceInfo.getBatteryLevel()` | `DeviceInfoModule.getBatteryLevel()` | 동기 메서드로 변경 |
| `await DeviceInfo.getPowerState()` | `DeviceInfoModule.getPowerState()` | 동기 메서드로 변경 |
| `await DeviceInfo.isBatteryCharging()` | `DeviceInfoModule.getIsBatteryCharging()` | 동기 메서드로 변경 |
### 앱 메타데이터 \{#application-metadata}
| react-native-device-info | `react-native-nitro-device-info` | 참고 |
| --------------------------------- | ---------------------------------- | ------- |
| `DeviceInfo.getVersion()` | `DeviceInfoModule.version` | 속성으로 변경 |
| `DeviceInfo.getBuildNumber()` | `DeviceInfoModule.buildNumber` | 속성으로 변경 |
| `DeviceInfo.getBundleId()` | `DeviceInfoModule.bundleId` | 속성으로 변경 |
| `DeviceInfo.getApplicationName()` | `DeviceInfoModule.applicationName` | 속성으로 변경 |
| `DeviceInfo.getReadableVersion()` | `DeviceInfoModule.readableVersion` | 속성으로 변경 |
### 네트워크와 연결 \{#network--connectivity}
| react-native-device-info | `react-native-nitro-device-info` | 참고 |
| -------------------------------------- | -------------------------------------------- | ----------- |
| `await DeviceInfo.getIpAddress()` | `await DeviceInfoModule.getIpAddress()` | 비동기 유지(I/O) |
| `await DeviceInfo.getMacAddress()` | `await DeviceInfoModule.getMacAddress()` | 비동기 유지(I/O) |
| `await DeviceInfo.getCarrier()` | `await DeviceInfoModule.getCarrier()` | 비동기 유지(I/O) |
| `await DeviceInfo.isLocationEnabled()` | `await DeviceInfoModule.isLocationEnabled()` | 비동기 유지(I/O) |
### 네이티브 API로 전환하는 순서 \{#step-by-step-native-path}
> 네이티브 API로 전환하는 절차입니다. 호출 코드를 유지하려면 [호환 API 마이그레이션](#drop-in-migration-recommended)을 사용하세요.
#### 1. 새 라이브러리 설치 \{#1-install-the-new-library}
```bash
# Remove old library
npm uninstall react-native-device-info
# Install new library
npm install react-native-nitro-device-info react-native-nitro-modules
# iOS
cd ios && pod install && cd ..
```
#### 2. import 수정 \{#2-update-imports}
코드 전체에서 import를 찾아 바꾸세요.
```typescript
// Before
import DeviceInfo from 'react-native-device-info';
// After
import { DeviceInfoModule } from 'react-native-nitro-device-info';
```
#### 3. 모듈 이름 수정 \{#3-update-module-name}
모든 `DeviceInfo` 참조를 `DeviceInfoModule`로 바꾸세요.
```typescript
// Before
const brand = DeviceInfo.getBrand();
// After
const brand = DeviceInfoModule.brand; // Also changed to property
```
#### 4. 메서드 호출을 속성 접근으로 변경 \{#4-convert-method-calls-to-properties}
메서드가 속성으로 바뀌었다면 호출 대신 속성을 읽도록 수정하세요.
```typescript
// Before
const deviceId = DeviceInfo.getDeviceId();
const brand = DeviceInfo.getBrand();
const model = DeviceInfo.getModel();
const systemName = DeviceInfo.getSystemName();
const systemVersion = DeviceInfo.getSystemVersion();
const readableVersion = DeviceInfo.getReadableVersion();
// After
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const systemName = DeviceInfoModule.systemName;
const systemVersion = DeviceInfoModule.systemVersion;
const readableVersion = DeviceInfoModule.readableVersion;
```
#### 5. 불필요한 `await` 제거 \{#5-remove-unnecessary-await-keywords}
동기로 바뀐 메서드의 `await`를 제거하세요.
```typescript
// Before
const uniqueId = await DeviceInfo.getUniqueId();
const totalMemory = await DeviceInfo.getTotalMemory();
const batteryLevel = await DeviceInfo.getBatteryLevel();
// After (no await needed, now sync properties/methods)
const uniqueId = DeviceInfoModule.uniqueId;
const totalMemory = DeviceInfoModule.totalMemory;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
```
#### 6. 변경 테스트 \{#6-test-your-changes}
앱을 실행하고 확인하세요.
- 모든 기기 정보 호출의 정상 동작
- 비동기·동기 변경으로 인한 런타임 오류 여부
- TypeScript 타입의 정확성
## 전체 예제 \{#complete-example}
### 변경 전(react-native-device-info) \{#before-react-native-device-info}
```typescript
import React, { useEffect, useState } from 'react';
import DeviceInfo from 'react-native-device-info';
function DeviceInfoScreen() {
const [deviceId, setDeviceId] = useState('');
const [brand, setBrand] = useState('');
const [uniqueId, setUniqueId] = useState('');
const [totalMemory, setTotalMemory] = useState(0);
const [batteryLevel, setBatteryLevel] = useState(0);
const [ipAddress, setIpAddress] = useState('');
useEffect(() => {
async function loadDeviceInfo() {
// Everything was async or method-based
const id = DeviceInfo.getDeviceId();
const b = DeviceInfo.getBrand();
const uid = await DeviceInfo.getUniqueId();
const mem = await DeviceInfo.getTotalMemory();
const bat = await DeviceInfo.getBatteryLevel();
const ip = await DeviceInfo.getIpAddress();
setDeviceId(id);
setBrand(b);
setUniqueId(uid);
setTotalMemory(mem);
setBatteryLevel(bat);
setIpAddress(ip);
}
loadDeviceInfo();
}, []);
return (
Device: {brand} {deviceId}
Unique ID: {uniqueId}
Memory: {totalMemory}
Battery: {batteryLevel < 0 ? 'Unavailable' : `${(batteryLevel * 100).toFixed(0)}%`}
IP: {ipAddress}
);
}
```
### 변경 후(`react-native-nitro-device-info`) \{#after-react-native-nitro-device-info}
```typescript
import React, { useEffect, useState } from 'react';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function DeviceInfoScreen() {
const [ipAddress, setIpAddress] = useState('');
// Sync properties/methods - instant access, no state needed
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const uniqueId = DeviceInfoModule.uniqueId;
const totalMemory = DeviceInfoModule.totalMemory;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
useEffect(() => {
// Only async operations need useEffect
DeviceInfoModule.getIpAddress().then(setIpAddress);
}, []);
return (
Device: {brand} {deviceId}
Unique ID: {uniqueId}
Memory: {totalMemory}
Battery: {batteryLevel < 0 ? 'Unavailable' : `${(batteryLevel * 100).toFixed(0)}%`}
IP: {ipAddress}
);
}
```
## 마이그레이션의 이점 \{#benefits-of-migration}
### 1. 성능 비교 \{#1-performance-improvement}
```typescript
// react-native-device-info: model and brand already return synchronously.
const brand = DeviceInfo.getBrand();
const model = DeviceInfo.getModel();
const memory = await DeviceInfo.getTotalMemory();
// Native API: direct properties; measure latency in your app.
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const memory = DeviceInfoModule.totalMemory;
```
### 2. 간단한 코드 \{#2-simpler-code}
단순 getter에는 `async`/`await`가 필요하지 않습니다.
```typescript
// Old - required async function
async function getDeviceInfo() {
const brand = DeviceInfo.getBrand();
const model = DeviceInfo.getModel();
return `${brand} ${model}`;
}
// New - direct access
function getDeviceInfo() {
return `${DeviceInfoModule.brand} ${DeviceInfoModule.model}`;
}
```
### 3. TypeScript 지원 \{#3-better-typescript-support}
전체 타입 정의와 IntelliSense를 제공합니다.
```typescript
import type { PowerState, BatteryState } from 'react-native-nitro-device-info';
const powerState: PowerState = DeviceInfoModule.getPowerState();
// TypeScript knows: powerState.batteryLevel, powerState.batteryState, powerState.lowPowerMode
```
### 4. New Architecture 기반 구조 \{#4-future-proof-architecture}
장기 지원을 위해 React Native의 New Architecture(Fabric + JSI)를 사용합니다.
## React 훅 마이그레이션 \{#react-hooks-migration}
**호환 API:** 모든 RNDI 훅을 같은 시그니처로 re-export합니다. 비동기 훅의 `{ loading, result }` 형태도 포함합니다. codemod가 import를 수정하며 사용법은 같습니다.
```tsx
// Before
import { useBatteryLevel, useDeviceName } from 'react-native-device-info';
// After (rewritten to the compat subpath — usage identical)
import { useBatteryLevel, useDeviceName } from 'react-native-nitro-device-info/compat';
function BatteryWidget() {
const batteryLevel = useBatteryLevel(); // number | null
const { result: name } = useDeviceName(); // AsyncHookResult
return {name}: {batteryLevel};
}
```
**네이티브 API:** 패키지 루트에서는 `AsyncHookResult` 래퍼 없이 값 자체를 반환하는 훅 7개를 직접 export합니다. 호출 코드를 네이티브 API로 옮길 때 사용하세요.
| react-native-device-info | 패키지 루트의 훅 | 참고 |
| ------------------------------------- | ------------------------------------- | ---------------------------------------------- |
| `useBatteryLevel()` | `useBatteryLevel()` | 동일(`number \| null`) |
| `useBatteryLevelIsLow()` | `useBatteryLevelIsLow()` | 동일 |
| `usePowerState()` | `usePowerState()` | 동일 |
| `useIsHeadphonesConnected()` | `useIsHeadphonesConnected()` | `boolean` 반환(호환 계층은 `{ loading, result }`로 감쌈) |
| `useIsWiredHeadphonesConnected()` | `useIsWiredHeadphonesConnected()` | `boolean` 반환(호환 계층은 래퍼 사용) |
| `useIsBluetoothHeadphonesConnected()` | `useIsBluetoothHeadphonesConnected()` | `boolean` 반환(호환 계층은 래퍼 사용) |
| `useBrightness()` | `useBrightness()` | 동일(`number \| null`) |
나머지 RNDI 훅(`useFirstInstallTime`, `useDeviceName`, `useHasSystemFeature`, `useIsEmulator`, `useManufacturer`)은 **호환 API에서만** 제공하며 RNDI의 `AsyncHookResult` 형태를 반환합니다.
전체 훅 설명은 [React 훅 가이드](/react-native-nitro-device-info/ko/guide/react-hooks.md)를 참고하세요.
### 네이티브 API로 전환할 때 달라지는 동작 \{#behavioral-changes-native-path-only}
다음 차이는 **네이티브 API**(`DeviceInfoModule`)를 사용할 때 적용됩니다. 호환 계층은 함수 시그니처와 훅 결과 형태를 맞추지만 모든 플랫폼 동작을 재현하지는 않습니다. [호환 계층 주의 사항](#compat-layer-caveats)을 확인하세요.
1. **기본 동기 호출**: 대부분의 메서드는 더 이상 Promise를 반환하지 않습니다.
2. **속성 접근**: 일부 getter는 속성입니다.
3. **모듈 이름**: `DeviceInfo` 대신 `DeviceInfoModule`을 사용합니다.
4. **이벤트 리스너**: 원시 배터리·네트워크 상태 리스너를 export하지 않습니다. 상태 관찰에는 제공하는 React 훅(`useBatteryLevel`, `usePowerState` 등)을 사용하세요. 호환 계층은 RNDI 훅을 같은 형태로 re-export합니다.
## 문제 해결 \{#troubleshooting}
### 마이그레이션 후 TypeScript 오류 \{#typescript-errors-after-migration}
타입 오류가 발생하면 다음을 확인하세요.
```bash
# Clear TypeScript cache
rm -rf node_modules/.cache
yarn install
# Restart TypeScript server in your IDE
```
### 런타임 오류 \{#runtime-errors}
"Cannot read property" 오류가 발생하면 확인하세요.
1. peer dependencies `react-native-nitro-modules` 설치 여부
2. iOS의 `pod install` 실행 여부
3. 정리 후 빌드(`yarn android` / `yarn ios`)
### 메서드를 찾을 수 없는 경우 \{#missing-methods}
1. [API 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md)에서 정확한 메서드 이름을 확인하세요.
2. 일부 메서드는 이름이 바뀌거나 통합됐을 수 있습니다.
3. 필요한 메서드가 없으면 GitHub 이슈를 등록하세요.
***
## expo-device에서 마이그레이션 \{#migrating-from-expo-device}
`expo-device`의 여러 API에 대응하는 API를 `react-native-nitro-device-info`에서 제공합니다.
### 주요 차이 \{#key-differences-1}
| 항목 | expo-device | react-native-nitro-device-info |
| -------- | --------------- | ------------------------------ |
| 구조 | Expo Module API | Nitro Modules(JSI) |
| 동기/비동기 | 혼합(일부 비동기) | 대부분 동기 |
| Expo 의존성 | Expo 필요 | 일반 React Native에서 동작 |
| 성능 | 양호 | 직접 동기 접근. 앱에서 측정하세요. |
### API 대응표 \{#api-migration-reference}
| expo-device | react-native-nitro-device-info | 참고 |
| ------------------------------------ | ----------------------------------------- | ------------------ |
| `Device.brand` | `DeviceInfoModule.brand` | 동일 |
| `Device.manufacturer` | `DeviceInfoModule.manufacturer` | 동일 |
| `Device.modelName` | `DeviceInfoModule.model` | 속성 이름 다름 |
| `Device.modelId` | `DeviceInfoModule.deviceId` | 속성 이름 다름 |
| `Device.designName` | `DeviceInfoModule.device` | Android 전용 |
| `Device.productName` | `DeviceInfoModule.product` | Android 전용 |
| `Device.deviceYearClass` | `DeviceInfoModule.deviceYearClass` | 동일 |
| `Device.totalMemory` | `DeviceInfoModule.totalMemory` | 동일 |
| `Device.supportedCpuArchitectures` | `DeviceInfoModule.supportedAbis` | Android 전용 |
| `Device.osName` | `DeviceInfoModule.systemName` | 속성 이름 다름 |
| `Device.osVersion` | `DeviceInfoModule.systemVersion` | 속성 이름 다름 |
| `Device.osBuildId` | `DeviceInfoModule.display` | Android 전용 |
| `Device.osInternalBuildId` | `DeviceInfoModule.fingerprint` | Android 전용 |
| `Device.osBuildFingerprint` | `DeviceInfoModule.fingerprint` | Android 전용 |
| `Device.platformApiLevel` | `DeviceInfoModule.apiLevel` | Android 전용 |
| `Device.deviceName` | `DeviceInfoModule.deviceName` | 동일 |
| `Device.DeviceType` | `DeviceInfoModule.deviceType` | 문자열 열거형 반환 |
| `Device.getDeviceTypeAsync()` | `DeviceInfoModule.deviceType` | 동기로 변경 |
| `Device.getUptimeAsync()` | `DeviceInfoModule.getUptime()` | 동기로 변경. 밀리초 반환 |
| `Device.isRootedExperimentalAsync()` | `DeviceInfoModule.isDeviceCompromised()` | 동기. 더 넓은 탐지 범위 |
| `Device.isSideLoadingEnabledAsync()` | `DeviceInfoModule.isSideLoadingEnabled()` | 동기로 변경. Android 전용 |
### 마이그레이션 예제 \{#migration-example}
**변경 전**(`expo-device`):
```typescript
import * as Device from 'expo-device';
async function getDeviceInfo() {
const deviceType = await Device.getDeviceTypeAsync();
const isRooted = await Device.isRootedExperimentalAsync();
const canSideload = await Device.isSideLoadingEnabledAsync();
return {
brand: Device.brand,
model: Device.modelName,
yearClass: Device.deviceYearClass,
totalMemory: Device.totalMemory,
deviceType,
isRooted,
canSideload,
};
}
```
**변경 후**(`react-native-nitro-device-info`):
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getDeviceInfo() {
// All synchronous - no async/await needed!
return {
brand: DeviceInfoModule.brand,
model: DeviceInfoModule.model,
yearClass: DeviceInfoModule.deviceYearClass,
totalMemory: DeviceInfoModule.totalMemory,
deviceType: DeviceInfoModule.deviceType,
isRooted: DeviceInfoModule.isDeviceCompromised(),
canSideload: DeviceInfoModule.isSideLoadingEnabled(),
};
}
```
### 제공하지 않는 API \{#apis-not-available}
다음 `expo-device` API에는 직접 대응하는 API가 없습니다.
| expo-device API | 대안 |
| ----------------------------------- | --------------------------------- |
| `Device.isDevice` | `!DeviceInfoModule.isEmulator` 사용 |
| `Device.getPlatformFeaturesAsync()` | 미지원 |
### 플랫폼별 주의 사항 \{#platform-specific-considerations}
#### 가동 시간 동작 \{#uptime-behavior}
iOS의 `getUptime()`은 앱 이벤트 시간 측정에만 지원합니다. 경과 시간 측정, 타이머, 또는 `startupTime`으로 앱 이벤트 uptime을 절대 타임스탬프로 변환하는 용도입니다. 원시 가동 시간과 부팅 타임스탬프는 일반 기기 정보 데이터에 포함하지 마세요. 선언한 목적과 전송 제한은 [iOS privacy info manifest](/react-native-nitro-device-info/ko/guide/getting-started.md#ios-privacy-manifest)를 참고하세요.
- **expo-device**: 깊은 절전을 제외한 가동 시간을 밀리초로 반환
- **react-native-nitro-device-info**: 깊은 절전을 제외한 가동 시간을 밀리초로 반환
- iOS: `systemUptime` 사용
- Android: `uptimeMillis()` 사용
- 두 플랫폼 모두 expo-device와 같은 활성 시간 반환
#### year class \{#device-year-class}
두 라이브러리는 RAM과 CPU 사양으로 year class를 계산하는 같은 Facebook 알고리즘을 사용합니다. year class는 하드웨어가 고급 사양으로 평가됐을 것으로 추정하는 연도입니다.
#### 루팅·탈옥 탐지 \{#rootjailbreak-detection}
- **expo-device**: `isRootedExperimentalAsync()` — 실험적 기본 검사
- **react-native-nitro-device-info**: `isDeviceCompromised()` — 종합 검사
- Android: su 바이너리, 루팅 앱, 시스템 속성, test-keys 검사
- iOS: Cydia, 탈옥 파일, 샌드박스 탈출, 의심 경로 검사
***
## react-native-carrier-info에서 마이그레이션 \{#migrating-from-react-native-carrier-info}
통신사 정보에 `react-native-carrier-info`를 사용하고 있다면 `react-native-nitro-device-info`로 통합할 수 있습니다.
### API 대응표 \{#api-migration-reference-1}
| react-native-carrier-info | react-native-nitro-device-info | 참고 |
| ------------------------------------------- | ---------------------------------------- | ---------- |
| `await CarrierInfo.allowsVOIP()` | `DeviceInfoModule.carrierAllowsVOIP` | 동기 속성으로 변경 |
| `await CarrierInfo.carrierName()` | `DeviceInfoModule.getCarrierSync()` | 동기 메서드로 변경 |
| `await CarrierInfo.isoCountryCode()` | `DeviceInfoModule.carrierIsoCountryCode` | 동기 속성으로 변경 |
| `await CarrierInfo.mobileCountryCode()` | `DeviceInfoModule.mobileCountryCode` | 동기 속성으로 변경 |
| `await CarrierInfo.mobileNetworkCode()` | `DeviceInfoModule.mobileNetworkCode` | 동기 속성으로 변경 |
| `await CarrierInfo.mobileNetworkOperator()` | `DeviceInfoModule.mobileNetworkOperator` | 동기 속성으로 변경 |
### 마이그레이션 예제 \{#migration-example-1}
**변경 전**(`react-native-carrier-info`):
```typescript
import CarrierInfo from 'react-native-carrier-info';
async function getCarrierDetails() {
const carrierName = await CarrierInfo.carrierName();
const allowsVOIP = await CarrierInfo.allowsVOIP();
const isoCountryCode = await CarrierInfo.isoCountryCode();
const mcc = await CarrierInfo.mobileCountryCode();
const mnc = await CarrierInfo.mobileNetworkCode();
const operator = await CarrierInfo.mobileNetworkOperator();
return { carrierName, allowsVOIP, isoCountryCode, mcc, mnc, operator };
}
```
**변경 후**(`react-native-nitro-device-info`):
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getCarrierDetails() {
// All synchronous - no async/await needed!
return {
carrierName: DeviceInfoModule.getCarrierSync(),
allowsVOIP: DeviceInfoModule.carrierAllowsVOIP,
isoCountryCode: DeviceInfoModule.carrierIsoCountryCode,
mcc: DeviceInfoModule.mobileCountryCode,
mnc: DeviceInfoModule.mobileNetworkCode,
operator: DeviceInfoModule.mobileNetworkOperator,
};
}
```
### 주요 이점 \{#key-benefits}
1. **async/await 불필요**: 모든 통신사 속성은 동기입니다.
2. **단일 의존성**: 별도 carrier-info 패키지가 필요하지 않습니다.
3. **JSI 직접 접근**: Nitro Modules로 네이티브 코드에 접근합니다.
4. **통합 API**: 다른 80개 이상의 기기 속성과 통신사 정보를 함께 제공합니다.
### 플랫폼 참고 사항 \{#platform-notes}
- **iOS**: `CTTelephonyNetworkInfo`와 `CTCarrier` API 사용
- **Android**: `TelephonyManager` API 사용
- **carrierAllowsVOIP**: iOS에서는 실제 값, Android에서는 대응 API가 없어 항상 `true`
- **빈 문자열**: SIM 카드가 없으면 모든 속성이 `""` 반환
## 도움이 필요한 경우 \{#need-help}
- [전체 API 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md)
- [타입 정의](/react-native-nitro-device-info/ko/api/types.md)
- [예제](/react-native-nitro-device-info/ko/examples/basic-usage.md)
- [GitHub 이슈](https://github.com/l2hyunwoo/react-native-nitro-device-info/issues)
---
url: /react-native-nitro-device-info/ko/api/types.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 타입 정의 \{#type-definitions}
`react-native-nitro-device-info`의 TypeScript 타입 정의입니다.
## 타입 import하기 \{#importing-types}
```typescript
import type {
DeviceInfo,
PowerState,
BatteryState,
DeviceType,
NavigationMode,
} from 'react-native-nitro-device-info';
```
## 기본 타입 \{#core-types}
### PowerState \{#powerstate}
전원과 배터리의 전체 상태를 나타냅니다.
```typescript
interface PowerState {
/**
* Battery charge level (0.0 to 1.0, or -1 when unavailable)
* @example 0.75 represents 75% battery
*/
batteryLevel: number;
/**
* Current battery charging status
*/
batteryState: BatteryState;
/**
* Whether low power mode is enabled
* @platform iOS only - always false on Android
*/
lowPowerMode: boolean;
}
```
**사용법**:
```typescript
const powerState: PowerState = DeviceInfoModule.getPowerState();
console.log(powerState.batteryLevel < 0
? 'Battery: unavailable'
: `Battery: ${(powerState.batteryLevel * 100).toFixed(0)}%`);
console.log(`Status: ${powerState.batteryState}`);
console.log(`Low Power Mode: ${powerState.lowPowerMode ? 'Yes' : 'No'}`);
```
**필드**:
- **batteryLevel**: 0.0(0%)\~1.0(100%)의 수치. 조회 불가 시 `-1`
- **batteryState**: 현재 충전 상태(아래 BatteryState 참고)
- **lowPowerMode**: 저전력 모드가 켜져 있는지 표시(iOS 전용)
### BatteryState \{#batterystate}
배터리 충전 상태입니다.
```typescript
type BatteryState = 'unknown' | 'unplugged' | 'charging' | 'full';
```
**값**:
- **unknown**: 배터리 상태 판단 불가
- **unplugged**: 배터리 방전 중(전원 연결 안 됨)
- **charging**: 배터리 충전 중
- **full**: 완전히 충전됨(전원이 연결돼 있을 수 있음)
**사용법**:
```typescript
const powerState = DeviceInfoModule.getPowerState();
switch (powerState.batteryState) {
case 'charging':
console.log('Device is charging');
break;
case 'full':
console.log('Battery is full');
break;
case 'unplugged':
console.log('Device is running on battery');
break;
case 'unknown':
console.log('Battery state unknown');
break;
}
```
### NavigationMode \{#navigationmode}
Android 내비게이션 방식 타입입니다.
```typescript
type NavigationMode = 'gesture' | 'buttons' | 'twobuttons' | 'unknown';
```
**값**:
- **gesture**: 제스처 내비게이션(스와이프 기반)
- **buttons**: 기존 3버튼 내비게이션(뒤로, 홈, 최근 앱)
- **twobuttons**: 2버튼 내비게이션(뒤로, 위로 스와이프하는 홈)
- **unknown**: 판단 불가(iOS에서는 항상 이 값)
**사용법**:
```typescript
const navMode = DeviceInfoModule.navigationMode;
switch (navMode) {
case 'gesture':
console.log('Device uses gesture navigation');
// Add extra bottom padding for gesture conflicts
break;
case 'buttons':
console.log('Device uses 3-button navigation');
break;
case 'twobuttons':
console.log('Device uses 2-button navigation');
break;
case 'unknown':
console.log('Navigation mode unknown (iOS)');
break;
}
```
**플랫폼 동작**:
- **Android API 29 이상**: 실제 내비게이션 방식 반환
- **Android API \< 29**: `"buttons"` 반환(제스처 내비게이션 미지원)
- **iOS**: 항상 `"unknown"` 반환
### DeviceType \{#devicetype}
기기 유형 분류입니다.
```typescript
type DeviceType =
| 'Handset' // Smartphone
| 'Tablet' // Tablet device
| 'Tv' // TV or set-top box
| 'Desktop' // Desktop computer
| 'GamingConsole' // Gaming console
| 'unknown'; // Unknown device type
```
**값**:
- **Handset**: 일반 스마트폰
- **Tablet**: 태블릿(iPad, Android 태블릿)
- **Tv**: 스마트 TV 또는 셋톱박스
- **Desktop**: 데스크톱 또는 노트북
- **GamingConsole**: 게임 콘솔
- **unknown**: 기기 유형 판단 불가
**사용법**:
```typescript
const deviceType: DeviceType = DeviceInfoModule.deviceType;
if (deviceType === 'Tablet') {
// Apply tablet-specific layout
console.log('Tablet detected, using tablet layout');
} else if (deviceType === 'Handset') {
// Apply phone-specific layout
console.log('Phone detected, using mobile layout');
}
```
**플랫폼 동작**:
- **iOS**: iPhone, iPad, Apple TV 감지
- **Android**: 화면 크기로 판단(최소 너비 >= 600dp이면 Tablet)
## DeviceInfo 인터페이스 \{#deviceinfo-interface}
타입 선언을 앱에 복사하지 말고 패키지에서 제공하는 인터페이스를 import하세요.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { DeviceInfo } from 'react-native-nitro-device-info';
const deviceInfo: DeviceInfo = DeviceInfoModule;
const model: string = deviceInfo.model;
const hasGms: boolean = deviceInfo.getHasGms();
```
`DeviceInfo`는 타입이며 런타임 싱글턴이 아닙니다. 값을 읽을 때는 `DeviceInfoModule`을 사용하세요.
전체 시그니처 원본은 [`DeviceInfo.nitro.ts`](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/main/packages/react-native-nitro-device-info/src/DeviceInfo.nitro.ts)입니다. 현재 웹사이트가 설치한 릴리스와 다르면 설치한 버전의 타입 선언을 확인하세요. 반환값과 플랫폼 동작은 [DeviceInfo 모듈](/react-native-nitro-device-info/ko/api/device-info.md)을 참고하세요.
## 사용 예제 \{#usage-examples}
### 타입을 지정해 전원 상태 다루기 \{#type-safe-power-state}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { PowerState, BatteryState } from 'react-native-nitro-device-info';
function getBatteryStatus(): string {
const powerState: PowerState = DeviceInfoModule.getPowerState();
if (powerState.batteryLevel < 0) return 'Battery: unavailable';
const percentage = (powerState.batteryLevel * 100).toFixed(0);
const state: BatteryState = powerState.batteryState;
let statusMessage = `Battery: ${percentage}%`;
if (state === 'charging') {
statusMessage += ' (Charging)';
} else if (state === 'full') {
statusMessage += ' (Full)';
}
if (powerState.lowPowerMode) {
statusMessage += ' [Low Power Mode]';
}
return statusMessage;
}
```
### 타입을 지정해 기기 유형별로 처리하기 \{#type-safe-device-type-handling}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { DeviceType } from 'react-native-nitro-device-info';
function getLayoutMode(): 'mobile' | 'tablet' | 'desktop' {
const deviceType: DeviceType = DeviceInfoModule.deviceType;
switch (deviceType) {
case 'Handset':
return 'mobile';
case 'Tablet':
return 'tablet';
case 'Desktop':
return 'desktop';
default:
return 'mobile'; // Default to mobile for unknown types
}
}
```
### 커스텀 타입 별칭 \{#custom-type-aliases}
필요에 따라 타입 별칭을 추가할 수 있습니다.
```typescript
import type { DeviceInfo } from 'react-native-nitro-device-info';
// Alias for device info
type DI = DeviceInfo;
// Custom types for your app
type DeviceCapabilities = {
hasNotch: boolean;
hasDynamicIsland: boolean;
isTablet: boolean;
isEmulator: boolean;
};
function getDeviceCapabilities(): DeviceCapabilities {
return {
hasNotch: DeviceInfoModule.getHasNotch(),
hasDynamicIsland: DeviceInfoModule.getHasDynamicIsland(),
isTablet: DeviceInfoModule.isTablet,
isEmulator: DeviceInfoModule.isEmulator,
};
}
```
## TypeScript 설정 \{#typescript-configuration}
`tsconfig.json`의 타입 검사 설정을 확인하세요.
```json
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true
}
}
```
## 타입 검사의 이점 \{#type-safety-benefits}
### IntelliSense 지원 \{#intellisense-support}
모든 메서드와 속성의 자동 완성을 제공합니다.
```typescript
// TypeScript knows all available methods
const model: string = DeviceInfoModule.model;
const charging: boolean = DeviceInfoModule.getIsBatteryCharging();
```
### 컴파일 시 오류 검사 \{#compile-time-error-checking}
```typescript
// Intentional type errors: do not copy these into working code.
// @ts-expect-error Property 'invalid' does not exist
const invalid = DeviceInfoModule.invalid;
// @ts-expect-error Expected 1 argument, got 0
const missingThreshold = DeviceInfoModule.isLowBatteryLevel();
// @ts-expect-error Threshold must be a number
const invalidThreshold = DeviceInfoModule.isLowBatteryLevel('0.2');
```
### 타입 가드 \{#type-guards}
```typescript
function checkBatteryState(state: BatteryState): string {
// TypeScript ensures you handle all cases
switch (state) {
case 'unknown':
return 'Battery state unknown';
case 'unplugged':
return 'Running on battery';
case 'charging':
return 'Charging';
case 'full':
return 'Fully charged';
// TypeScript error if any case is missing
}
}
```
## 다음 단계 \{#next-steps}
- [전체 API 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md)에서 사용 가능한 메서드 확인
- [사용 예제](/react-native-nitro-device-info/ko/examples/basic-usage.md) 확인
- 다른 라이브러리에서 전환하려면 [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md) 확인
---
url: /react-native-nitro-device-info/ko/contributing/documentation.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 문서 기여 \{#contributing-to-documentation}
문서 사이트는 Rspress를 사용합니다. 원문 페이지는 `docs/docs/`에, 설정은 `docs/rspress.config.ts`에 있습니다.
## 사이트 실행 \{#run-the-site}
레포지터리 루트에서 실행하세요.
```bash
cd docs
yarn install --immutable
yarn dev
```
Rspress가 출력하는 URL을 여세요. `/react-native-nitro-device-info/` base 경로를 포함해야 합니다.
같은 디렉터리에서 프로덕션 사이트를 빌드하고 미리 볼 수 있습니다.
```bash
yarn build
yarn preview
```
빌드 결과는 이 디렉터리의 `doc_build/`에 생성됩니다.
## 문서 위치 선택 \{#choose-the-right-page}
| 내용 | 위치 | 목적 |
| --------------- | ------------------------------------------------- | ------------------------ |
| 설치와 설정 | `guide/getting-started.md`, `guide/expo-setup.md` | 요구 사항, 명령, 동작 확인 |
| 첫 사용 예제 | `guide/quick-start.md` | 설치부터 사용까지의 짧은 절차 |
| 상태 변화에 반응하는 사용법 | `guide/react-hooks.md` | 폴링 간격, 초기값, 컴포넌트 패턴 |
| 정확한 API 동작 | `api/` | 시그니처, 단위, 플랫폼 동작, 오류 |
| 마이그레이션 | `api/migration.md` | import 경로, 대응 관계, 호환성 예외 |
| 작업별 코드 | `examples/` | 가이드에 이어 사용할 예제 |
영어 경로는 `docs/docs/` 기준입니다. 한국어 대응 페이지는 `docs/docs/ko/` 아래의 같은 경로에 둡니다. 정적 자산은 공통 `docs/docs/public/`에 둡니다.
## 독자가 사용할 수 있는 예제 작성 \{#write-examples-readers-can-use}
- import 경로를 명시하세요. 루트와 `/compat` API는 이름과 반환 타입이 다릅니다.
- JSX를 포함하는 코드에는 `tsx`를 사용하세요.
- 독립 예제에는 import 문을 포함하세요. 앞선 코드에 의존하는 조각은 표시하세요.
- 조회 불가 값, 단위, 플랫폼 제한, Promise가 reject되는 경우를 설명하세요.
- 필요한 설정은 해당 코드보다 먼저 안내하세요.
- 의도한 타입 오류를 표시하세요. 존재하지 않는 멤버를 자동 완성 예제로 제시하지 마세요.
- 성능 수치는 측정 조건과 함께 적으세요. 동기 반환 타입은 실행 시간 보장이 아닙니다.
export한 TypeScript 타입을 사용하세요. 시그니처 원본은 [`DeviceInfo.nitro.ts`](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/main/packages/react-native-nitro-device-info/src/DeviceInfo.nitro.ts)이며, 플랫폼 동작은 Swift, Kotlin, 웹 구현이 결정합니다.
## 지원 여부 배지 관리 \{#maintain-availability-badges}
새 API 섹션이나 여러 속성을 묶은 표의 행마다 도입 버전과 플랫폼 배지를 추가하세요. 기존 Rspress 테마의 `rp-badge` span을 사용하세요. Markdown으로 출력하거나 MCP로 검색할 때도 문구가 남도록 span 안에 쓰세요.
[배지 정의와 버전 근거](/react-native-nitro-device-info/ko/api/index.md#availability-badges)를 확인하세요. `Unreleased`를 `Since v…`로 바꾸기 전에 실제 npm 배포 버전과 소스를 확인하세요. 매니페스트의 버전이나 API 선언만으로 플랫폼 구현이 배포됐다고 확인할 수는 없습니다.
특정 플랫폼에서 고정 fallback 값을 반환하던 API를 실제로 구현했다면 배지를 수정하고 이 구현을 처음 배포한 릴리스를 설명하세요. API 자체의 최초 도입 버전은 유지하세요. Swift, Kotlin, 웹 구현을 각각 확인하세요.
## 페이지 추가 또는 수정 \{#add-or-change-a-page}
1. 알맞은 콘텐츠 디렉터리에서 Markdown 파일을 만들거나 수정하세요.
2. 새 페이지는 `docs/rspress.config.ts`의 `themeConfig.nav`와 `themeConfig.sidebar`, 한국어 locale 메뉴에 모두 추가하세요.
3. `/guide/quick-start` 같은 콘텐츠 루트 링크 또는 상대 Markdown 링크를 사용하세요. 내부 링크에 배포 base를 반복하지 마세요.
4. 기존 경로와 제목 앵커를 가능한 한 유지하세요.
5. 관련 예제와 README가 영향을 받으면 함께 수정하세요.
6. 사이트를 빌드하고 미리 보세요. 바꾼 링크와 검색 결과를 확인하세요.
영어를 기준 문서로 유지합니다. 모든 영어 페이지에는 `ko/`의 한국어 대응 페이지가 있어야 합니다. 한국어 frontmatter의 `translationOf`와 `sourceCommit`으로 원문과 번역 기준 커밋을 기록하세요. API 이름, 명령, 타입, 수치, 단위, 반환값, 권한, 필수 조건과 예외를 원문과 대조하세요. 한국어 페이지의 명시적 제목 ID도 유지하세요. 언어 선택기는 같은 경로로 이동하므로 대응 페이지를 빠뜨리면 404가 발생합니다. [한국어 문서 운영 안내](https://github.com/l2hyunwoo/react-native-nitro-device-info/blob/main/docs/I18N_PLAN.ko.md)를 참고하세요.
## AI가 읽는 문서 \{#ai-readable-documentation}
Rspress는 사이트 빌드 중 페이지 Markdown, `llms.txt`, `llms-full.txt`를 언어별로 생성합니다.
MCP 서버는 빌드 중 별도의 문서 스냅샷을 포함합니다. 사이트 배포만으로 이미 배포한 MCP 패키지가 갱신되지는 않습니다. 문서 모음을 바꾸면 패키지를 다시 빌드하고 테스트하세요.
각 섹션에 API 이름, import 경로, 플랫폼 fallback 값, 호환성 주의 사항을 명확하게 적으세요. 검색 결과에는 페이지 전체가 아니라 섹션 하나만 포함될 수 있습니다.
## 배포 \{#deployment}
`docs/**`를 바꾸는 PR에서는 문서 검증 워크플로가 실행되어 사이트를 빌드하고 검토용 산출물을 업로드합니다.
`main`에 병합하면 배포 워크플로가 실행됩니다. 배포에 실패하면 [Actions 로그](https://github.com/l2hyunwoo/react-native-nitro-device-info/actions)와 GitHub Pages 설정을 확인하세요.
---
url: /react-native-nitro-device-info/ko/examples/advanced-usage.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 고급 사용 예제 \{#advanced-usage-examples}
`react-native-nitro-device-info`의 고급 패턴과 활용 방법입니다.
## 플랫폼별 코드 \{#platform-specific-code}
### 플랫폼에 따른 조건 분기 \{#conditional-logic-based-on-platform}
```typescript
import { Platform } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getDeviceDetails() {
if (Platform.OS === 'ios') {
return {
hasNotch: DeviceInfoModule.getHasNotch(),
hasDynamicIsland: DeviceInfoModule.getHasDynamicIsland(),
isDisplayZoomed: DeviceInfoModule.isDisplayZoomed,
brightness: DeviceInfoModule.getBrightness(),
};
} else {
return {
apiLevel: DeviceInfoModule.apiLevel,
securityPatch: DeviceInfoModule.securityPatch,
hasGms: DeviceInfoModule.getHasGms(),
hasHms: DeviceInfoModule.getHasHms(),
};
}
}
```
### Android 전용 기능 \{#android-specific-features}
```typescript
import { Platform } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getAndroidDetails() {
if (Platform.OS !== 'android') {
return null;
}
return {
// API Level
apiLevel: DeviceInfoModule.apiLevel,
// Build Information
androidId: DeviceInfoModule.androidId,
securityPatch: DeviceInfoModule.securityPatch,
fingerprint: DeviceInfoModule.fingerprint,
// ABIs (CPU architectures)
supportedAbis: DeviceInfoModule.supportedAbis,
supported32BitAbis: DeviceInfoModule.supported32BitAbis,
supported64BitAbis: DeviceInfoModule.supported64BitAbis,
// Mobile Services
hasGooglePlayServices: DeviceInfoModule.getHasGms(),
hasHuaweiMobileServices: DeviceInfoModule.getHasHms(),
// Device State
isAirplaneMode: DeviceInfoModule.getIsAirplaneMode(),
isLowRamDevice: DeviceInfoModule.isLowRamDevice,
// System Features
hasNfc: DeviceInfoModule.hasSystemFeature('android.hardware.nfc'),
hasBluetooth: DeviceInfoModule.hasSystemFeature('android.hardware.bluetooth'),
// All Available Features
availableFeatures: DeviceInfoModule.systemAvailableFeatures,
};
}
```
### iOS 전용 기능 \{#ios-specific-features}
```typescript
import { Platform } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
async function getIOSDetails() {
if (Platform.OS !== 'ios') {
return null;
}
return {
// Display Features
hasNotch: DeviceInfoModule.getHasNotch(),
hasDynamicIsland: DeviceInfoModule.getHasDynamicIsland(),
isDisplayZoomed: DeviceInfoModule.isDisplayZoomed,
// Screen Brightness
brightness: DeviceInfoModule.getBrightness(),
// DeviceCheck Token (async, requires network)
deviceToken: await DeviceInfoModule.getDeviceToken().catch(() => null),
// Write the current IDFV to the local app-specific Keychain item
syncedUniqueId: await DeviceInfoModule.syncUniqueId(),
};
}
```
## 성능 최적화 \{#performance-optimization}
### 비용이 큰 작업의 결과 캐시 \{#caching-expensive-operations}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
class DeviceInfoCache {
private static cache: Map = new Map();
// Cache User-Agent (slow on iOS first call)
static async getUserAgent(): Promise {
if (this.cache.has('userAgent')) {
return this.cache.get('userAgent');
}
const userAgent = await DeviceInfoModule.getUserAgent();
this.cache.set('userAgent', userAgent);
return userAgent;
}
// Cache IP address with TTL
static async getIpAddress(ttlMs: number = 60000): Promise {
const now = Date.now();
const cached = this.cache.get('ipAddress');
if (cached && (now - cached.timestamp) < ttlMs) {
return cached.value;
}
const ipAddress = await DeviceInfoModule.getIpAddress();
this.cache.set('ipAddress', { value: ipAddress, timestamp: now });
return ipAddress;
}
// Use synchronous cached values when available
static getIpAddressSync(): string {
return DeviceInfoModule.getIpAddressSync();
}
static getCarrierSync(): string {
return DeviceInfoModule.getCarrierSync();
}
}
```
### 비동기 호출 묶기 \{#batch-async-calls}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
async function fetchAllNetworkInfo() {
// Fetch multiple async values in parallel
const [ipAddress, macAddress, carrier, locationEnabled, headphones] =
await Promise.all([
DeviceInfoModule.getIpAddress(),
DeviceInfoModule.getMacAddress(),
DeviceInfoModule.getCarrier(),
DeviceInfoModule.isLocationEnabled(),
DeviceInfoModule.isHeadphonesConnected(),
]);
return {
ipAddress,
macAddress,
carrier,
locationEnabled,
headphones,
};
}
```
### 동기 API 사용 \{#use-synchronous-variants}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Prefer synchronous cached variants for better performance
function getNetworkInfoFast() {
return {
// 5-second cache, instant access
ipAddress: DeviceInfoModule.getIpAddressSync(),
macAddress: DeviceInfoModule.getMacAddressSync(),
carrier: DeviceInfoModule.getCarrierSync(),
// Cached install times
firstInstallTime: DeviceInfoModule.firstInstallTimeSync,
lastUpdateTime: DeviceInfoModule.lastUpdateTimeSync,
// Cached connectivity
isLocationEnabled: DeviceInfoModule.getIsLocationEnabled(),
isHeadphonesConnected: DeviceInfoModule.getIsHeadphonesConnected(),
};
}
```
## React 훅 \{#react-hooks}
### 내장 훅(권장) \{#built-in-hooks-recommended}
일반적인 상태 관찰에는 내장 React 훅을 권장합니다.
```typescript
import {
useBatteryLevel,
useBatteryLevelIsLow,
usePowerState,
useIsHeadphonesConnected,
useIsWiredHeadphonesConnected,
useIsBluetoothHeadphonesConnected,
useBrightness,
} from 'react-native-nitro-device-info';
function DeviceMonitor() {
// Battery monitoring
const batteryLevel = useBatteryLevel(); // 0.0 - 1.0
const lowBattery = useBatteryLevelIsLow(); // null or level when low
const powerState = usePowerState(); // { batteryLevel, batteryState, lowPowerMode }
// Audio monitoring
const headphones = useIsHeadphonesConnected(); // boolean
const wired = useIsWiredHeadphonesConnected(); // boolean
const bluetooth = useIsBluetoothHeadphonesConnected(); // boolean
// Display monitoring (iOS only)
const brightness = useBrightness(); // 0.0 - 1.0 on iOS, -1 on Android
return (
Battery: {batteryLevel !== null ? `${Math.round(batteryLevel * 100)}%` : 'Loading...'}
Charging: {powerState.batteryState === 'charging' ? 'Yes' : 'No'}
Headphones: {headphones ? 'Connected' : 'Disconnected'}
{lowBattery !== null && ⚠️ Low Battery Warning!}
);
}
```
전체 문서는 [React 훅 가이드](/react-native-nitro-device-info/ko/guide/react-hooks.md)를 참고하세요.
### 커스텀 훅으로 기능 확장 \{#custom-hooks-for-extended-functionality}
내장 훅에 없는 기능이 필요하면 커스텀 훅을 만들 수 있습니다.
#### 커스텀 기기 정보 훅 \{#custom-device-info-hook}
```typescript
import { useEffect, useState } from 'react';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
type DeviceInfo = {
deviceId: string;
brand: string;
model: string;
systemVersion: string;
isTablet: boolean;
batteryLevel: number;
ipAddress?: string;
};
export function useDeviceInfo(): DeviceInfo {
const [ipAddress, setIpAddress] = useState();
// Sync values - instant access
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const systemVersion = DeviceInfoModule.systemVersion;
const isTablet = DeviceInfoModule.isTablet;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
// Async values - fetch on mount
useEffect(() => {
DeviceInfoModule.getIpAddress()
.then(setIpAddress)
.catch(() => setIpAddress(undefined));
}, []);
return {
deviceId,
brand,
model,
systemVersion,
isTablet,
batteryLevel,
ipAddress,
};
}
// Usage
function MyComponent() {
const deviceInfo = useDeviceInfo();
return (
Running on {deviceInfo.brand} {deviceInfo.model}
);
}
```
#### 커스텀 배터리 관찰 훅 \{#custom-battery-monitoring-hook}
다른 폴링 간격이나 추가 로직이 필요하면 내장 훅을 확장할 수 있습니다.
```typescript
import { useEffect, useState } from 'react';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { PowerState } from 'react-native-nitro-device-info';
// Custom hook with configurable polling interval
export function useBatteryMonitor(intervalMs: number = 5000) {
const [powerState, setPowerState] = useState(
DeviceInfoModule.getPowerState()
);
useEffect(() => {
const interval = setInterval(() => {
setPowerState(DeviceInfoModule.getPowerState());
}, intervalMs);
return () => clearInterval(interval);
}, [intervalMs]);
return powerState;
}
// Usage
function BatteryMonitor() {
const powerState = useBatteryMonitor(5000); // Update every 5 seconds
return (
Battery: {powerState.batteryLevel < 0 ? 'Unavailable' : `${(powerState.batteryLevel * 100).toFixed(0)}%`}
Status: {powerState.batteryState}
{powerState.lowPowerMode && Low Power Mode Active}
);
}
```
#### 메모리 관찰 훅 \{#memory-monitoring-hook}
```typescript
import { useEffect, useState } from 'react';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
type MemoryInfo = {
totalMemory: number;
usedMemory: number;
usedPercentage: number;
};
export function useMemoryMonitor(intervalMs: number = 1000): MemoryInfo {
const [memoryInfo, setMemoryInfo] = useState(() => {
const total = DeviceInfoModule.totalMemory;
const used = DeviceInfoModule.getUsedMemory();
return {
totalMemory: total,
usedMemory: used,
usedPercentage: (used / total) * 100,
};
});
useEffect(() => {
const interval = setInterval(() => {
const total = DeviceInfoModule.totalMemory;
const used = DeviceInfoModule.getUsedMemory();
setMemoryInfo({
totalMemory: total,
usedMemory: used,
usedPercentage: (used / total) * 100,
});
}, intervalMs);
return () => clearInterval(interval);
}, [intervalMs]);
return memoryInfo;
}
// Usage
function MemoryMonitor() {
const memory = useMemoryMonitor(1000); // Update every second
return (
Used: {(memory.usedMemory / 1024 / 1024).toFixed(0)} MB
Total: {(memory.totalMemory / 1024 / 1024).toFixed(0)} MB
Usage: {memory.usedPercentage.toFixed(1)}%
);
}
```
## 기기에 맞춘 UI \{#adaptive-ui-based-on-device}
### 반응형 레이아웃 \{#responsive-layout}
```typescript
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function AdaptiveLayout({ children }: { children: React.ReactNode }) {
const isTablet = DeviceInfoModule.isTablet;
const hasNotch = DeviceInfoModule.getHasNotch();
return (
{children}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
tabletContainer: {
padding: 32,
maxWidth: 768,
alignSelf: 'center',
},
notchContainer: {
paddingTop: 44, // Extra padding for notch
},
});
```
### 기능 감지 UI \{#feature-detection-ui}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function FeatureAwareUI() {
const hasNotch = DeviceInfoModule.getHasNotch();
const hasDynamicIsland = DeviceInfoModule.getHasDynamicIsland();
const hasCamera = DeviceInfoModule.isCameraPresent;
return (
{hasDynamicIsland && (
🏝️ Dynamic Island Detected
)}
{hasNotch && !hasDynamicIsland && (
📱 Notch Detected
)}
{!hasCamera && (
⚠️ No Camera Available
)}
);
}
```
## 오류 처리 \{#error-handling}
### 비동기 오류 처리 \{#graceful-async-error-handling}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
async function getDeviceInfoSafely() {
const deviceInfo = {
// Sync values - always available
deviceId: DeviceInfoModule.deviceId,
brand: DeviceInfoModule.brand,
model: DeviceInfoModule.model,
// Async values - may fail
ipAddress: 'Unknown',
carrier: 'Unknown',
deviceToken: null as string | null,
};
// Try to get IP address
try {
deviceInfo.ipAddress = await DeviceInfoModule.getIpAddress();
} catch (error) {
console.warn('Failed to get IP address:', error);
}
// Try to get carrier
try {
deviceInfo.carrier = await DeviceInfoModule.getCarrier();
} catch (error) {
console.warn('Failed to get carrier:', error);
}
// Try to get device token (iOS only, may fail)
try {
deviceInfo.deviceToken = await DeviceInfoModule.getDeviceToken();
} catch (error) {
console.log('DeviceCheck not available:', error);
}
return deviceInfo;
}
```
### TypeScript 타입 가드 \{#typescript-type-guards}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { BatteryState } from 'react-native-nitro-device-info';
function getBatteryStatusMessage(state: BatteryState): string {
switch (state) {
case 'charging':
return '⚡ Charging';
case 'full':
return '✅ Fully Charged';
case 'unplugged':
return '🔋 On Battery';
case 'unknown':
return '❓ Unknown';
default:
// TypeScript ensures exhaustive checking
const _exhaustive: never = state;
return 'Unknown';
}
}
function checkBattery() {
const powerState = DeviceInfoModule.getPowerState();
const message = getBatteryStatusMessage(powerState.batteryState);
console.log(message);
}
```
## 고급 Android 기능 \{#advanced-android-features}
### 시스템 기능 확인 \{#check-system-features}
```typescript
import { Platform } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getAndroidCapabilities() {
if (Platform.OS !== 'android') {
return {};
}
return {
hasNfc: DeviceInfoModule.hasSystemFeature('android.hardware.nfc'),
hasBluetooth: DeviceInfoModule.hasSystemFeature('android.hardware.bluetooth'),
hasWifi: DeviceInfoModule.hasSystemFeature('android.hardware.wifi'),
hasCamera: DeviceInfoModule.hasSystemFeature('android.hardware.camera'),
hasCameraFlash: DeviceInfoModule.hasSystemFeature('android.hardware.camera.flash'),
hasFingerprint: DeviceInfoModule.hasSystemFeature('android.hardware.fingerprint'),
hasGps: DeviceInfoModule.hasSystemFeature('android.hardware.location.gps'),
};
}
```
### 위치 정보 provider 확인 \{#location-providers}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getLocationCapabilities() {
const providers = DeviceInfoModule.getAvailableLocationProviders();
return {
hasGps: providers.includes('gps'),
hasNetwork: providers.includes('network'),
hasFused: providers.includes('fused'),
};
}
```
## 전체 고급 예제 \{#complete-advanced-example}
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView, StyleSheet, Platform } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { PowerState } from 'react-native-nitro-device-info';
export default function AdvancedDeviceInfo() {
const [asyncData, setAsyncData] = useState({
ipAddress: 'Loading...',
carrier: 'Loading...',
});
const [powerState, setPowerState] = useState(
DeviceInfoModule.getPowerState()
);
// Fetch async data on mount
useEffect(() => {
Promise.all([
DeviceInfoModule.getIpAddress(),
DeviceInfoModule.getCarrier(),
])
.then(([ip, carrier]) => {
setAsyncData({ ipAddress: ip, carrier });
})
.catch(error => {
console.error('Failed to fetch async data:', error);
});
}, []);
// Monitor battery every 5 seconds
useEffect(() => {
const interval = setInterval(() => {
setPowerState(DeviceInfoModule.getPowerState());
}, 5000);
return () => clearInterval(interval);
}, []);
// Sync device info
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const isTablet = DeviceInfoModule.isTablet;
const totalMemory = DeviceInfoModule.totalMemory;
const usedMemory = DeviceInfoModule.getUsedMemory();
// Platform-specific info
const platformInfo = Platform.OS === 'ios' ? {
hasNotch: DeviceInfoModule.getHasNotch(),
hasDynamicIsland: DeviceInfoModule.getHasDynamicIsland(),
brightness: DeviceInfoModule.getBrightness(),
} : {
apiLevel: DeviceInfoModule.apiLevel,
hasGms: DeviceInfoModule.getHasGms(),
isAirplaneMode: DeviceInfoModule.getIsAirplaneMode(),
};
return (
{powerState.lowPowerMode && (
)}
{Object.entries(platformInfo).map(([key, value]) => (
))}
);
}
function Section({ title, children }: { title: string; children: React.ReactNode }) {
return (
{title}
{children}
);
}
function Info({ label, value }: { label: string; value: string }) {
return (
{label}:
{value}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
section: {
marginBottom: 24,
padding: 16,
backgroundColor: '#f5f5f5',
borderRadius: 8,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 12,
},
row: {
flexDirection: 'row',
marginBottom: 8,
},
label: {
fontWeight: '600',
marginRight: 8,
},
value: {
flex: 1,
},
});
```
## 다음 단계 \{#next-steps}
- [React 훅](/react-native-nitro-device-info/ko/guide/react-hooks.md): 상태 변화 관찰
- [API 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md): 사용 가능한 전체 메서드
- [타입 정의](/react-native-nitro-device-info/ko/api/types.md): TypeScript 타입
- [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md): 다른 라이브러리에서 전환
---
url: /react-native-nitro-device-info/ko/examples/basic-usage.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 기본 사용 예제 \{#basic-usage-examples}
실제 예제로 `react-native-nitro-device-info` 사용법을 설명합니다.
## 시작하기 \{#getting-started}
컴포넌트에서 모듈을 import하세요.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
```
## 간단한 기기 정보 \{#simple-device-information}
### 기기 속성 읽기 \{#accessing-device-properties}
속성에 직접 접근하면 간단하게 기기 정보를 읽을 수 있습니다.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function showDeviceInfo() {
console.log('Device ID:', DeviceInfoModule.deviceId);
console.log('Brand:', DeviceInfoModule.brand);
console.log('Model:', DeviceInfoModule.model);
console.log('OS:', DeviceInfoModule.systemName);
console.log('OS Version:', DeviceInfoModule.systemVersion);
}
showDeviceInfo();
// Output:
// Device ID: iPhone14,2
// Brand: Apple
// Model: iPhone 13 Pro
// OS: iOS
// OS Version: 15.0
```
### 기본 React 컴포넌트 \{#basic-react-component}
```typescript
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function DeviceInfoCard() {
return (
Device Information
Brand: {DeviceInfoModule.brand}
Model: {DeviceInfoModule.model}
Device ID: {DeviceInfoModule.deviceId}
OS: {DeviceInfoModule.systemName} {DeviceInfoModule.systemVersion}
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
backgroundColor: '#f5f5f5',
borderRadius: 8,
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 8,
},
});
```
## 기기 기능 \{#device-capabilities}
### 기기 유형 확인 \{#check-device-type}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getDeviceCategory(): string {
if (DeviceInfoModule.isTablet) {
return 'This is a tablet';
} else {
return 'This is a phone';
}
}
console.log(getDeviceCategory());
```
### 특정 기능 확인 \{#check-for-specific-features}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Check if device has a notch
if (DeviceInfoModule.getHasNotch()) {
console.log('Device has a notch - adjust UI accordingly');
}
// Check if device has Dynamic Island (iPhone 14 Pro+)
if (DeviceInfoModule.getHasDynamicIsland()) {
console.log('Device has Dynamic Island');
}
// Check if camera is available
if (DeviceInfoModule.isCameraPresent) {
console.log('Camera is available');
}
// Check if running in simulator/emulator
if (DeviceInfoModule.isEmulator) {
console.log('Running in simulator/emulator');
}
```
## 배터리 정보 \{#battery-information}
### 간단한 배터리 표시 \{#simple-battery-display}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function BatteryIndicator() {
const batteryLevel = DeviceInfoModule.getBatteryLevel();
const isCharging = DeviceInfoModule.getIsBatteryCharging();
const batteryText = batteryLevel < 0 ? 'Unavailable' : `${(batteryLevel * 100).toFixed(0)}%`;
return (
Battery: {batteryText}
{isCharging && ⚡ Charging}
);
}
```
### 배터리 잔량 경고 \{#battery-level-warning}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function checkBatteryStatus() {
const batteryLevel = DeviceInfoModule.getBatteryLevel();
if (batteryLevel < 0) {
console.log('Battery: unavailable');
return 'unavailable';
}
if (batteryLevel < 0.2) {
console.warn(`Battery low: ${(batteryLevel * 100).toFixed(0)}%`);
return 'low';
} else if (batteryLevel < 0.5) {
console.log(`Battery moderate: ${(batteryLevel * 100).toFixed(0)}%`);
return 'moderate';
} else {
console.log(`Battery good: ${(batteryLevel * 100).toFixed(0)}%`);
return 'good';
}
}
```
### 전체 전원 상태 \{#complete-power-state}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
import type { PowerState } from 'react-native-nitro-device-info';
export default function PowerStateDisplay() {
const powerState: PowerState = DeviceInfoModule.getPowerState();
const batteryText = powerState.batteryLevel < 0 ? 'Unavailable' : `${(powerState.batteryLevel * 100).toFixed(0)}%`;
return (
Battery: {batteryText}
Status: {powerState.batteryState}
{powerState.lowPowerMode && 🔋 Low Power Mode}
);
}
```
## 시스템 리소스 \{#system-resources}
### 메모리 사용량 표시 \{#memory-usage-display}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function MemoryInfo() {
const totalMemory = DeviceInfoModule.totalMemory;
const usedMemory = DeviceInfoModule.getUsedMemory();
const totalGB = (totalMemory / 1024 / 1024 / 1024).toFixed(1);
const usedMB = (usedMemory / 1024 / 1024).toFixed(0);
return (
Total RAM: {totalGB} GB
App Memory Usage: {usedMB} MB
);
}
```
### 저장 공간 정보 \{#storage-information}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function StorageInfo() {
const totalDisk = DeviceInfoModule.totalDiskCapacity;
const freeDisk = DeviceInfoModule.getFreeDiskStorage();
const totalGB = (totalDisk / 1024 / 1024 / 1024).toFixed(0);
const freeGB = (freeDisk / 1024 / 1024 / 1024).toFixed(1);
return (
Total Storage: {totalGB} GB
Free Space: {freeGB} GB
);
}
```
## 앱 정보 \{#application-information}
### 앱 버전 표시 \{#app-version-display}
```typescript
import React from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function AppVersionInfo() {
const appName = DeviceInfoModule.applicationName;
const version = DeviceInfoModule.version;
const buildNumber = DeviceInfoModule.buildNumber;
const bundleId = DeviceInfoModule.bundleId;
return (
{appName}
Version: {version}
Build: {buildNumber}
Bundle ID: {bundleId}
);
}
```
### 읽기 쉬운 버전 문자열 \{#readable-version-string}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Get formatted version string
const version = DeviceInfoModule.readableVersion;
console.log(`App version: ${version}`); // "1.2.3.42"
```
## 네트워크 정보(비동기) \{#network-information-async}
### IP 주소 읽기 \{#get-ip-address}
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function NetworkInfo() {
const [ipAddress, setIpAddress] = useState('Loading...');
useEffect(() => {
DeviceInfoModule.getIpAddress()
.then(setIpAddress)
.catch(() => setIpAddress('Unavailable'));
}, []);
return (
IP Address: {ipAddress}
);
}
```
### 통신사 정보 읽기 \{#get-carrier-information}
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function CarrierInfo() {
const [carrier, setCarrier] = useState('Loading...');
useEffect(() => {
DeviceInfoModule.getCarrier()
.then(setCarrier)
.catch(() => setCarrier('No SIM'));
}, []);
return (
Carrier: {carrier}
);
}
```
### 여러 비동기 호출 \{#multiple-async-calls}
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
type NetworkState = {
ipAddress: string;
carrier: string;
locationEnabled: boolean;
};
export default function CompleteNetworkInfo() {
const [networkState, setNetworkState] = useState({
ipAddress: 'Loading...',
carrier: 'Loading...',
locationEnabled: false,
});
useEffect(() => {
// Fetch all network info in parallel
Promise.all([
DeviceInfoModule.getIpAddress(),
DeviceInfoModule.getCarrier(),
DeviceInfoModule.isLocationEnabled(),
])
.then(([ip, carrier, location]) => {
setNetworkState({
ipAddress: ip,
carrier: carrier,
locationEnabled: location,
});
})
.catch(error => {
console.error('Failed to fetch network info:', error);
});
}, []);
return (
IP: {networkState.ipAddress}
Carrier: {networkState.carrier}
Location: {networkState.locationEnabled ? 'Enabled' : 'Disabled'}
);
}
```
## 전체 예제 앱 \{#complete-example-app}
여러 기능을 함께 사용하는 전체 예제입니다.
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView, StyleSheet } from 'react-native';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
export default function DeviceInfoScreen() {
const [ipAddress, setIpAddress] = useState('Loading...');
// Synchronous data - instant access
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const systemVersion = DeviceInfoModule.systemVersion;
const isTablet = DeviceInfoModule.isTablet;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
const totalMemory = DeviceInfoModule.totalMemory;
const freeDisk = DeviceInfoModule.getFreeDiskStorage();
// Async data - fetch on mount
useEffect(() => {
DeviceInfoModule.getIpAddress()
.then(setIpAddress)
.catch(() => setIpAddress('Unavailable'));
}, []);
return (
Device Information
Brand: {brand}
Model: {model}
Device ID: {deviceId}
OS Version: {systemVersion}
Type: {isTablet ? 'Tablet' : 'Phone'}
System Status
Battery: {batteryLevel < 0 ? 'Unavailable' : `${(batteryLevel * 100).toFixed(0)}%`}
RAM: {(totalMemory / 1024 / 1024 / 1024).toFixed(1)} GB
Free Storage: {(freeDisk / 1024 / 1024 / 1024).toFixed(1)} GB
Network
IP Address: {ipAddress}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
section: {
marginBottom: 24,
padding: 16,
backgroundColor: '#f5f5f5',
borderRadius: 8,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 12,
},
});
```
## 다음 단계 \{#next-steps}
- [고급 사용법](/react-native-nitro-device-info/ko/examples/advanced-usage.md): 복잡한 사용 패턴
- [React 훅](/react-native-nitro-device-info/ko/guide/react-hooks.md): 상태 변화 관찰
- [API 레퍼런스](/react-native-nitro-device-info/ko/api/device-info.md): 사용 가능한 전체 메서드
- [타입 정의](/react-native-nitro-device-info/ko/api/types.md): TypeScript 지원
---
url: /react-native-nitro-device-info/ko/guide/expo-setup.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# Expo 설정 \{#expo-setup}
Expo 프로젝트에서 [Continuous Native Generation](https://docs.expo.dev/workflow/continuous-native-generation/)(`expo prebuild` / 개발 클라이언트)을 사용한다면 **config plugin**으로 `react-native-nitro-device-info`를 설정할 수 있습니다. `ios/`나 `android/`를 직접 편집하지 않아도 됩니다.
[Expo 개발 빌드](https://docs.expo.dev/develop/development-builds/introduction/) 또는 EAS Build를 사용하세요. Expo Go에는 이 네이티브 모듈이 없습니다. Expo SDK와 호환되는 React Native 및 Nitro 버전을 선택하세요.
## 설치 \{#install}
```bash
npx expo install react-native-nitro-device-info react-native-nitro-modules
```
네이티브 모듈은 autolinking으로 등록됩니다. 대부분의 API는 이 과정만으로 사용할 수 있으므로 `plugins` 배열에 plugin을 추가하지 않고 `npx expo prebuild`를 실행할 수 있습니다.
## config plugin이 필요한 경우 \{#when-you-need-the-config-plugin}
일부 API가 사용하는 네이티브 기능에는 권한이나 entitlement가 필요합니다. 이 설정은 **선택 사항**이며 plugin은 요청한 항목만 추가합니다. 사용하지 않는 권한을 요청하면 앱 스토어 심사에서 거절될 수 있습니다. `app.json` 또는 `app.config.js`의 `plugins` 배열에 추가하고 필요한 옵션을 켜세요.
```json
{
"expo": {
"plugins": [
[
"react-native-nitro-device-info",
{
"enableSerialNumber": true
}
]
]
}
}
```
Expo가 네이티브 디렉터리를 관리한다면 plugin 옵션을 바꾼 뒤 네이티브 디렉터리를 다시 생성하세요. `--clean`은 `ios/`와 `android/`를 삭제하고 다시 만듭니다. 직접 수정한 네이티브 코드는 실행 전에 따로 보관하세요.
```bash
npx expo prebuild --clean
```
prebuild 후 `npx expo run:ios`, `npx expo run:android` 또는 EAS Build로 네이티브 앱을 다시 빌드하고 설치하세요. JavaScript 서버만 재시작하면 네이티브 변경이 적용되지 않습니다.
### Plugin 옵션 \{#plugin-options}
| 옵션 | 기본값 | 효과 |
| -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `enableSerialNumber` | `false` | Android `READ_PHONE_STATE`를 선언합니다. 앱에서 런타임 권한을 별도로 요청해야 합니다. Android 10 이상은 일련번호 접근을 추가로 제한하므로 일반 앱은 권한을 받아도 대개 `"unknown"`을 받습니다. |
Plugin은 권한을 선언할 뿐 런타임에 요청하거나 [Android 일련번호 제한](https://developer.android.com/reference/android/os/Build#getSerial\(\))을 우회하지 않습니다. 라이브러리는 처음 접근할 때 `serialNumber`를 캐시하므로 필요한 권한은 읽기 전에 요청하세요.
### 자동으로 추가하지 않는 설정 \{#what-is-not-injected-by-design}
- **`getInstallReferrer()`, `getHasGms()`**: Play Install Referrer와 Google Play Services 의존성은 라이브러리의 Gradle 빌드에 포함됩니다. 사용하는 앱에서 매니페스트나 Gradle을 바꿀 필요가 없습니다.
- **위치 및 통신사 API**: `getIsLocationEnabled()`와 통신사 getter는 권한을 요청하지 않고 전역 시스템 상태를 읽습니다. `Info.plist`의 용도 설명 키가 필요하지 않습니다.
- **`isSideLoadingEnabled()`**: 아래를 참고하세요.
## `isSideLoadingEnabled()`의 수동 설정 \{#issideloadingenabled-requires-manual-setup}
`isSideLoadingEnabled()`는 `canRequestPackageInstalls()`를 호출합니다. 앱이 Android `REQUEST_INSTALL_PACKAGES` 권한을 선언해야 `true`를 반환할 수 있습니다. Google Play는 이 권한을 제한 권한으로 분류하므로 plugin은 이 권한을 추가하지 않습니다. 사용자가 직접 시작한 설치 과정에서 실제로 패키지를 설치하는 앱에만 허용됩니다. 사이드로딩 상태 조회만을 위해 선언하면 Play 심사에서 거절될 수 있습니다.
앱이 사용 요건을 충족한다면 [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/) plugin이나 작은 커스텀 plugin으로 권한을 추가하고 Play Console 권한 신고에서 용도를 설명하세요. 권한이 없으면 `isSideLoadingEnabled()`는 `false`를 반환합니다.
## Device attestation(App Attest / Play Integrity) \{#device-attestation-app-attest--play-integrity}
서버에서 검증할 device attestation 토큰을 발급하는 선택 패키지 `react-native-nitro-device-integrity`에는 별도의 config plugin이 있습니다.
```bash
npx expo install react-native-nitro-device-integrity
```
```json
{
"expo": {
"plugins": [
[
"react-native-nitro-device-integrity",
{
"appAttest": true
}
]
]
}
}
```
| 옵션 | 기본값 | 효과 |
| ----------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `appAttest` | `false` | iOS `com.apple.developer.devicecheck.appattest-environment` entitlement를 `development` 값으로 추가해 `DCAppAttestService`를 사용할 수 있게 합니다. |
Entitlement 값은 항상 `development`로 기록합니다. TestFlight나 App Store로 배포하는 빌드는 iOS가 이 값을 무시하고 자동으로 프로덕션 환경을 사용하므로 두 환경에서 같은 값을 사용할 수 있습니다.
:::warning Apple Developer 포털의 App Attest 기능도 필요합니다
Plugin은 entitlement를 기록하지만 App ID에서 App Attest 기능을 켤 수는 없습니다. Apple Developer 포털에서 App ID의 **App Attest**를 켜거나 EAS / Xcode 자동 서명으로 관리하세요. 기능이 없으면 빌드 서명이 실패합니다(오류 `0xE8008016`).
:::
Play Integrity(Android)와 DeviceCheck(iOS)는 entitlement나 권한이 필요하지 않습니다. Play Integrity의 런타임 `cloudProjectNumber`만 필요하므로 config plugin을 요구하지 않습니다.
## 결과 확인 \{#verifying-the-result}
`npx expo prebuild --clean` 후 추가한 설정을 확인하세요.
- `enableSerialNumber`를 켰다면 `android/app/src/main/AndroidManifest.xml`에 ``가 있어야 합니다.
- `appAttest`를 켰다면 `ios//.entitlements`에 `appattest-environment` 키가 있어야 합니다.
Plugin은 멱등성을 유지하므로 prebuild를 다시 실행해도 항목이 중복되지 않습니다.
---
url: /react-native-nitro-device-info/ko/guide/getting-started.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 시작하기 \{#getting-started}
React Native 프로젝트에 `react-native-nitro-device-info`를 설치하고 설정합니다.
## 사전 요구 사항 \{#prerequisites}
설치 전에 프로젝트가 다음 조건을 충족하는지 확인하세요.
- **React Native**: 설치한 Nitro 런타임이 지원하는 버전을 사용하세요. 레포지터리 예제는 React Native 0.85.3을 사용하며, 이 값이 최소 지원 버전을 뜻하지는 않습니다.
- **iOS**: 배포 대상 15.1 이상
- **Android**: minSdkVersion 24 이상(Android 7.0 Nougat)
- **Node.js**: React Native toolchain 요구 사항을 따르세요. 레포지터리 개발에는 Node.js 22를 사용합니다.
위 iOS와 Android 최소 버전은 이 라이브러리의 네이티브 빌드에 설정한 값입니다. React Native나 Nitro는 더 높은 최소 버전을 요구할 수 있습니다.
## 설치 \{#installation}
원하는 패키지 관리자로 라이브러리와 peer dependencies를 설치하세요.
```bash
# npm
npm install react-native-nitro-device-info react-native-nitro-modules
# yarn
yarn add react-native-nitro-device-info react-native-nitro-modules
# pnpm
pnpm add react-native-nitro-device-info react-native-nitro-modules
```
> **필수**: JSI 바인딩에 필요한 peer dependencies는 `react-native-nitro-modules` >=0.35.0 \<1.0.0입니다.
## 플랫폼 설정 \{#platform-setup}
### iOS 설정 \{#ios-configuration}
패키지를 설치한 뒤 CocoaPods 의존성을 설치하세요.
```sh
cd ios && pod install && cd ..
```
Pod 설치 후 iOS 앱을 다시 빌드하세요. Metro만 재시작하면 네이티브 코드가 설치되지 않습니다.
### iOS privacy info manifest \{#ios-privacy-manifest}
> **v1.9.0**: privacy info manifest 자동 포함은 v1.9.0부터 지원합니다. `1.8.3`에는 포함되지 않습니다. [PR #144](https://github.com/l2hyunwoo/react-native-nitro-device-info/pull/144)를 참고하세요.
Pod는 `ios/PrivacyInfo.xcprivacy`를 `NitroDeviceInfo_privacy.bundle`에 포함합니다. CocoaPods는 이 리소스 번들을 앱에 복사합니다. Expo prebuild나 EAS Build에서 Pod를 설치할 때도 같습니다. 개인정보 보호 전용 config plugin 옵션을 켜거나 앱 타깃에 직접 복사할 필요는 없습니다.
privacy info manifest는 [Expo Device](https://github.com/expo/expo/blob/5729befbfdb34e4be8880c19b3c5eff99bd04795/packages/expo-device/ios/ExpoDevice.podspec#L23)와 같은 리소스 번들 방식으로 포함하며 이 라이브러리가 사용하는 API에 맞춰 `approved reason`(Apple이 허용한 API 사용 목적)을 선언했습니다.
| API 범주 | 라이브러리 API | 선언한 approved reason |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 파일 타임스탬프 | `getFirstInstallTime()`과 `getLastUpdateTime()`은 앱 컨테이너 안의 메타데이터를 읽습니다. `firstInstallTimeSync`는 처음 접근할 때 메타데이터를 읽고 이후 캐시를 반환합니다. `lastUpdateTimeSync`는 iOS에서 `-1`을 반환합니다. | `C617.1`. [Expo Application](https://github.com/expo/expo/blob/5729befbfdb34e4be8880c19b3c5eff99bd04795/packages/expo-application/ios/PrivacyInfo.xcprivacy)도 사용합니다. |
| 디스크 공간 | `totalDiskCapacity`, `getFreeDiskStorage()` 및 레거시 API | `E174.1`, `85F4.1`. [Expo FileSystem](https://github.com/expo/expo/blob/5729befbfdb34e4be8880c19b3c5eff99bd04795/packages/expo-file-system/ios/PrivacyInfo.xcprivacy)도 사용합니다. |
| 시스템 부팅 시각 | `getUptime()`은 앱 이벤트 사이의 경과 시간이나 타이머에, `startupTime`은 앱 이벤트의 uptime을 절대 타임스탬프로 변환하는 데 사용합니다. | `35F9.1`: 경과 시간·타이머. `8FFB.1`: 앱 이벤트 타임스탬프. |
각 `approved reason`에는 [Apple이 정한 사용 제한](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api)이 적용됩니다. 디스크 공간 데이터는 사용자에게 저장 공간을 보여 주거나 저장 공간에 따라 앱을 동작시키는 데 사용하며, 기기 밖으로 전송하는 데 제한이 있습니다.
iOS에서 `getUptime()`과 `startupTime`은 표에 적힌 앱 이벤트 시간 측정 목적으로만 사용해야 합니다. 원시 기기 가동 시간과 부팅 타임스탬프를 일반 기기 정보로 표시·수집하거나 기기 밖으로 전송하거나 핑거프린팅에 사용하면 안 됩니다. `35F9.1`에서는 앱 내 이벤트 사이의 경과 시간만 기기 밖으로 전송할 수 있습니다. `8FFB.1`에서는 앱 내 이벤트를 변환한 절대 타임스탬프만 기기 밖으로 전송할 수 있습니다. [시간 측정 API 예제](/react-native-nitro-device-info/ko/api/device-info.md#getuptime-number)를 참고하세요. Expo Device도 `35F9.1`을 선언하지만, 이 선언이 더 넓은 용도를 허용하지는 않습니다.
라이브러리 자체는 데이터 수집이나 추적을 선언하지 않습니다. 앱의 데이터 수집·추적과 다른 SDK에 필요한 선언은 앱에서 관리해야 합니다. 이 API를 기기 핑거프린팅에 사용하지 마세요.
iOS 앱을 빌드하거나 아카이브한 뒤 `NitroDeviceInfo_privacy.bundle/PrivacyInfo.xcprivacy`가 앱에 포함됐는지 확인하세요. 기존 앱 수준의 privacy info manifest는 그대로 둘 수 있습니다.
### Android 설정 \{#android-configuration}
Android 앱을 다시 빌드하면 Gradle의 autolinking으로 라이브러리를 등록합니다. 권한이 필요한 API에는 추가 설정이 필요할 수 있습니다. [Expo 설정](/react-native-nitro-device-info/ko/guide/expo-setup.md)을 참고하세요.
### Expo 앱 \{#expo-apps}
개발 빌드 또는 EAS Build를 사용하세요. Expo Go에는 이 네이티브 모듈이 없습니다. 설치, 네이티브 설정, 재빌드 절차는 [Expo 설정](/react-native-nitro-device-info/ko/guide/expo-setup.md)을 따르세요.
## 설치 확인 \{#verify-installation}
앱에 다음 코드를 추가하세요.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
console.log('Device ID:', DeviceInfoModule.deviceId);
console.log('Brand:', DeviceInfoModule.brand);
console.log('System Version:', DeviceInfoModule.systemVersion);
```
콘솔에 기기 정보가 출력되면 설치가 완료된 것입니다.
## 다음 단계 \{#next-steps}
앱에서 API를 사용하는 방법은 [빠른 시작](/react-native-nitro-device-info/ko/guide/quick-start.md)에서 확인하세요.
- [API 레퍼런스](/react-native-nitro-device-info/ko/api/index.md): 사용 가능한 전체 API
- [예제](/react-native-nitro-device-info/ko/examples/basic-usage.md): 자주 쓰는 활용 방법
- [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md): `react-native-device-info`에서 전환하는 방법
---
url: /react-native-nitro-device-info/ko/guide/introduction.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 소개 \{#introduction}
`react-native-nitro-device-info`는 [Nitro Modules](https://nitro.margelo.com/)를 사용해 Swift와 Kotlin으로 구현한 네이티브 코드에서 기기 정보를 읽습니다. 동기 속성, 동기 메서드, Promise 메서드, React 훅을 제공합니다.
## 작업에 맞는 문서 찾기 \{#start-with-your-task}
| 작업 | 먼저 읽을 문서 |
| ----------------------------- | ---------------------------------------------------------------------- |
| React Native 앱에 설치 | [시작하기](/react-native-nitro-device-info/ko/guide/getting-started.md) |
| Expo 앱에 설치 | [Expo 설정](/react-native-nitro-device-info/ko/guide/expo-setup.md) |
| 기기 정보 읽기 | [빠른 시작](/react-native-nitro-device-info/ko/guide/quick-start.md) |
| 기기 상태가 바뀔 때 컴포넌트 갱신 | [React 훅 가이드](/react-native-nitro-device-info/ko/guide/react-hooks.md) |
| `react-native-device-info` 교체 | [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md) |
| 웹 또는 서버 렌더링용 빌드 | [웹 지원](/react-native-nitro-device-info/ko/guide/web-support.md) |
| 정확한 시그니처와 플랫폼별 fallback 값 확인 | [API 레퍼런스](/react-native-nitro-device-info/ko/api/index.md) |
| AI 도우미에서 문서 사용 | [MCP 연동](/react-native-nitro-device-info/ko/guide/mcp-integration.md) |
## 네이티브 API와 호환 API 중 선택하기 \{#choose-an-api-entry-point}
패키지 루트에서는 네이티브 API를, `/compat`에서는 호환 API를 import할 수 있습니다. 두 API는 이름과 반환 타입이 다릅니다.
```typescript
// Native API: named singleton, properties, and methods.
import { DeviceInfoModule } from 'react-native-nitro-device-info';
const model = DeviceInfoModule.model;
const battery = DeviceInfoModule.getBatteryLevel();
```
```typescript
// Compatibility API: react-native-device-info-style functions.
import DeviceInfo from 'react-native-nitro-device-info/compat';
async function readBattery() {
return await DeviceInfo.getBatteryLevel();
}
const model = DeviceInfo.getModel();
```
호환 계층은 `react-native-device-info` 15.x를 대상으로 합니다. 전환 전에 [fallback 값과 동작 차이](/react-native-nitro-device-info/ko/api/migration.md#compat-layer-caveats)를 확인하세요.
## 플랫폼과 반환값 \{#platforms-and-return-values}
- **iOS**: 라이브러리의 배포 대상은 15.1 이상입니다.
- **Android**: 라이브러리의 최소 SDK는 API 24(Android 7.0)입니다.
- **웹**: 브라우저 API로 읽을 수 있는 값은 JavaScript 구현에서 제공합니다. 나머지 API는 fallback 값을 반환합니다. [웹 지원](/react-native-nitro-device-info/ko/guide/web-support.md)을 참고하세요.
React Native와 Nitro 버전에 따라 더 높은 플랫폼 버전이 필요할 수 있습니다. 동기 호출은 호출한 스레드에서 실행되며 결과를 직접 반환합니다. 특정 실행 시간을 보장하지는 않습니다.
지원하지 않거나 읽을 수 없는 값은 `"unknown"`, `-1`, `false`, 빈 컬렉션일 수 있습니다. 결과를 사용하기 전에 각 API의 반환값과 동작을 확인하세요.
## 기기 정보와 보안 \{#device-information-and-security}
[로컬 무결성 검사](/react-native-nitro-device-info/ko/api/device-integrity.md)는 루팅 또는 탈옥 징후를 탐지합니다. 우회할 수 있는 검사이므로 기기의 신뢰성을 증명하지 않습니다.
백엔드에서 검증할 토큰이 필요하면 별도 선택 패키지인 [`react-native-nitro-device-integrity`](/react-native-nitro-device-info/ko/api/device-attestation.md)를 사용하세요.
구조와 성능 측정 방법은 [Nitro Module을 사용하는 이유](/react-native-nitro-device-info/ko/guide/why-nitro-module.md)에서 설명합니다.
---
url: /react-native-nitro-device-info/ko/guide/mcp-integration.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# AI 연동용 MCP 서버 \{#mcp-server-for-ai-integration}
MCP(Model Context Protocol) 서버를 사용하면 Claude, Cursor, Copilot 같은 AI 코딩 도우미가 react-native-nitro-device-info 문서를 조회할 수 있습니다.
## 문서 버전과 import 경로 확인 \{#check-the-documentation-version-and-entry-point}
MCP 패키지에는 빌드 시점의 API 명세와 Markdown이 포함됩니다. 실행 중에 최신 웹사이트를 읽어 오지는 않습니다. 설치한 라이브러리 버전의 API를 설명하는 서버 릴리스를 사용하고, 설치된 TypeScript 선언과 대조하세요.
AI와 함께 코드를 바꿀 때 다음 정보를 지정하세요.
- 설치한 라이브러리 버전과 대상 플랫폼
- 패키지 루트의 네이티브 API를 import할지, `/compat` API를 import할지
- Expo 개발 빌드, 일반 React Native, 웹/SSR 중 사용 환경
- 값을 읽을 수 없는 경우와 Promise가 reject될 가능성
정확한 시그니처는 `get_api`, 설정과 플랫폼 주의 사항은 `search_docs`로 조회하세요. 검색 결과에는 페이지 일부만 포함될 수 있습니다.
웹사이트는 [llms.txt](https://l2hyunwoo.github.io/react-native-nitro-device-info/ko/llms.txt)와 [llms-full.txt](https://l2hyunwoo.github.io/react-native-nitro-device-info/ko/llms-full.txt)도 제공합니다. 이 파일은 설치한 npm 릴리스가 아닌 웹사이트 빌드를 기준으로 합니다.
## MCP란? \{#what-is-mcp}
[MCP(Model Context Protocol)](https://modelcontextprotocol.io/)는 Anthropic의 공개 프로토콜로, AI 도구가 외부 데이터와 도구에 접근할 수 있게 합니다. react-native-nitro-device-info용 MCP 서버는 다음 작업을 지원합니다.
- API 선언과 문서 섹션 조회
- 올바른 타입을 사용하는 TypeScript 코드 작성
- 플랫폼별 질문에 답변(iOS와 Android)
- 자주 생기는 문제 해결
## 빠른 설정(권장) \{#quick-setup-recommended}
React Native 프로젝트에서 `init`을 실행하면 Cursor와 Claude Code의 MCP 설정을 자동으로 생성합니다.
```bash
cd your-react-native-project
npx @react-native-nitro-device-info/mcp-server init
```
다음 파일을 만듭니다.
- `.cursor/mcp.json`: Cursor IDE 설정
- `.mcp.json`: Claude Code 프로젝트 설정
IDE를 재시작한 뒤 질문하세요.
## 수동 설치 \{#manual-installation}
### npx 사용 \{#using-npx}
설치 없이 AI 도구가 다음 명령을 실행하도록 설정하세요.
```bash
npx @react-native-nitro-device-info/mcp-server
```
### 전역 설치 \{#global-installation}
```bash
npm install -g @react-native-nitro-device-info/mcp-server
```
설치 후 실행하세요.
```bash
nitro-device-info-mcp
```
## 수동 설정 \{#manual-configuration}
### Claude Desktop \{#claude-desktop}
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"nitro-device-info": {
"command": "npx",
"args": ["@react-native-nitro-device-info/mcp-server"]
}
}
}
```
저장 후 Claude Desktop을 완전히 종료하고(Cmd+Q) 다시 실행하세요.
### Cursor IDE \{#cursor-ide}
프로젝트 루트에 `.cursor/mcp.json`을 만드세요.
```json
{
"mcpServers": {
"nitro-device-info": {
"command": "npx",
"args": ["@react-native-nitro-device-info/mcp-server"]
}
}
}
```
### 다른 MCP 클라이언트 \{#other-mcp-clients}
stdio 전송을 지원하는 MCP 클라이언트는 다음과 같이 설정하세요.
```json
{
"command": "npx",
"args": ["@react-native-nitro-device-info/mcp-server"],
"transport": "stdio"
}
```
## 제공 도구 \{#available-tools}
서버는 세 도구를 제공합니다.
| 도구 | 용도 | 질문 예시 |
| ------------- | ----------------- | ------------------------- |
| `search_docs` | 자연어로 문서 검색 | "기기 모델을 어떻게 읽나요?" |
| `get_api` | 특정 API의 상세 정보 | "getBatteryLevel을 보여 주세요" |
| `list_apis` | 범주·플랫폼·타입별 API 목록 | "네트워크 API를 모두 보여 주세요" |
## 사용 예제 \{#usage-examples}
### 기본 API 질문 \{#basic-api-questions}
> "기기의 배터리 잔량을 어떻게 읽나요?"
AI가 MCP 서버를 조회하고 다음 코드를 제시할 수 있습니다.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Get battery level (0.0 to 1.0)
const batteryLevel = DeviceInfoModule.getBatteryLevel();
console.log(batteryLevel < 0
? 'Battery: unavailable'
: `Battery: ${Math.round(batteryLevel * 100)}%`);
```
### API 찾기 \{#api-discovery}
> "네트워크 정보를 읽는 API에는 무엇이 있나요?"
### 플랫폼별 질문 \{#platform-specific-questions}
> "iOS 시뮬레이터에서 getIpAddress가 빈 값을 반환하는 이유는 무엇인가요?"
### 코드 생성 \{#code-generation}
> "모든 기기 정보를 화면에 표시하는 코드를 만들어 주세요"
## 동작 확인 \{#verification}
설정 후 서버가 동작하는지 확인하세요.
1. AI 도구에 "nitro-device-info MCP 서버는 어떤 도구를 제공하나요?"라고 질문합니다.
2. 응답에 `search_docs`, `get_api`, `list_apis`가 있는지 확인합니다.
## 문제 해결 \{#troubleshooting}
### 서버가 로드되지 않는 경우 \{#server-not-loading}
1. Node.js 버전을 확인하세요(v20.0.0 이상 필요).
```bash
node --version
```
2. npx 동작을 확인하세요.
```bash
npx --version
```
3. 서버를 직접 테스트하세요.
```bash
npx @react-native-nitro-device-info/mcp-server --help
```
4. Claude Desktop 로그를 확인하세요(macOS).
```bash
tail -f ~/Library/Logs/Claude/mcp*.log
```
### 자주 생기는 문제 \{#common-issues}
| 문제 | 원인 | 해결 방법 |
| ------------------- | ----------------- | ----------------------- |
| "command not found" | PATH에 Node.js가 없음 | Node.js 재설치 또는 PATH에 추가 |
| "npm ERR! 404" | 패키지가 배포되지 않음 | npm 배포를 기다리거나 소스에서 빌드 |
| JSON 구문 오류 | 잘못된 설정 문법 | 후행 쉼표와 따옴표 확인 |
| 서버 시간 초과 | 느린 네트워크 또는 레지스트리 | 오프라인 사용을 위해 전역 설치 |
## 요구 사항 \{#requirements}
- Node.js 20.0.0 이상
- npm 10.0.0 이상
- MCP를 지원하는 AI 도구(Claude Desktop, Cursor 등)
---
url: /react-native-nitro-device-info/ko/guide/quick-start.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 빠른 시작 \{#quick-start}
먼저 [시작하기](/react-native-nitro-device-info/ko/guide/getting-started.md) 또는 [Expo 설정](/react-native-nitro-device-info/ko/guide/expo-setup.md)을 완료하고 네이티브 앱을 다시 빌드하세요.
이 페이지는 패키지 루트의 네이티브 API를 사용합니다. `react-native-device-info` 형식의 함수는 [`/compat` API](/react-native-nitro-device-info/ko/api/migration.md)을 사용하세요.
## 속성과 메서드, Promise 사용하기 \{#read-a-property-call-a-method-await-a-promise}
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Properties: no parentheses and no await.
const model = DeviceInfoModule.model;
const isTablet = DeviceInfoModule.isTablet;
// Synchronous methods: parentheses, no await.
const batteryLevel = DeviceInfoModule.getBatteryLevel();
const hasGms = DeviceInfoModule.getHasGms();
// Promise-based methods: await inside an async function.
async function readNetworkInfo() {
try {
const [ipAddress, carrier] = await Promise.all([
DeviceInfoModule.getIpAddress(),
DeviceInfoModule.getCarrier(),
]);
console.log({ ipAddress, carrier });
} catch (error) {
console.error('Could not read network information', error);
}
}
console.log({ model, isTablet, hasGms });
console.log(batteryLevel < 0
? 'Battery: unavailable'
: `Battery: ${Math.round(batteryLevel * 100)}%`);
void readNetworkInfo();
```
`getBatteryLevel()`은 값을 읽을 수 없을 때 `-1`을 반환합니다. `getHasGms()`는 iOS에서 `false`를 반환합니다. Promise를 반환한다고 해서 정해진 시간 안에 작업이 완료되는 것은 아닙니다.
## React에서 값이 바뀔 때 화면 갱신하기 \{#display-changing-values-in-react}
getter를 직접 호출하면 그 시점의 값을 읽습니다. 값이 바뀔 때 컴포넌트도 갱신해야 한다면 훅을 사용하세요.
```tsx
import { Text, View } from 'react-native';
import {
DeviceInfoModule,
useBatteryLevel,
} from 'react-native-nitro-device-info';
export default function DeviceInfoScreen() {
const batteryLevel = useBatteryLevel();
return (
Model: {DeviceInfoModule.model}
OS: {DeviceInfoModule.systemVersion}
Battery: {batteryLevel === null
? 'Loading or unavailable'
: `${Math.round(batteryLevel * 100)}%`}
);
}
```
`useBatteryLevel()`은 마운트 후 값을 읽고 5초마다 폴링합니다. 처음 읽기 전이나 배터리 잔량을 읽을 수 없을 때는 `null`을 반환합니다. 갱신 간격과 훅별 반환 타입은 [React 훅](/react-native-nitro-device-info/ko/guide/react-hooks.md)에서 확인하세요.
## 단위와 미지원 값 확인 \{#check-units-and-unsupported-values}
| 값 | 단위 또는 의미 | 사용 전 확인 사항 |
| -------------------------------- | ------------------------------ | ------------------------------------ |
| `totalMemory`, `getUsedMemory()` | 바이트. 각각 기기 RAM과 현재 앱 메모리 | 플랫폼에 따라 지원 여부가 다릅니다. |
| `getBatteryLevel()` | `0`\~`1`의 비율 | `-1`은 조회 불가를 뜻합니다. |
| `getBrightness()` | iOS에서 `0`\~`1`의 비율 | Android에서는 `-1`입니다. |
| `apiLevel` | Android API 수준 | iOS에서는 `-1`입니다. |
| `uniqueId` | iOS IDFV 또는 Android ANDROID_ID | 바뀔 수 있습니다. 계정이나 영구 기기 식별자로 사용하지 마세요. |
정확한 시그니처, 캐시, 권한, 플랫폼 동작은 [DeviceInfo 모듈](/react-native-nitro-device-info/ko/api/device-info.md)을 참고하세요. 웹에서는 [fallback 값](/react-native-nitro-device-info/ko/guide/web-support.md)을 사용합니다.
## 다음 단계 \{#next-steps}
- [기본 사용법](/react-native-nitro-device-info/ko/examples/basic-usage.md): 작업별 예제
- [API 레퍼런스](/react-native-nitro-device-info/ko/api/index.md): 속성, 메서드, 훅, 타입 찾기
- [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md): 호환 API와 네이티브 API 선택
---
url: /react-native-nitro-device-info/ko/guide/react-hooks.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# React 훅 가이드 \{#react-hooks-guide}
React Native 앱에서 React 훅으로 기기 속성의 변화를 확인하고 화면을 갱신하는 방법을 설명합니다.
## 개요 \{#overview}
React 훅은 마운트 후 기기 getter를 읽고 값을 갱신하려고 일정 간격으로 폴링합니다. 컴포넌트를 마운트 해제하면 타이머를 정리합니다. 네이티브 이벤트를 구독하거나 즉시 알림을 보장하지는 않습니다.
**제공하는 기능**:
- 컴포넌트 마운트 해제 시 자동 정리
- 기기 상태 변화에 따른 화면 갱신
- 익숙한 React 훅 패턴
- 기본 TypeScript 지원
## 설치 \{#installation}
훅은 `react-native-nitro-device-info`에 포함됩니다.
```bash
# npm
npm install react-native-nitro-device-info react-native-nitro-modules
# yarn
yarn add react-native-nitro-device-info react-native-nitro-modules
# Don't forget pod install for iOS
cd ios && pod install
```
## 갱신 간격과 초기값 \{#update-intervals-and-initial-values}
| 패키지 루트의 훅 | 폴링 간격 | 초기값 또는 조회 불가 값 |
| ------------------------ | ------ | ---------------------------------------- |
| `useBatteryLevel()` | 5초 | `null` |
| `useBatteryLevelIsLow()` | 2초 | `null`. 배터리가 부족하지 않을 때도 반환합니다. |
| `usePowerState()` | 5초 | 처음에는 `{}`. `batteryLevel`은 `-1`일 수 있습니다. |
| 헤드폰 훅 | 1초 | 처음에는 `false` |
| `useBrightness()` | 500밀리초 | 처음에는 `null`. Android에서는 `-1` |
타이머는 JavaScript 스케줄링에 의존하며 백그라운드에서 지연될 수 있습니다. 상태가 바뀐 순간에 훅의 반환값이 바뀌는 것은 아닙니다.
예제에서는 패키지 루트에서 훅을 import합니다. `/compat`의 헤드폰 훅은 `{ loading, result }`를 반환합니다. [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md)를 참고하세요.
## 간단한 예제 \{#quick-examples}
### 배터리 관찰 \{#battery-monitoring}
배터리 잔량에 따라 자동으로 다시 렌더링합니다.
```tsx
import { useBatteryLevel, usePowerState } from 'react-native-nitro-device-info';
function BatteryWidget() {
const batteryLevel = useBatteryLevel();
const powerState = usePowerState();
return (
Battery
{batteryLevel !== null
? `${Math.round(batteryLevel * 100)}%`
: 'Loading or unavailable'}
{powerState.batteryState === 'charging' ? '⚡ Charging' : '🔋 On Battery'}
);
}
// Note: styles (widget, label, value, status) need to be defined in a StyleSheet
```
### 배터리 부족 알림 \{#low-battery-alerts}
배터리가 부족할 때 경고를 표시합니다.
```tsx
import { useBatteryLevelIsLow } from 'react-native-nitro-device-info';
function LowBatteryAlert() {
const lowBattery = useBatteryLevelIsLow();
// Only renders when battery is below threshold
if (lowBattery === null) {
return null;
}
return (
⚠️ Low Battery: {Math.round(lowBattery * 100)}%
Please connect your charger
);
}
// Note: styles (alert, alertText, alertHint) need to be defined in a StyleSheet
```
### 헤드폰 감지 \{#headphone-detection}
오디오 출력에 맞춰 UI를 바꿉니다.
```tsx
import {
useIsHeadphonesConnected,
useIsWiredHeadphonesConnected,
useIsBluetoothHeadphonesConnected
} from 'react-native-nitro-device-info';
function AudioOutputIndicator() {
const anyHeadphones = useIsHeadphonesConnected();
const wiredHeadphones = useIsWiredHeadphonesConnected();
const bluetoothHeadphones = useIsBluetoothHeadphonesConnected();
const getOutputIcon = () => {
if (bluetoothHeadphones) return '🎧 Bluetooth';
if (wiredHeadphones) return '🔌 Wired';
return '🔊 Speaker';
};
return (
{getOutputIcon()}
);
}
```
### 밝기 관찰(iOS) \{#brightness-monitoring-ios}
화면 밝기 변화를 확인합니다.
```tsx
import { useBrightness } from 'react-native-nitro-device-info';
import { Platform } from 'react-native';
function BrightnessDisplay() {
const brightness = useBrightness();
if (Platform.OS === 'android') {
return Brightness monitoring is iOS only;
}
if (brightness === null) {
return Loading...;
}
return (
Brightness: {Math.round(brightness * 100)}%
);
}
// Note: styles.brightnessBar needs to be defined in a StyleSheet
```
## 전체 예제: 기기 상태 대시보드 \{#complete-example-device-monitor-dashboard}
```tsx
import React from 'react';
import { View, Text, StyleSheet, ScrollView } from 'react-native';
import {
useBatteryLevel,
usePowerState,
useBatteryLevelIsLow,
useIsHeadphonesConnected,
useIsWiredHeadphonesConnected,
useIsBluetoothHeadphonesConnected,
useBrightness,
} from 'react-native-nitro-device-info';
export function DeviceMonitorDashboard() {
// Battery hooks
const batteryLevel = useBatteryLevel();
const powerState = usePowerState();
const lowBattery = useBatteryLevelIsLow();
// Headphone hooks
const headphones = useIsHeadphonesConnected();
const wiredHeadphones = useIsWiredHeadphonesConnected();
const bluetoothHeadphones = useIsBluetoothHeadphonesConnected();
// Display hooks
const brightness = useBrightness();
return (
Device Monitor
{/* Battery Section */}
🔋 Battery
{lowBattery !== null && (
⚠️ Low Battery!
)}
{/* Audio Section */}
🎧 Audio Output
{/* Display Section */}
📱 Display
= 0
? formatPercent(brightness)
: 'N/A'
}
/>
);
}
function Row({ label, value }: { label: string; value: string }) {
return (
{label}
{value}
);
}
function formatPercent(value: number | null): string {
if (value === null) return 'Loading...';
return `${Math.round(value * 100)}%`;
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 16,
},
section: {
marginBottom: 20,
padding: 12,
backgroundColor: '#f5f5f5',
borderRadius: 8,
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 8,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: 4,
},
label: {
fontWeight: '500',
},
value: {
color: '#666',
},
warning: {
backgroundColor: '#fff3cd',
padding: 8,
borderRadius: 4,
marginTop: 8,
},
warningText: {
color: '#856404',
},
});
```
## 문제 해결 \{#troubleshooting}
### 훅이 계속 null을 반환하는 경우 \{#hook-returns-null-indefinitely}
네이티브 모듈이 올바르게 연결됐는지 확인하세요.
```tsx
import { DeviceInfoModule } from 'react-native-nitro-device-info';
// Debug: check if module is available
console.log('DeviceInfoModule:', DeviceInfoModule);
```
### 기기 상태가 바뀌어도 화면이 갱신되지 않는 경우 \{#updates-not-received}
훅의 값이 갱신되지 않으면 앱이 포그라운드에 있는지 확인하세요.
### 밝기가 -1인 경우 \{#brightness-returns--1}
Android에서 예상되는 동작입니다. 밝기를 확인하는 훅은 iOS만 지원합니다.
## 관련 문서 \{#see-also}
- [훅 API 레퍼런스](/react-native-nitro-device-info/ko/api/hooks.md): 전체 훅 시그니처와 타입
- [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md): react-native-device-info에서 전환
- [기본 사용 예제](/react-native-nitro-device-info/ko/examples/basic-usage.md): 추가 사용법
---
url: /react-native-nitro-device-info/ko/guide/web-support.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# 웹 지원 \{#web-support}
v1.8.0부터 웹: 제한적 지원 / fallback
웹용 entry point는 v1.8.0에 도입했습니다. 각 [API 레퍼런스 섹션](/react-native-nitro-device-info/ko/api/index.md#availability-badges)은 브라우저에서 얻는 값과 고정 fallback 값을 구별합니다.
`react-native-nitro-device-info`는 JSI/네이티브 기술인 [Nitro](https://nitro.margelo.com/)를 사용합니다. 브라우저에는 네이티브 모듈이 없으므로 웹에서는 **패키지를 오류 없이 import하고 지원하지 않는 값은 명시적인 fallback 값으로 반환하는 것**을 목표로 합니다. 모든 기기 API를 재현하지는 않습니다.
따라서 네이티브와 웹(react-native-web, Next.js SSR)을 함께 대상으로 하는 모노레포에서도 웹 빌드 오류 없이 패키지를 사용할 수 있습니다.
## 동작 방식 \{#how-it-works}
패키지는 `DeviceInfo` 인터페이스 전체를 구현한 순수 JavaScript 웹 구현(`DeviceInfo.web.ts`)을 포함합니다. 번들러가 자동으로 선택하므로 **별도 패키지 설치나 import 경로 변경이 필요하지 않습니다**.
```ts
// Same import on every platform.
import { DeviceInfoModule, createDeviceInfo } from 'react-native-nitro-device-info';
```
일반적인 웹 toolchain에서는 다음 두 방식으로 웹 구현을 선택합니다.
- **Metro / react-native-web(Expo web)**: Metro는 `.web.ts` 플랫폼 확장자를 해석하여 `index.ts`보다 `index.web.ts`를 먼저 찾습니다. 웹 플랫폼에서는 `browser` export 조건도 적용합니다.
- **webpack / Next.js**: `package.json`의 `exports`는 웹 빌드를 가리키는 `"browser"` 조건을 선언합니다. webpack은 `target: 'web'`에서 이 조건을 따릅니다.
서버 번들러가 네이티브 entry point를 선택하면 HybridObject는 처음 속성에 접근할 때 생성됩니다. 이 entry point를 import하는 것만으로는 HybridObject가 생성되지 않습니다. `DeviceInfoModule.model` 읽기, 메서드 호출, `createDeviceInfo()` 호출은 여전히 네이티브 바인딩이 필요하므로 서버에서 예외가 발생할 수 있습니다.
## 훅과 compat 진입점 \{#hooks-and-compat-entry}
v1.9.0부터
훅과 `/compat` 진입점은 패키지의 조건부 export로 `DeviceInfoModule` singleton을 import합니다. 따라서 브라우저 번들은 `.web.js` 확장자 우선순위가 없어도 웹 구현을 선택합니다. `browser`와 `source` 조건을 함께 적용하면 루트의 `browser` export를 먼저 선택합니다.
## 브라우저에서 읽는 값과 fallback 값 \{#what-is-real-vs-fallback}
브라우저 API로 조회할 수 있으면 실제 값을 반환합니다. 나머지는 네이티브 구현이 미지원 플랫폼에서 반환하는 상수(`"unknown"` / `-1` / `false` / `[]`)를 반환합니다. **실제 값처럼 보이는 데이터를 만들어 반환하지 않습니다.**
### 브라우저 API에서 얻는 값(지원할 때) \{#derived-from-a-browser-api-when-available}
| 멤버 | 출처 |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `systemName` | `navigator.userAgent`에서 추출(`"Windows"`/`"macOS"`/`"iOS"`/`"Android"`/`"Linux"`, 그 외 `"web"`) |
| `systemLanguage` | `navigator.language` |
| `brand`, `manufacturer` | `navigator.vendor` |
| `totalMemory` | `navigator.deviceMemory` × 1024³. 명세에 정한 구간 단위의 대략적인 값이며 지원하지 않으면 `-1` |
| `getIsLandscape()` | `screen.width > screen.height` |
| `getUserAgent()` | `navigator.userAgent` |
| `getBatteryLevel()`, `getPowerState()`, `getIsBatteryCharging()` | Battery Status API(`navigator.getBattery()`)를 한 번 요청합니다. getter는 이때 얻은 BatteryManager 객체에서 현재 값을 읽습니다. API가 없거나 요청이 거부되면 `-1` / `"unknown"` |
| `isLowBatteryLevel(threshold)` | 브라우저 배터리 잔량과 지정한 임계값을 비교합니다. 잔량을 읽지 못하면 `false` |
오래된 브라우저나 `navigator`/`screen`이 없는 서버처럼 필요한 전역 객체가 없으면 예외 대신 fallback 상수를 반환합니다.
### 웹에서 항상 fallback 상수를 반환하는 값 \{#always-a-fallback-constant-on-web}
- 모든 Android `Build.*` 필드(`androidId`, `serialNumber`, `fingerprint`, `board`, `bootloader`, `apiLevel`, `securityPatch`, …)
- 통신사 / MCC / MNC 정보
- 디스크 용량과 사용 메모리
- 헤드폰, 위치, 노치, Dynamic Island 검사
- 비행기 모드: 브라우저에서 상태를 판단할 수 없으므로 `getIsAirplaneMode()`는 `false`
- 무결성 검사: `isDeviceCompromised()`는 `false`
- 앱 메타데이터(`version`, `buildNumber`, `bundleId`, `applicationName`, …)
- Windows 전용 필드(`isMouseConnected`, `hostNames`, …)
### Promise 메서드 \{#promise-methods}
Promise 메서드는 시그니처를 유지하고 fallback 값으로 **resolve**합니다. reject하지 않으므로 기존 `await` 호출을 유지할 수 있습니다.
```ts
await DeviceInfoModule.getIpAddress(); // "unknown"
await DeviceInfoModule.verifyDeviceIntegrity(); // false
```
예외적으로 `getDeviceToken()`은 웹에서 **reject**합니다. 이 메서드는 웹에 대응 기능이 없는 Apple DeviceCheck를 사용하며, Android에서 문서화한 동작과 같습니다.
## SSR 주의 사항 \{#ssr-notes}
웹 구현은 브라우저 전역 객체를 확인하므로 서버 렌더링 중에도 fallback 값을 반환할 수 있습니다. 단, 서버 번들이 웹 구현을 선택했을 때만 적용됩니다.
서버가 네이티브 entry point를 선택한다면 기기 정보는 `useEffect` 같은 클라이언트 전용 코드에서 읽으세요. React는 서버에서도 컴포넌트 본문을 렌더링하므로 본문에서 속성을 읽으면 네이티브 초기화가 실행될 수 있습니다. SSR 중에 값을 읽기 전에 프레임워크의 서버 모듈 해석 방식을 확인하세요.
서버와 브라우저의 값은 다를 수 있습니다. 브라우저에서 얻은 값 때문에 하이드레이션 불일치가 생긴다면 먼저 일관된 로딩 상태를 렌더링하세요.
---
url: /react-native-nitro-device-info/ko/guide/why-nitro-module.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# Nitro Module을 사용하는 이유 \{#why-nitro-module}
[Nitro Modules](https://nitro.margelo.com/)는 JSI(JavaScript Interface)를 통해 JavaScript와 네이티브 코드를 연결합니다. 이 라이브러리는 Swift와 Kotlin으로 구현한 Nitro HybridObject를 사용합니다.
## JS 함수 호출로 네이티브 모듈 함수를 어떻게 호출할 수 있을까? \{#how-a-call-reaches-native-code}
1. `DeviceInfo.nitro.ts`에서 속성, 메서드, 반환 타입을 선언합니다.
2. Nitrogen이 C++, Swift, Kotlin 바인딩을 생성합니다.
3. `DeviceInfoModule`은 처음 접근할 때 네이티브 HybridObject를 생성합니다.
4. 속성을 읽거나 메서드를 호출하면 바인딩을 통해 네이티브 구현을 실행합니다.
값을 캐시할지 운영체제에서 조회할지는 네이티브 구현이 결정합니다.
```typescript
import { DeviceInfoModule } from 'react-native-nitro-device-info';
const model = DeviceInfoModule.model; // Synchronous property.
const battery = DeviceInfoModule.getBatteryLevel(); // Synchronous method.
async function readIpAddress() {
return await DeviceInfoModule.getIpAddress(); // Promise-based method.
}
```
## 동기 getter를 사용할 때 알아둘 점 \{#synchronous-access-and-its-limits}
동기 getter는 Promise를 기다리지 않고 값을 읽을 수 있어 기기 메타데이터를 조회하거나 컴포넌트에서 한 번만 값을 읽을 때 유용합니다.
동기 작업도 호출한 스레드에서 실행합니다. getter가 운영체제를 조회하거나 조회한 값을 캐시에 저장할 수 있습니다. JSI가 1밀리초 이내의 완료를 보장하지는 않습니다.
이름이나 다른 기기 정보 라이브러리의 동작만으로 호출 방식을 판단하지 마세요. [API 레퍼런스](/react-native-nitro-device-info/ko/api/index.md)에서 속성, 동기 메서드, Promise 메서드를 구별하세요.
## React 훅은 폴링으로 값을 갱신합니다 \{#react-hooks-use-polling}
제공하는 훅은 일정 간격으로 네이티브 getter를 읽고 컴포넌트를 마운트 해제할 때 타이머를 정리합니다. 네이티브 기기 이벤트를 구독하지 않습니다.
예를 들어 `useBatteryLevel()`은 5초마다 조회합니다. 배터리가 바뀌는 즉시 알림을 주지는 않습니다. 훅별 폴링 간격은 [React 훅 가이드](/react-native-nitro-device-info/ko/guide/react-hooks.md)에서 확인하세요.
## 패키지 루트와 `/compat` API의 차이 \{#migration-uses-a-separate-entry-point}
패키지 루트에서 export하는 API에서는 `DeviceInfoModule.model`처럼 속성을 읽습니다. `/compat`에서 export하는 API에서는 `DeviceInfo.getModel()`처럼 함수를 호출합니다.
호환 계층은 `react-native-device-info` 15.x를 대상으로 합니다. 일부 메서드는 fallback 값을 반환하며 네이티브 플랫폼 동작도 다를 수 있습니다. import 경로를 바꾸기 전에 [마이그레이션 가이드](/react-native-nitro-device-info/ko/api/migration.md)를 확인하세요.
## 앱에서 성능 측정하기 \{#measure-in-your-app}
레포지터리의 [벤치마크 앱](https://github.com/l2hyunwoo/react-native-nitro-device-info/tree/main/example/benchmark)으로 앱에 필요한 호출을 비교하세요.
기기, OS, 라이브러리 버전, 빌드 모드를 기록하세요. 캐시에 값이 저장되어 있었는지도 함께 기록하세요. 호출 지연 시간과 렌더링에 미치는 영향을 함께 측정하세요. 이 문서는 지연 시간이나 다른 라이브러리 대비 속도 향상을 보장하지 않습니다.
## 다음 단계 \{#next-steps}
- [시작하기](/react-native-nitro-device-info/ko/guide/getting-started.md): 의존성과 네이티브 설정
- [빠른 시작](/react-native-nitro-device-info/ko/guide/quick-start.md): 속성, 메서드, React 사용법
- [API 레퍼런스](/react-native-nitro-device-info/ko/api/index.md): 시그니처와 플랫폼 제한
---
url: /react-native-nitro-device-info/ko/index.md
---
> For AI agents: the complete documentation index is available at /react-native-nitro-device-info/ko/llms.txt, the full documentation bundle is available at /react-native-nitro-device-info/ko/llms-full.txt.
# React Native
Nitro Device Info
> Nitro Modules로 읽는 기기 정보 ⚡️
[시작하기](/ko/guide/getting-started) | [GitHub에서 보기](https://github.com/l2hyunwoo/react-native-nitro-device-info)
## Features
- **⚡ JSI로 직접 연결**: 기존 브리지 없이 JavaScript에서 네이티브 코드 호출
- **📱 100개 이상의 속성**: 기기 정보와 시스템 상태 조회
- **📦 TypeScript 지원**: 전체 타입 정의 제공
- **🚀 동기 API**: 속성과 동기 메서드로 값 조회. Promise 메서드는 await로 결과 확인
- **🌐 플랫폼 지원**: iOS 15.1+ 및 Android API 24+ (Android 7.0+) 지원
- **🔄 마이그레이션**: react-native-device-info 15.x에서 전환하려면 import 경로를 /compat으로 변경. 전환 전에 호환성 주의 사항 확인