@parrotnavy/rn-native-updates 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +246 -0
- package/README.md +245 -0
- package/android/build.gradle +56 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/parrotnavy/nativeupdates/NativeUpdatesExceptions.kt +33 -0
- package/android/src/main/java/com/parrotnavy/nativeupdates/NativeUpdatesModule.kt +171 -0
- package/expo-module.config.json +9 -0
- package/ios/NativeUpdatesExceptions.swift +26 -0
- package/ios/NativeUpdatesModule.swift +77 -0
- package/lib/module/NativeUpdatesModule.js +5 -0
- package/lib/module/NativeUpdatesModule.js.map +1 -0
- package/lib/module/api.js +163 -0
- package/lib/module/api.js.map +1 -0
- package/lib/module/hooks/index.js +4 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/useAppUpdate.js +135 -0
- package/lib/module/hooks/useAppUpdate.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +157 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/versionUtils.js +18 -0
- package/lib/module/versionUtils.js.map +1 -0
- package/lib/typescript/src/NativeUpdatesModule.d.ts +3 -0
- package/lib/typescript/src/NativeUpdatesModule.d.ts.map +1 -0
- package/lib/typescript/src/api.d.ts +15 -0
- package/lib/typescript/src/api.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +2 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useAppUpdate.d.ts +3 -0
- package/lib/typescript/src/hooks/useAppUpdate.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +246 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/versionUtils.d.ts +3 -0
- package/lib/typescript/src/versionUtils.d.ts.map +1 -0
- package/package.json +103 -0
- package/rn-native-updates.podspec +19 -0
- package/src/NativeUpdatesModule.ts +5 -0
- package/src/api.ts +239 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAppUpdate.ts +189 -0
- package/src/index.ts +36 -0
- package/src/types.ts +315 -0
- package/src/versionUtils.ts +28 -0
package/README.ko.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# @parrotnavy/rn-native-updates
|
|
2
|
+
|
|
3
|
+
[English](./README.md)
|
|
4
|
+
|
|
5
|
+
React Native 앱 업데이트 확인 라이브러리로, 훅(Hook) 지원이 포함되어 있습니다.
|
|
6
|
+
Android는 Play Core In-App Updates, iOS는 iTunes Lookup API를 사용합니다.
|
|
7
|
+
|
|
8
|
+
## 주요 기능
|
|
9
|
+
|
|
10
|
+
- **Hook API** - `useAppUpdate()`로 React 컴포넌트에 쉽게 통합
|
|
11
|
+
- **Function API** - `react-native-version-check` 스타일의 API와 호환
|
|
12
|
+
- **Android In-App Updates** - Play Core를 통한 유연(Flexible) 및 즉시(Immediate) 업데이트 플로우
|
|
13
|
+
- **iOS App Store Check** - iTunes API 기반 버전 조회 및 캐싱
|
|
14
|
+
- **TypeScript** - 완전한 타입 정의 포함
|
|
15
|
+
- **Expo & Bare RN** - Expo 및 Bare React Native 프로젝트 모두 지원
|
|
16
|
+
|
|
17
|
+
## 설치
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @parrotnavy/rn-native-updates
|
|
21
|
+
# 또는
|
|
22
|
+
yarn add @parrotnavy/rn-native-updates
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### iOS 설정
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd ios && pod install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Android 설정
|
|
32
|
+
|
|
33
|
+
추가 설정이 필요하지 않습니다. 라이브러리가 Play Core를 자동으로 포함합니다.
|
|
34
|
+
|
|
35
|
+
> **참고**: Android In-App Updates는 Google Play Store에서 설치된 앱에서만 동작합니다.
|
|
36
|
+
|
|
37
|
+
## 사용법
|
|
38
|
+
|
|
39
|
+
### Hook API (권장)
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { useAppUpdate, UpdateType } from '@parrotnavy/rn-native-updates';
|
|
43
|
+
|
|
44
|
+
function UpdateChecker() {
|
|
45
|
+
const {
|
|
46
|
+
isChecking,
|
|
47
|
+
isUpdateAvailable,
|
|
48
|
+
currentVersion,
|
|
49
|
+
latestVersion,
|
|
50
|
+
checkUpdate,
|
|
51
|
+
openStore,
|
|
52
|
+
startUpdate, // Android 전용
|
|
53
|
+
completeUpdate, // Android 전용
|
|
54
|
+
} = useAppUpdate({
|
|
55
|
+
checkOnMount: true,
|
|
56
|
+
onError: (error) => console.log('업데이트 확인 실패:', error),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (isUpdateAvailable) {
|
|
60
|
+
return (
|
|
61
|
+
<View>
|
|
62
|
+
<Text>업데이트 가능: {latestVersion}</Text>
|
|
63
|
+
<Button title="지금 업데이트" onPress={() => startUpdate(UpdateType.IMMEDIATE)} />
|
|
64
|
+
</View>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return <Text>최신 버전입니다: {currentVersion}</Text>;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Function API
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import {
|
|
76
|
+
getCurrentVersion,
|
|
77
|
+
getLatestVersion,
|
|
78
|
+
needUpdate,
|
|
79
|
+
openStore,
|
|
80
|
+
} from '@parrotnavy/rn-native-updates';
|
|
81
|
+
|
|
82
|
+
// 현재 설치된 버전
|
|
83
|
+
const version = getCurrentVersion(); // "1.0.0"
|
|
84
|
+
|
|
85
|
+
// 스토어 최신 버전 조회
|
|
86
|
+
const latest = await getLatestVersion(); // "1.1.0"
|
|
87
|
+
|
|
88
|
+
// 업데이트 필요 여부 확인
|
|
89
|
+
const result = await needUpdate();
|
|
90
|
+
// { isNeeded: true, currentVersion: "1.0.0", latestVersion: "1.1.0", storeUrl: "..." }
|
|
91
|
+
|
|
92
|
+
// 스토어 페이지 열기
|
|
93
|
+
await openStore();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API 레퍼런스
|
|
97
|
+
|
|
98
|
+
### 훅: `useAppUpdate(options?)`
|
|
99
|
+
|
|
100
|
+
#### 옵션
|
|
101
|
+
|
|
102
|
+
| 옵션 | 타입 | 기본값 | 설명 |
|
|
103
|
+
|--------|------|---------|-------------|
|
|
104
|
+
| `checkOnMount` | `boolean` | `false` | 컴포넌트 마운트 시 자동으로 업데이트 확인 |
|
|
105
|
+
| `country` | `string` | 디바이스 로케일 | App Store 조회용 국가 코드 (iOS 전용) |
|
|
106
|
+
| `onError` | `(error: AppUpdateError) => void` | - | 에러 콜백 |
|
|
107
|
+
|
|
108
|
+
#### 반환 값
|
|
109
|
+
|
|
110
|
+
| 속성 | 타입 | 설명 |
|
|
111
|
+
|----------|------|-------------|
|
|
112
|
+
| `isChecking` | `boolean` | 업데이트 확인 중인지 여부 |
|
|
113
|
+
| `isUpdateAvailable` | `boolean` | 업데이트 가능 여부 |
|
|
114
|
+
| `currentVersion` | `string` | 현재 설치된 버전 |
|
|
115
|
+
| `latestVersion` | `string \| null` | 최신 버전 (미확인 시 null) |
|
|
116
|
+
| `storeUrl` | `string \| null` | 앱 스토어 URL |
|
|
117
|
+
| `error` | `AppUpdateError \| null` | 마지막으로 발생한 오류 |
|
|
118
|
+
| `isDownloading` | `boolean` | Android: 다운로드 중인지 여부 |
|
|
119
|
+
| `downloadProgress` | `number` | Android: 다운로드 진행률 (0-100) |
|
|
120
|
+
| `isReadyToInstall` | `boolean` | Android: 다운로드 완료 여부 |
|
|
121
|
+
| `playStoreInfo` | `PlayStoreUpdateInfo \| null` | Android: Play Store 상세 정보 |
|
|
122
|
+
| `checkUpdate` | `() => Promise<void>` | 업데이트 확인 |
|
|
123
|
+
| `openStore` | `() => Promise<void>` | 스토어 페이지 열기 |
|
|
124
|
+
| `startUpdate` | `(type: UpdateType) => Promise<void>` | Android: 인앱 업데이트 시작 |
|
|
125
|
+
| `completeUpdate` | `() => Promise<void>` | Android: 유연 업데이트 완료 |
|
|
126
|
+
|
|
127
|
+
### 함수
|
|
128
|
+
|
|
129
|
+
#### `getCurrentVersion(): string`
|
|
130
|
+
현재 설치된 앱 버전을 반환합니다.
|
|
131
|
+
|
|
132
|
+
#### `getCurrentBuildNumber(): number`
|
|
133
|
+
현재 빌드 번호를 반환합니다.
|
|
134
|
+
|
|
135
|
+
#### `getPackageName(): string`
|
|
136
|
+
번들 ID(iOS) 또는 패키지명(Android)을 반환합니다.
|
|
137
|
+
|
|
138
|
+
#### `getCountry(): string`
|
|
139
|
+
디바이스 국가 코드를 반환합니다.
|
|
140
|
+
|
|
141
|
+
#### `getLatestVersion(options?): Promise<string>`
|
|
142
|
+
스토어의 최신 버전을 가져옵니다.
|
|
143
|
+
|
|
144
|
+
| 옵션 | 타입 | 설명 |
|
|
145
|
+
|--------|------|-------------|
|
|
146
|
+
| `forceRefresh` | `boolean` | 캐시 무시 (iOS 전용) |
|
|
147
|
+
| `country` | `string` | 국가 코드 (iOS 전용) |
|
|
148
|
+
|
|
149
|
+
#### `needUpdate(options?): Promise<NeedUpdateResult>`
|
|
150
|
+
업데이트가 필요한지 확인합니다.
|
|
151
|
+
|
|
152
|
+
| 옵션 | 타입 | 설명 |
|
|
153
|
+
|--------|------|-------------|
|
|
154
|
+
| `currentVersion` | `string` | 비교할 현재 버전 (기본값: 설치된 버전) |
|
|
155
|
+
| `latestVersion` | `string` | 최신 버전 (미제공 시 스토어에서 조회) |
|
|
156
|
+
| `depth` | `number` | 버전 비교 깊이 (1=major, 2=major.minor 등) |
|
|
157
|
+
| `forceRefresh` | `boolean` | 캐시 무시 (iOS 전용) |
|
|
158
|
+
| `country` | `string` | 국가 코드 (iOS 전용) |
|
|
159
|
+
|
|
160
|
+
#### `openStore(options?): Promise<void>`
|
|
161
|
+
앱 스토어 페이지를 엽니다.
|
|
162
|
+
|
|
163
|
+
#### `getAppStoreInfo(options?): Promise<AppStoreInfo>` (iOS 전용)
|
|
164
|
+
App Store 상세 정보를 반환합니다.
|
|
165
|
+
|
|
166
|
+
#### `checkPlayStoreUpdate(): Promise<PlayStoreUpdateInfo>` (Android 전용)
|
|
167
|
+
Play Core를 통해 업데이트를 확인합니다.
|
|
168
|
+
|
|
169
|
+
#### `startInAppUpdate(type: UpdateType): Promise<void>` (Android 전용)
|
|
170
|
+
인앱 업데이트 플로우를 시작합니다.
|
|
171
|
+
|
|
172
|
+
#### `completeInAppUpdate(): Promise<void>` (Android 전용)
|
|
173
|
+
유연 업데이트를 완료합니다(앱 재시작).
|
|
174
|
+
|
|
175
|
+
#### `addUpdateListener(listener): UpdateSubscription` (Android 전용)
|
|
176
|
+
다운로드 진행률 업데이트를 구독합니다.
|
|
177
|
+
|
|
178
|
+
### 타입
|
|
179
|
+
|
|
180
|
+
#### `UpdateType`
|
|
181
|
+
```ts
|
|
182
|
+
enum UpdateType {
|
|
183
|
+
FLEXIBLE = 0, // 백그라운드 다운로드, 사용자 앱 사용 가능
|
|
184
|
+
IMMEDIATE = 1, // 전체 화면 차단 업데이트
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### `AppUpdateError`
|
|
189
|
+
```ts
|
|
190
|
+
class AppUpdateError extends Error {
|
|
191
|
+
code: AppUpdateErrorCode;
|
|
192
|
+
nativeError?: unknown;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
enum AppUpdateErrorCode {
|
|
196
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
197
|
+
APP_NOT_FOUND = 'APP_NOT_FOUND',
|
|
198
|
+
RATE_LIMITED = 'RATE_LIMITED',
|
|
199
|
+
NOT_FROM_PLAY_STORE = 'NOT_FROM_PLAY_STORE',
|
|
200
|
+
PLAY_STORE_NOT_AVAILABLE = 'PLAY_STORE_NOT_AVAILABLE',
|
|
201
|
+
CHECK_FAILED = 'CHECK_FAILED',
|
|
202
|
+
UPDATE_FAILED = 'UPDATE_FAILED',
|
|
203
|
+
UPDATE_CANCELLED = 'UPDATE_CANCELLED',
|
|
204
|
+
UNKNOWN = 'UNKNOWN',
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Android 인앱 업데이트
|
|
209
|
+
|
|
210
|
+
Android는 두 가지 업데이트 유형을 지원합니다.
|
|
211
|
+
|
|
212
|
+
### 유연(Flexible) 업데이트
|
|
213
|
+
- 백그라운드에서 다운로드
|
|
214
|
+
- 사용자 계속 앱 사용 가능
|
|
215
|
+
- 다운로드 완료 후 `completeUpdate()` 호출
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
const { startUpdate, isReadyToInstall, completeUpdate } = useAppUpdate();
|
|
219
|
+
|
|
220
|
+
// 유연 업데이트 시작
|
|
221
|
+
await startUpdate(UpdateType.FLEXIBLE);
|
|
222
|
+
|
|
223
|
+
// 다운로드 완료 시 설치 완료
|
|
224
|
+
if (isReadyToInstall) {
|
|
225
|
+
await completeUpdate(); // 앱 재시작
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### 즉시(Immediate) 업데이트
|
|
230
|
+
- 전체 화면 차단 UI
|
|
231
|
+
- 업데이트 완료 전까지 앱 사용 불가
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
await startUpdate(UpdateType.IMMEDIATE);
|
|
235
|
+
// 업데이트 완료 후 앱 자동 재시작
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 요구 사항
|
|
239
|
+
|
|
240
|
+
- React Native >= 0.73.0
|
|
241
|
+
- iOS >= 13.0
|
|
242
|
+
- Android: Play Store에서 설치된 앱만 인앱 업데이트 지원
|
|
243
|
+
|
|
244
|
+
## 라이선스
|
|
245
|
+
|
|
246
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# @parrotnavy/rn-native-updates
|
|
2
|
+
|
|
3
|
+
[한국어](./README.ko.md)
|
|
4
|
+
|
|
5
|
+
React Native app update checker with hooks support. Uses Play Core In-App Updates for Android and iTunes Lookup API for iOS.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Hook API** - `useAppUpdate()` for easy integration with React components
|
|
10
|
+
- **Function API** - Compatible with `react-native-version-check` API style
|
|
11
|
+
- **Android In-App Updates** - Flexible and Immediate update flows via Play Core
|
|
12
|
+
- **iOS App Store Check** - Version lookup via iTunes API with caching
|
|
13
|
+
- **TypeScript** - Full type definitions included
|
|
14
|
+
- **Expo & Bare RN** - Works with both Expo and bare React Native projects
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @parrotnavy/rn-native-updates
|
|
20
|
+
# or
|
|
21
|
+
yarn add @parrotnavy/rn-native-updates
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### iOS Setup
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd ios && pod install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Android Setup
|
|
31
|
+
|
|
32
|
+
No additional setup required. The library uses Play Core which is bundled automatically.
|
|
33
|
+
|
|
34
|
+
> **Note**: Android In-App Updates only work for apps installed from the Google Play Store.
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Hook API (Recommended)
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useAppUpdate, UpdateType } from '@parrotnavy/rn-native-updates';
|
|
42
|
+
|
|
43
|
+
function UpdateChecker() {
|
|
44
|
+
const {
|
|
45
|
+
isChecking,
|
|
46
|
+
isUpdateAvailable,
|
|
47
|
+
currentVersion,
|
|
48
|
+
latestVersion,
|
|
49
|
+
checkUpdate,
|
|
50
|
+
openStore,
|
|
51
|
+
startUpdate, // Android only
|
|
52
|
+
completeUpdate, // Android only
|
|
53
|
+
} = useAppUpdate({
|
|
54
|
+
checkOnMount: true,
|
|
55
|
+
onError: (error) => console.log('Update check failed:', error),
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (isUpdateAvailable) {
|
|
59
|
+
return (
|
|
60
|
+
<View>
|
|
61
|
+
<Text>Update available: {latestVersion}</Text>
|
|
62
|
+
<Button title="Update Now" onPress={() => startUpdate(UpdateType.IMMEDIATE)} />
|
|
63
|
+
</View>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return <Text>You're on the latest version: {currentVersion}</Text>;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Function API
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import {
|
|
75
|
+
getCurrentVersion,
|
|
76
|
+
getLatestVersion,
|
|
77
|
+
needUpdate,
|
|
78
|
+
openStore,
|
|
79
|
+
} from '@parrotnavy/rn-native-updates';
|
|
80
|
+
|
|
81
|
+
// Get current installed version
|
|
82
|
+
const version = getCurrentVersion(); // "1.0.0"
|
|
83
|
+
|
|
84
|
+
// Check latest version from store
|
|
85
|
+
const latest = await getLatestVersion(); // "1.1.0"
|
|
86
|
+
|
|
87
|
+
// Check if update is needed
|
|
88
|
+
const result = await needUpdate();
|
|
89
|
+
// { isNeeded: true, currentVersion: "1.0.0", latestVersion: "1.1.0", storeUrl: "..." }
|
|
90
|
+
|
|
91
|
+
// Open store page
|
|
92
|
+
await openStore();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## API Reference
|
|
96
|
+
|
|
97
|
+
### Hook: `useAppUpdate(options?)`
|
|
98
|
+
|
|
99
|
+
#### Options
|
|
100
|
+
|
|
101
|
+
| Option | Type | Default | Description |
|
|
102
|
+
|--------|------|---------|-------------|
|
|
103
|
+
| `checkOnMount` | `boolean` | `false` | Automatically check for updates when component mounts |
|
|
104
|
+
| `country` | `string` | Device locale | Country code for App Store lookup (iOS only) |
|
|
105
|
+
| `onError` | `(error: AppUpdateError) => void` | - | Error callback |
|
|
106
|
+
|
|
107
|
+
#### Return Value
|
|
108
|
+
|
|
109
|
+
| Property | Type | Description |
|
|
110
|
+
|----------|------|-------------|
|
|
111
|
+
| `isChecking` | `boolean` | Whether an update check is in progress |
|
|
112
|
+
| `isUpdateAvailable` | `boolean` | Whether an update is available |
|
|
113
|
+
| `currentVersion` | `string` | Current installed version |
|
|
114
|
+
| `latestVersion` | `string \| null` | Latest version available (null if not checked) |
|
|
115
|
+
| `storeUrl` | `string \| null` | Store URL for the app |
|
|
116
|
+
| `error` | `AppUpdateError \| null` | Last error that occurred |
|
|
117
|
+
| `isDownloading` | `boolean` | Android: Whether update is downloading |
|
|
118
|
+
| `downloadProgress` | `number` | Android: Download progress (0-100) |
|
|
119
|
+
| `isReadyToInstall` | `boolean` | Android: Whether download is complete |
|
|
120
|
+
| `playStoreInfo` | `PlayStoreUpdateInfo \| null` | Android: Detailed Play Store info |
|
|
121
|
+
| `checkUpdate` | `() => Promise<void>` | Check for updates |
|
|
122
|
+
| `openStore` | `() => Promise<void>` | Open store page |
|
|
123
|
+
| `startUpdate` | `(type: UpdateType) => Promise<void>` | Android: Start in-app update |
|
|
124
|
+
| `completeUpdate` | `() => Promise<void>` | Android: Complete flexible update |
|
|
125
|
+
|
|
126
|
+
### Functions
|
|
127
|
+
|
|
128
|
+
#### `getCurrentVersion(): string`
|
|
129
|
+
Returns the current installed app version.
|
|
130
|
+
|
|
131
|
+
#### `getCurrentBuildNumber(): number`
|
|
132
|
+
Returns the current build number.
|
|
133
|
+
|
|
134
|
+
#### `getPackageName(): string`
|
|
135
|
+
Returns the bundle ID (iOS) or package name (Android).
|
|
136
|
+
|
|
137
|
+
#### `getCountry(): string`
|
|
138
|
+
Returns the device's country code.
|
|
139
|
+
|
|
140
|
+
#### `getLatestVersion(options?): Promise<string>`
|
|
141
|
+
Fetches the latest version from the store.
|
|
142
|
+
|
|
143
|
+
| Option | Type | Description |
|
|
144
|
+
|--------|------|-------------|
|
|
145
|
+
| `forceRefresh` | `boolean` | Bypass cache (iOS only) |
|
|
146
|
+
| `country` | `string` | Country code (iOS only) |
|
|
147
|
+
|
|
148
|
+
#### `needUpdate(options?): Promise<NeedUpdateResult>`
|
|
149
|
+
Checks if an update is needed.
|
|
150
|
+
|
|
151
|
+
| Option | Type | Description |
|
|
152
|
+
|--------|------|-------------|
|
|
153
|
+
| `currentVersion` | `string` | Version to compare (defaults to installed) |
|
|
154
|
+
| `latestVersion` | `string` | Latest version (fetches if not provided) |
|
|
155
|
+
| `depth` | `number` | Version comparison depth (1=major, 2=major.minor, etc.) |
|
|
156
|
+
| `forceRefresh` | `boolean` | Bypass cache (iOS only) |
|
|
157
|
+
| `country` | `string` | Country code (iOS only) |
|
|
158
|
+
|
|
159
|
+
#### `openStore(options?): Promise<void>`
|
|
160
|
+
Opens the store page for your app.
|
|
161
|
+
|
|
162
|
+
#### `getAppStoreInfo(options?): Promise<AppStoreInfo>` (iOS only)
|
|
163
|
+
Returns detailed App Store information.
|
|
164
|
+
|
|
165
|
+
#### `checkPlayStoreUpdate(): Promise<PlayStoreUpdateInfo>` (Android only)
|
|
166
|
+
Checks for updates via Play Core.
|
|
167
|
+
|
|
168
|
+
#### `startInAppUpdate(type: UpdateType): Promise<void>` (Android only)
|
|
169
|
+
Starts an in-app update flow.
|
|
170
|
+
|
|
171
|
+
#### `completeInAppUpdate(): Promise<void>` (Android only)
|
|
172
|
+
Completes a flexible update (triggers app restart).
|
|
173
|
+
|
|
174
|
+
#### `addUpdateListener(listener): UpdateSubscription` (Android only)
|
|
175
|
+
Subscribes to update download progress.
|
|
176
|
+
|
|
177
|
+
### Types
|
|
178
|
+
|
|
179
|
+
#### `UpdateType`
|
|
180
|
+
```ts
|
|
181
|
+
enum UpdateType {
|
|
182
|
+
FLEXIBLE = 0, // Background download, user can continue using app
|
|
183
|
+
IMMEDIATE = 1, // Full-screen blocking update
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `AppUpdateError`
|
|
188
|
+
```ts
|
|
189
|
+
class AppUpdateError extends Error {
|
|
190
|
+
code: AppUpdateErrorCode;
|
|
191
|
+
nativeError?: unknown;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
enum AppUpdateErrorCode {
|
|
195
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
196
|
+
APP_NOT_FOUND = 'APP_NOT_FOUND',
|
|
197
|
+
RATE_LIMITED = 'RATE_LIMITED',
|
|
198
|
+
NOT_FROM_PLAY_STORE = 'NOT_FROM_PLAY_STORE',
|
|
199
|
+
PLAY_STORE_NOT_AVAILABLE = 'PLAY_STORE_NOT_AVAILABLE',
|
|
200
|
+
CHECK_FAILED = 'CHECK_FAILED',
|
|
201
|
+
UPDATE_FAILED = 'UPDATE_FAILED',
|
|
202
|
+
UPDATE_CANCELLED = 'UPDATE_CANCELLED',
|
|
203
|
+
UNKNOWN = 'UNKNOWN',
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Android In-App Updates
|
|
208
|
+
|
|
209
|
+
Android supports two update types:
|
|
210
|
+
|
|
211
|
+
### Flexible Update
|
|
212
|
+
- Downloads in background
|
|
213
|
+
- User can continue using the app
|
|
214
|
+
- Call `completeUpdate()` when ready to install
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
const { startUpdate, isReadyToInstall, completeUpdate } = useAppUpdate();
|
|
218
|
+
|
|
219
|
+
// Start flexible update
|
|
220
|
+
await startUpdate(UpdateType.FLEXIBLE);
|
|
221
|
+
|
|
222
|
+
// When download completes, show install prompt
|
|
223
|
+
if (isReadyToInstall) {
|
|
224
|
+
await completeUpdate(); // App will restart
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Immediate Update
|
|
229
|
+
- Full-screen blocking UI
|
|
230
|
+
- User cannot use app until update completes
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
await startUpdate(UpdateType.IMMEDIATE);
|
|
234
|
+
// App will restart automatically after update
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Requirements
|
|
238
|
+
|
|
239
|
+
- React Native >= 0.73.0
|
|
240
|
+
- iOS >= 13.0
|
|
241
|
+
- Android: App must be installed from Play Store for in-app updates
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.safeExtGet = { prop, fallback ->
|
|
3
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
repositories {
|
|
7
|
+
google()
|
|
8
|
+
mavenCentral()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
dependencies {
|
|
12
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
13
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '2.0.21')}"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
apply plugin: "com.android.library"
|
|
18
|
+
apply plugin: "kotlin-android"
|
|
19
|
+
apply plugin: "com.facebook.react"
|
|
20
|
+
|
|
21
|
+
android {
|
|
22
|
+
namespace "com.parrotnavy.nativeupdates"
|
|
23
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 35)
|
|
24
|
+
|
|
25
|
+
defaultConfig {
|
|
26
|
+
minSdkVersion safeExtGet("minSdkVersion", 24)
|
|
27
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 35)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
buildFeatures {
|
|
31
|
+
buildConfig true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
compileOptions {
|
|
35
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
36
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
kotlinOptions {
|
|
40
|
+
jvmTarget = "17"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
repositories {
|
|
45
|
+
google()
|
|
46
|
+
mavenCentral()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
dependencies {
|
|
50
|
+
implementation "com.facebook.react:react-android"
|
|
51
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
|
52
|
+
|
|
53
|
+
// Play Core for In-App Updates
|
|
54
|
+
implementation "com.google.android.play:app-update:2.1.0"
|
|
55
|
+
implementation "com.google.android.play:app-update-ktx:2.1.0"
|
|
56
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.parrotnavy.nativeupdates
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.exception.CodedException
|
|
4
|
+
|
|
5
|
+
class PlayStoreNotAvailableException : CodedException(
|
|
6
|
+
code = "PLAY_STORE_NOT_AVAILABLE",
|
|
7
|
+
message = "Play Store is not available on this device"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
class NotFromPlayStoreException : CodedException(
|
|
11
|
+
code = "NOT_FROM_PLAY_STORE",
|
|
12
|
+
message = "App was not installed from Play Store"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
class CheckFailedException(detail: String? = null) : CodedException(
|
|
16
|
+
code = "CHECK_FAILED",
|
|
17
|
+
message = "Failed to check for updates${detail?.let { ": $it" } ?: ""}"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
class UpdateNotAvailableException : CodedException(
|
|
21
|
+
code = "UPDATE_NOT_AVAILABLE",
|
|
22
|
+
message = "No update is available"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
class UpdateFailedException(detail: String? = null) : CodedException(
|
|
26
|
+
code = "UPDATE_FAILED",
|
|
27
|
+
message = "Failed to start update${detail?.let { ": $it" } ?: ""}"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
class NoActivityException : CodedException(
|
|
31
|
+
code = "NO_ACTIVITY",
|
|
32
|
+
message = "No activity available to start update flow"
|
|
33
|
+
)
|