@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/src/types.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @parrotnavy/rn-native-updates
|
|
3
|
+
* TypeScript Type Definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Error Types
|
|
8
|
+
// =============================================================================
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error codes returned by the native modules
|
|
12
|
+
*/
|
|
13
|
+
export enum AppUpdateErrorCode {
|
|
14
|
+
/** Network request failed */
|
|
15
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
16
|
+
/** App not found on store */
|
|
17
|
+
APP_NOT_FOUND = 'APP_NOT_FOUND',
|
|
18
|
+
/** API rate limit exceeded (iOS) */
|
|
19
|
+
RATE_LIMITED = 'RATE_LIMITED',
|
|
20
|
+
/** App not installed from Play Store (Android) */
|
|
21
|
+
NOT_FROM_PLAY_STORE = 'NOT_FROM_PLAY_STORE',
|
|
22
|
+
/** Play Store not available on device (Android) */
|
|
23
|
+
PLAY_STORE_NOT_AVAILABLE = 'PLAY_STORE_NOT_AVAILABLE',
|
|
24
|
+
/** Update check failed */
|
|
25
|
+
CHECK_FAILED = 'CHECK_FAILED',
|
|
26
|
+
/** Update flow failed */
|
|
27
|
+
UPDATE_FAILED = 'UPDATE_FAILED',
|
|
28
|
+
/** Update was cancelled by user */
|
|
29
|
+
UPDATE_CANCELLED = 'UPDATE_CANCELLED',
|
|
30
|
+
/** Unknown error */
|
|
31
|
+
UNKNOWN = 'UNKNOWN',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Custom error class for app update operations
|
|
36
|
+
*/
|
|
37
|
+
export class AppUpdateError extends Error {
|
|
38
|
+
code: AppUpdateErrorCode;
|
|
39
|
+
nativeError?: unknown;
|
|
40
|
+
|
|
41
|
+
constructor(code: AppUpdateErrorCode, message: string, nativeError?: unknown) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = 'AppUpdateError';
|
|
44
|
+
this.code = code;
|
|
45
|
+
this.nativeError = nativeError;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// Android Types
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Android update type
|
|
55
|
+
*/
|
|
56
|
+
export enum UpdateType {
|
|
57
|
+
/** Background download, user can continue using app */
|
|
58
|
+
FLEXIBLE = 0,
|
|
59
|
+
/** Full-screen blocking update */
|
|
60
|
+
IMMEDIATE = 1,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Android update availability status
|
|
65
|
+
*/
|
|
66
|
+
export enum UpdateAvailability {
|
|
67
|
+
UNKNOWN = 0,
|
|
68
|
+
UPDATE_NOT_AVAILABLE = 1,
|
|
69
|
+
UPDATE_AVAILABLE = 2,
|
|
70
|
+
DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS = 3,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Android install status
|
|
75
|
+
*/
|
|
76
|
+
export enum InstallStatus {
|
|
77
|
+
UNKNOWN = 0,
|
|
78
|
+
PENDING = 1,
|
|
79
|
+
DOWNLOADING = 2,
|
|
80
|
+
DOWNLOADED = 3,
|
|
81
|
+
INSTALLING = 4,
|
|
82
|
+
INSTALLED = 5,
|
|
83
|
+
FAILED = 6,
|
|
84
|
+
CANCELED = 7,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Android Play Store update info
|
|
89
|
+
*/
|
|
90
|
+
export interface PlayStoreUpdateInfo {
|
|
91
|
+
/** Update availability status */
|
|
92
|
+
updateAvailability: UpdateAvailability;
|
|
93
|
+
/** Available version code (if update available) */
|
|
94
|
+
availableVersionCode: number | null;
|
|
95
|
+
/** Whether flexible update is allowed */
|
|
96
|
+
isFlexibleUpdateAllowed: boolean;
|
|
97
|
+
/** Whether immediate update is allowed */
|
|
98
|
+
isImmediateUpdateAllowed: boolean;
|
|
99
|
+
/** Days since update became available */
|
|
100
|
+
clientVersionStalenessDays: number | null;
|
|
101
|
+
/** Update priority (0-5, set in Play Console) */
|
|
102
|
+
updatePriority: number;
|
|
103
|
+
/** Total bytes to download */
|
|
104
|
+
totalBytesToDownload: number;
|
|
105
|
+
/** Package name */
|
|
106
|
+
packageName: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Android install state during update
|
|
111
|
+
*/
|
|
112
|
+
export interface InstallState {
|
|
113
|
+
/** Current install status */
|
|
114
|
+
installStatus: InstallStatus;
|
|
115
|
+
/** Bytes downloaded so far */
|
|
116
|
+
bytesDownloaded: number;
|
|
117
|
+
/** Total bytes to download */
|
|
118
|
+
totalBytesToDownload: number;
|
|
119
|
+
/** Download progress percentage (0-100) */
|
|
120
|
+
downloadProgress: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Android update listener callback
|
|
125
|
+
*/
|
|
126
|
+
export type UpdateListener = (state: InstallState) => void;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Subscription handle for removing listener
|
|
130
|
+
*/
|
|
131
|
+
export interface UpdateSubscription {
|
|
132
|
+
remove: () => void;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// =============================================================================
|
|
136
|
+
// iOS Types
|
|
137
|
+
// =============================================================================
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* iOS App Store version info
|
|
141
|
+
*/
|
|
142
|
+
export interface AppStoreInfo {
|
|
143
|
+
/** App Store version */
|
|
144
|
+
version: string;
|
|
145
|
+
/** iTunes track ID */
|
|
146
|
+
trackId: number;
|
|
147
|
+
/** App Store URL */
|
|
148
|
+
trackViewUrl: string;
|
|
149
|
+
/** Release date of current version */
|
|
150
|
+
currentVersionReleaseDate: string;
|
|
151
|
+
/** Release notes */
|
|
152
|
+
releaseNotes: string | null;
|
|
153
|
+
/** Minimum iOS version required */
|
|
154
|
+
minimumOsVersion: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Common Types
|
|
159
|
+
// =============================================================================
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Result of needUpdate() check
|
|
163
|
+
*/
|
|
164
|
+
export interface NeedUpdateResult {
|
|
165
|
+
/** Whether an update is needed */
|
|
166
|
+
isNeeded: boolean;
|
|
167
|
+
/** Current installed version */
|
|
168
|
+
currentVersion: string;
|
|
169
|
+
/** Latest version available on store */
|
|
170
|
+
latestVersion: string;
|
|
171
|
+
/** Store URL (App Store or Play Store) */
|
|
172
|
+
storeUrl: string;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Options for getLatestVersion()
|
|
177
|
+
*/
|
|
178
|
+
export interface GetLatestVersionOptions {
|
|
179
|
+
/** Force refresh (bypass cache) - iOS only */
|
|
180
|
+
forceRefresh?: boolean;
|
|
181
|
+
/** Country code for App Store lookup (e.g., 'us', 'kr') - iOS only */
|
|
182
|
+
country?: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Options for needUpdate()
|
|
187
|
+
*/
|
|
188
|
+
export interface NeedUpdateOptions extends GetLatestVersionOptions {
|
|
189
|
+
/** Current version to compare (defaults to installed version) */
|
|
190
|
+
currentVersion?: string;
|
|
191
|
+
/** Latest version to compare (will fetch from store if not provided) */
|
|
192
|
+
latestVersion?: string;
|
|
193
|
+
/**
|
|
194
|
+
* Depth of version comparison
|
|
195
|
+
* - 1: Major only (1.x.x)
|
|
196
|
+
* - 2: Major + Minor (1.2.x)
|
|
197
|
+
* - 3: Major + Minor + Patch (1.2.3)
|
|
198
|
+
* - Infinity: Full comparison (default)
|
|
199
|
+
*/
|
|
200
|
+
depth?: number;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Options for getStoreUrl()
|
|
205
|
+
*/
|
|
206
|
+
export interface GetStoreUrlOptions {
|
|
207
|
+
/** Country code for App Store URL - iOS only */
|
|
208
|
+
country?: string;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// =============================================================================
|
|
212
|
+
// Hook Types
|
|
213
|
+
// =============================================================================
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Options for useAppUpdate hook
|
|
217
|
+
*/
|
|
218
|
+
export interface UseAppUpdateOptions {
|
|
219
|
+
/** Automatically check for updates on mount (default: false) */
|
|
220
|
+
checkOnMount?: boolean;
|
|
221
|
+
/** Country code for App Store lookup - iOS only */
|
|
222
|
+
country?: string;
|
|
223
|
+
/** Error callback */
|
|
224
|
+
onError?: (error: AppUpdateError) => void;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Return type of useAppUpdate hook
|
|
229
|
+
*/
|
|
230
|
+
export interface UseAppUpdateResult {
|
|
231
|
+
// === State ===
|
|
232
|
+
|
|
233
|
+
/** Whether an update check is in progress */
|
|
234
|
+
isChecking: boolean;
|
|
235
|
+
|
|
236
|
+
/** Whether an update is available */
|
|
237
|
+
isUpdateAvailable: boolean;
|
|
238
|
+
|
|
239
|
+
/** Current installed version */
|
|
240
|
+
currentVersion: string;
|
|
241
|
+
|
|
242
|
+
/** Latest version available on store (null if not checked) */
|
|
243
|
+
latestVersion: string | null;
|
|
244
|
+
|
|
245
|
+
/** Store URL for the app */
|
|
246
|
+
storeUrl: string | null;
|
|
247
|
+
|
|
248
|
+
/** Last error that occurred */
|
|
249
|
+
error: AppUpdateError | null;
|
|
250
|
+
|
|
251
|
+
// === Android-specific state ===
|
|
252
|
+
|
|
253
|
+
/** Android: Whether update is currently downloading */
|
|
254
|
+
isDownloading: boolean;
|
|
255
|
+
|
|
256
|
+
/** Android: Download progress (0-100) */
|
|
257
|
+
downloadProgress: number;
|
|
258
|
+
|
|
259
|
+
/** Android: Whether download is complete and ready to install */
|
|
260
|
+
isReadyToInstall: boolean;
|
|
261
|
+
|
|
262
|
+
/** Android: Detailed Play Store update info */
|
|
263
|
+
playStoreInfo: PlayStoreUpdateInfo | null;
|
|
264
|
+
|
|
265
|
+
// === Actions ===
|
|
266
|
+
|
|
267
|
+
/** Check for available updates */
|
|
268
|
+
checkUpdate: () => Promise<void>;
|
|
269
|
+
|
|
270
|
+
/** Open store page for the app */
|
|
271
|
+
openStore: () => Promise<void>;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Android: Start in-app update
|
|
275
|
+
* @param type - Update type (FLEXIBLE or IMMEDIATE)
|
|
276
|
+
*/
|
|
277
|
+
startUpdate: (type: UpdateType) => Promise<void>;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Android: Complete flexible update (triggers app restart)
|
|
281
|
+
* Only call after download is complete
|
|
282
|
+
*/
|
|
283
|
+
completeUpdate: () => Promise<void>;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// =============================================================================
|
|
287
|
+
// Native Module Types (internal)
|
|
288
|
+
// =============================================================================
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Native module constants (exposed at load time)
|
|
292
|
+
*/
|
|
293
|
+
export interface NativeConstants {
|
|
294
|
+
/** Current app version */
|
|
295
|
+
currentVersion: string;
|
|
296
|
+
/** Current build number */
|
|
297
|
+
buildNumber: string;
|
|
298
|
+
/** Bundle ID (iOS) or package name (Android) */
|
|
299
|
+
packageName: string;
|
|
300
|
+
/** Device country code */
|
|
301
|
+
country: string;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Native module interface (internal)
|
|
306
|
+
*/
|
|
307
|
+
export interface NativeUpdatesModuleType extends NativeConstants {
|
|
308
|
+
// iOS
|
|
309
|
+
getAppStoreVersion(country: string | null, forceRefresh: boolean): Promise<AppStoreInfo>;
|
|
310
|
+
|
|
311
|
+
// Android
|
|
312
|
+
checkPlayStoreUpdate(): Promise<PlayStoreUpdateInfo>;
|
|
313
|
+
startUpdate(updateType: number): Promise<void>;
|
|
314
|
+
completeUpdate(): Promise<void>;
|
|
315
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function compareVersions(
|
|
2
|
+
version1: string,
|
|
3
|
+
version2: string,
|
|
4
|
+
depth: number = Number.POSITIVE_INFINITY,
|
|
5
|
+
): number {
|
|
6
|
+
const v1Parts = version1.split('.').map((p) => Number.parseInt(p, 10) || 0);
|
|
7
|
+
const v2Parts = version2.split('.').map((p) => Number.parseInt(p, 10) || 0);
|
|
8
|
+
|
|
9
|
+
const maxLength = Math.min(Math.max(v1Parts.length, v2Parts.length), depth);
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < maxLength; i++) {
|
|
12
|
+
const v1 = v1Parts[i] ?? 0;
|
|
13
|
+
const v2 = v2Parts[i] ?? 0;
|
|
14
|
+
|
|
15
|
+
if (v1 > v2) return 1;
|
|
16
|
+
if (v1 < v2) return -1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isNewerVersion(
|
|
23
|
+
currentVersion: string,
|
|
24
|
+
latestVersion: string,
|
|
25
|
+
depth?: number,
|
|
26
|
+
): boolean {
|
|
27
|
+
return compareVersions(latestVersion, currentVersion, depth) > 0;
|
|
28
|
+
}
|