{"_id":"@chankruze/react-native-in-app-updates","_rev":"2-c438a86cf0b72bafa4adff3b5df45f28","name":"@chankruze/react-native-in-app-updates","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@chankruze/react-native-in-app-updates","version":"0.1.0","keywords":["react-native","ios","android"],"author":{"url":"https://github.com/chankruze","name":"Chandan Kumar Mandal","email":"chankruze@gmail.com"},"license":"MIT","_id":"@chankruze/react-native-in-app-updates@0.1.0","maintainers":[{"name":"chankruze","email":"chankruze@gmail.com"}],"homepage":"https://github.com/chankruze/react-native-in-app-updates#readme","bugs":{"url":"https://github.com/chankruze/react-native-in-app-updates/issues"},"dist":{"shasum":"23b926fe79013bec5c245dd2ae282091223b55b2","tarball":"https://registry.npmjs.org/@chankruze/react-native-in-app-updates/-/react-native-in-app-updates-0.1.0.tgz","fileCount":42,"integrity":"sha512-CnzXTMb1kU32SAkL9LmG/Jj2I99qdZgmcOAAmx1++2iwfkNIqdvtx2SSmXYpX3Py/VGnebJfbtnuO8J4pIHl9Q==","signatures":[{"sig":"MEUCIQCyzKH+S6Br5lbxAIn/G/CLcBc7uL0jrniGyF+EsYXogwIgDhyUl3LHBKBPc8s+N3+Rv77PclB3EXPX21w5N8cKjeU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50129},"jest":{"preset":"@react-native/jest-preset","testEnvironmentOptions":{"customExportConditions":["require","react-native","<%- project.sourceCondition -%>"]},"modulePathIgnorePatterns":["<rootDir>/example/node_modules","<rootDir>/lib/"]},"main":"./lib/module/index.js","types":"./lib/typescript/src/index.d.ts","exports":{".":{"types":"./lib/typescript/src/index.d.ts","default":"./lib/module/index.js","chankruze-react-native-in-app-updates-source":"./src/index.tsx"},"./package.json":"./package.json"},"gitHead":"33b25b06a065927710d1f3fd17c067366daf8280","scripts":{"lint":"eslint \"**/*.{js,ts,tsx}\"","test":"jest","clean":"del-cli android/build example/android/build example/android/app/build example/ios/build lib","example":"yarn workspace @chankruze/react-native-in-app-updates-example","prepare":"bob build","release":"release-it --only-version","typecheck":"tsc"},"_npmUser":{"name":"chankruze","email":"chankruze@gmail.com"},"prettier":{"useTabs":false,"tabWidth":2,"quoteProps":"consistent","singleQuote":true,"trailingComma":"es5"},"commitlint":{"extends":["@commitlint/config-conventional"]},"release-it":{"git":{"tagName":"v${version}","commitMessage":"chore: release ${version}"},"npm":{"publish":true},"github":{"release":true},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"repository":{"url":"git+https://github.com/chankruze/react-native-in-app-updates.git","type":"git"},"workspaces":["example"],"_npmVersion":"11.4.2","description":"Lightweight in-app updates for Android (Play Store) and iOS (App Store)","directories":{},"_nodeVersion":"24.3.0","codegenConfig":{"name":"ReactNativeInAppUpdatesSpec","type":"modules","android":{"javaPackageName":"com.chankruze.reactnativeinappupdates"},"jsSrcsDir":"src"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"packageManager":"yarn@4.11.0","devDependencies":{"jest":"^29.7.0","react":"19.2.3","turbo":"^2.9.16","eslint":"^9.39.4","del-cli":"^7.0.0","lefthook":"^2.1.9","prettier":"^3.8.3","@eslint/js":"^10.0.1","commitlint":"^21.0.2","release-it":"^20.2.0","typescript":"^6.0.3","@types/react":"^19.2.0","react-native":"0.85.0","@jest/globals":"^29.7.0","@eslint/compat":"^2.1.0","@eslint/eslintrc":"^3.3.5","eslint-plugin-ft-flow":"^3.0.11","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.6","react-native-builder-bob":"^0.43.0","@react-native/jest-preset":"0.85.0","@react-native/babel-preset":"0.85.0","@react-native/eslint-config":"0.85.0","@commitlint/config-conventional":"^21.0.2","@release-it/conventional-changelog":"^11.0.1"},"peerDependencies":{"react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-in-app-updates_0.1.0_1782422720862_0.6808585334263115","host":"s3://npm-registry-packages-npm-production"},"react-native-builder-bob":{"output":"lib","source":"src","targets":[["module",{"esm":true}],["typescript",{"project":"tsconfig.build.json"}]]},"create-react-native-library":{"type":"turbo-module","tools":["jest","lefthook","release-it","eslint"],"version":"0.63.0","languages":"kotlin-objc"}},"0.1.1":{"name":"@chankruze/react-native-in-app-updates","version":"0.1.1","description":"Lightweight in-app updates for Android (Play Store) and iOS (App Store)","main":"./lib/module/index.js","types":"./lib/typescript/src/index.d.ts","exports":{".":{"chankruze-react-native-in-app-updates-source":"./src/index.tsx","types":"./lib/typescript/src/index.d.ts","default":"./lib/module/index.js"},"./package.json":"./package.json"},"scripts":{"example":"yarn workspace @chankruze/react-native-in-app-updates-example","clean":"del-cli android/build example/android/build example/android/app/build example/ios/build lib","prepare":"bob build","typecheck":"tsc","test":"jest","release":"release-it --only-version","lint":"eslint \"**/*.{js,ts,tsx}\""},"keywords":["react-native","ios","android"],"repository":{"type":"git","url":"git+https://github.com/chankruze/react-native-in-app-updates.git"},"author":{"name":"Chandan Kumar Mandal","email":"chankruze@gmail.com","url":"https://github.com/chankruze"},"license":"MIT","bugs":{"url":"https://github.com/chankruze/react-native-in-app-updates/issues"},"homepage":"https://github.com/chankruze/react-native-in-app-updates#readme","publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"devDependencies":{"@commitlint/config-conventional":"^21.0.2","@eslint/compat":"^2.1.0","@eslint/eslintrc":"^3.3.5","@eslint/js":"^10.0.1","@jest/globals":"^29.7.0","@react-native/babel-preset":"0.85.0","@react-native/eslint-config":"0.85.0","@react-native/jest-preset":"0.85.0","@release-it/conventional-changelog":"^11.0.1","@types/react":"^19.2.0","commitlint":"^21.0.2","del-cli":"^7.0.0","eslint":"^9.39.4","eslint-config-prettier":"^10.1.8","eslint-plugin-ft-flow":"^3.0.11","eslint-plugin-prettier":"^5.5.6","jest":"^29.7.0","lefthook":"^2.1.9","prettier":"^3.8.3","react":"19.2.3","react-native":"0.85.0","react-native-builder-bob":"^0.43.0","release-it":"^20.2.0","turbo":"^2.9.16","typescript":"^6.0.3"},"peerDependencies":{"react":"*","react-native":"*"},"workspaces":["example"],"packageManager":"yarn@4.11.0","react-native-builder-bob":{"source":"src","output":"lib","targets":[["module",{"esm":true}],["typescript",{"project":"tsconfig.build.json"}]]},"codegenConfig":{"name":"ReactNativeInAppUpdatesSpec","type":"modules","jsSrcsDir":"src","android":{"javaPackageName":"com.chankruze.reactnativeinappupdates"}},"jest":{"preset":"@react-native/jest-preset","testEnvironmentOptions":{"customExportConditions":["require","react-native","<%- project.sourceCondition -%>"]},"modulePathIgnorePatterns":["<rootDir>/example/node_modules","<rootDir>/lib/"]},"commitlint":{"extends":["@commitlint/config-conventional"]},"release-it":{"git":{"commitMessage":"chore: release ${version}","tagName":"v${version}"},"npm":{"publish":true},"github":{"release":true},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"prettier":{"quoteProps":"consistent","singleQuote":true,"tabWidth":2,"trailingComma":"es5","useTabs":false},"create-react-native-library":{"type":"turbo-module","languages":"kotlin-objc","tools":["jest","lefthook","release-it","eslint"],"version":"0.63.0"},"_id":"@chankruze/react-native-in-app-updates@0.1.1","gitHead":"2450944c9efbebdfaa9161caf2d7e57060a82a15","_nodeVersion":"24.3.0","_npmVersion":"11.4.2","dist":{"integrity":"sha512-8zlBl4nvB64yQlSOffh+COCbocGj9Ihq9sf/bKS262kjzGRMQJrf83R3wZawlEtRpwCxNNF+8dY2VLTYvdfl2Q==","shasum":"7b8d01b8976d11ba70b28688aed083a458fd0503","tarball":"https://registry.npmjs.org/@chankruze/react-native-in-app-updates/-/react-native-in-app-updates-0.1.1.tgz","fileCount":42,"unpackedSize":52610,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIE2veG3Dajhp3oxiGBriNLJo6LRN1unMoEygyr9QuhF6AiBvQWY3CthUrmFF25o/FwE/M8xW35g+Z+efz85nI6aJDg=="}]},"_npmUser":{"name":"chankruze","email":"chankruze@gmail.com"},"directories":{},"maintainers":[{"name":"chankruze","email":"chankruze@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-in-app-updates_0.1.1_1783700112437_0.8529769879156717"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-25T21:25:20.712Z","modified":"2026-07-10T16:15:12.726Z","0.1.0":"2026-06-25T21:25:21.000Z","0.1.1":"2026-07-10T16:15:12.640Z"},"bugs":{"url":"https://github.com/chankruze/react-native-in-app-updates/issues"},"author":{"name":"Chandan Kumar Mandal","email":"chankruze@gmail.com","url":"https://github.com/chankruze"},"license":"MIT","homepage":"https://github.com/chankruze/react-native-in-app-updates#readme","keywords":["react-native","ios","android"],"repository":{"type":"git","url":"git+https://github.com/chankruze/react-native-in-app-updates.git"},"description":"Lightweight in-app updates for Android (Play Store) and iOS (App Store)","maintainers":[{"name":"chankruze","email":"chankruze@gmail.com"}],"readme":"# @chankruze/react-native-in-app-updates\n\nLightweight in-app updates for Android and iOS.\n\n- **Android** — Google Play [In-App Updates API](https://developer.android.com/guide/playcore/in-app-updates) (FLEXIBLE + IMMEDIATE flows)\n- **iOS** — iTunes Search API version check + App Store redirect\n- **New Architecture** — TurboModule on Android, pure TypeScript on iOS\n- **Zero extra dependencies** beyond `react-native`\n\n## Compatibility\n\n| Environment                   | Supported |\n| ----------------------------- | --------- |\n| React Native CLI              | ✅        |\n| Expo Bare Workflow            | ✅        |\n| EAS Build + `expo-dev-client` | ✅        |\n| Expo Managed Workflow         | ❌        |\n| Expo Go                       | ❌        |\n\n> **Expo Managed / Expo Go users:** This library requires native module support which is not available in the managed sandbox. Use [`expo-in-app-updates`](https://github.com/SohelIslamImran/expo-in-app-updates) instead.\n\n**Why it won't work in Expo Managed Workflow**\n\nOur library uses the standard React Native TurboModule API (`NativeReactNativeInAppUpdatesSpec`, `TurboModuleRegistry`). Expo Go and Expo Managed Workflow sandbox\nthe native layer — custom `TurboModules` can't be registered because there's no access to the native build pipeline. The app would crash on the `TurboModuleRegistry.getEnforcing` call at startup.\n\nExpo has their own native module system (`expo-modules-core`) and their own in-app updates package (`expo-in-app-updates`) built on it. That's the right tool for managed Expo users.\n\n## Installation\n\n```sh\nyarn add @chankruze/react-native-in-app-updates\n# or\nnpm install @chankruze/react-native-in-app-updates\n```\n\n### iOS\n\nNo native setup needed — iOS is pure TypeScript.\n\n> **No `LSApplicationQueriesSchemes` required.** Unlike libraries that use the `itms-apps://` deep link scheme, this library opens the App Store via a standard `https://apps.apple.com/...` URL. HTTPS URLs do not need to be whitelisted in `Info.plist` or `app.json`.\n\n### Android\n\nNo manual linking needed. The library uses `com.google.android.play:app-update-ktx` which is bundled.\n\n> **Important:** In-App Updates only work on **release builds installed from the Play Store**. Debug builds always return `updateAvailable: false`.\n\n## Quick start\n\n```tsx\nimport { useEffect } from 'react';\nimport { Platform, Linking } from 'react-native';\nimport {\n  checkForUpdate,\n  startUpdate,\n  installUpdate,\n  addUpdateListener,\n  UpdateType,\n  InstallStatus,\n  type IosUpdateInfo,\n  type AndroidUpdateInfo,\n} from '@chankruze/react-native-in-app-updates';\n\nfunction useInAppUpdates() {\n  useEffect(() => {\n    // Android FLEXIBLE: auto-install once download completes\n    if (Platform.OS !== 'android') return;\n    return addUpdateListener('onInAppUpdateStatus', (event) => {\n      if (event.status === InstallStatus.DOWNLOADED) {\n        installUpdate();\n      }\n    });\n  }, []);\n\n  useEffect(() => {\n    const run = async () => {\n      try {\n        if (Platform.OS === 'ios') {\n          const info = (await checkForUpdate({\n            bundleId: 'com.example.myapp',\n            country: 'us',\n          })) as IosUpdateInfo;\n\n          if (info.updateAvailable && info.appStoreUrl) {\n            // Show your own modal, then:\n            Linking.openURL(info.appStoreUrl);\n          }\n        } else {\n          const info = (await checkForUpdate({})) as AndroidUpdateInfo;\n          if (info.updateAvailable) {\n            // priority >= 4 → force IMMEDIATE, otherwise FLEXIBLE\n            const type =\n              info.updatePriority >= 4\n                ? UpdateType.IMMEDIATE\n                : UpdateType.FLEXIBLE;\n            await startUpdate(type);\n          }\n        }\n      } catch {\n        // in-app updates are best-effort — never interrupt the user\n      }\n    };\n\n    run();\n  }, []);\n}\n```\n\n## API\n\n### `checkForUpdate(options?)`\n\nChecks whether an update is available.\n\n| Option       | Type     | Platform       | Description                                   |\n| ------------ | -------- | -------------- | --------------------------------------------- |\n| `bundleId`   | `string` | iOS (required) | App bundle ID                                 |\n| `country`    | `string` | iOS            | ISO 3166-1 country code (e.g. `'us'`, `'in'`) |\n| `curVersion` | `string` | iOS            | Current version to compare against            |\n\n**<img src=\"https://developer.android.com/static/images/brand/android-head_flat.png\" height=\"16\" alt=\"Android\" /> Returns `AndroidUpdateInfo` on Android:**\n\n| Field                | Type                 | Description                                        |\n| -------------------- | -------------------- | -------------------------------------------------- |\n| `updateAvailable`    | `boolean`            | Whether a newer version exists                     |\n| `availabilityStatus` | `AvailabilityStatus` | Raw Play Store availability enum                   |\n| `flexibleAllowed`    | `boolean`            | FLEXIBLE update is allowed                         |\n| `immediateAllowed`   | `boolean`            | IMMEDIATE update is allowed                        |\n| `updatePriority`     | `number`             | Server-set priority 0–5 (use `>= 4` for IMMEDIATE) |\n| `versionCode`        | `number`             | Available Play Store version code                  |\n| `daysSinceRelease`   | `number \\| null`     | Days since update was published                    |\n\n**<img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/IOS_logo.svg/1280px-IOS_logo.svg.png?_=20160930140049\" height=\"16\" alt=\"iOS\" /> Returns `IosUpdateInfo` on iOS:**\n\n| Field             | Type             | Description                                |\n| ----------------- | ---------------- | ------------------------------------------ |\n| `updateAvailable` | `boolean`        | Whether a newer version exists             |\n| `storeVersion`    | `string`         | Latest version string (e.g. `\"2.1.0\"`)     |\n| `releaseDate`     | `string \\| null` | ISO 8601 release date                      |\n| `appStoreUrl`     | `string \\| null` | Direct App Store URL for `Linking.openURL` |\n\n---\n\n### <img src=\"https://developer.android.com/static/images/brand/android-head_flat.png\" height=\"18\" alt=\"Android\" /> `startUpdate(updateType?)`\n\n_Android only._ Triggers the Play Store update flow.\n\n```ts\nawait startUpdate(UpdateType.FLEXIBLE); // download in background\nawait startUpdate(UpdateType.IMMEDIATE); // full-screen blocking update\n```\n\n---\n\n### <img src=\"https://developer.android.com/static/images/brand/android-head_flat.png\" height=\"18\" alt=\"Android\" /> `installUpdate()`\n\n_Android only._ Completes a finished FLEXIBLE download. Call this when `onInAppUpdateStatus` fires with `status === InstallStatus.DOWNLOADED`.\n\n---\n\n### <img src=\"https://developer.android.com/static/images/brand/android-head_flat.png\" height=\"18\" alt=\"Android\" /> `addUpdateListener(event, listener)`\n\n_Android only._ Subscribes to native update events. Returns an unsubscribe function.\n\n```ts\nconst unsubscribe = addUpdateListener('onInAppUpdateStatus', (event) => {\n  console.log(event.status); // InstallStatus enum value\n  console.log(event.bytesDownloaded); // bytes downloaded so far\n  console.log(event.totalBytesToDownload);\n});\n\n// cleanup\nunsubscribe();\n```\n\n**Events:**\n\n| Event                 | Payload             | Description                          |\n| --------------------- | ------------------- | ------------------------------------ |\n| `onInAppUpdateStatus` | `UpdateStatusEvent` | Download progress + install status   |\n| `onInAppUpdateResult` | `UpdateResultEvent` | Final result (installed / cancelled) |\n\n---\n\n### <img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/IOS_logo.svg/1280px-IOS_logo.svg.png?_=20160930140049\" height=\"18\" alt=\"iOS\" /> `openAppStore(appId)`\n\n_iOS only._ Opens the App Store page for the given numeric App Store ID.\n\n```ts\nopenAppStore('123456789');\n// opens https://apps.apple.com/app/id123456789\n```\n\nAlternatively, use `Linking.openURL(info.appStoreUrl)` with the URL from `checkForUpdate`.\n\n## Enums\n\n```ts\nenum UpdateType {\n  FLEXIBLE = 0, // background download, user continues using app\n  IMMEDIATE = 1, // full-screen blocking update\n}\n\nenum InstallStatus {\n  UNKNOWN = 0,\n  PENDING = 1,\n  DOWNLOADING = 2,\n  INSTALLING = 3,\n  INSTALLED = 4,\n  FAILED = 5,\n  CANCELED = 6,\n  DOWNLOADED = 11, // ready to install — call installUpdate()\n}\n\nenum AvailabilityStatus {\n  UNKNOWN = 0,\n  UNAVAILABLE = 1,\n  AVAILABLE = 2,\n  DEVELOPER_TRIGGERED = 3,\n}\n```\n\n## <img src=\"https://developer.android.com/static/images/brand/android-head_flat.png\" height=\"20\" alt=\"Android\" /> Android testing\n\nPlay Store In-App Updates require a **real device** with a **release build** installed from the **Play Store** (or Internal Testing track).\n\n1. Upload `versionCode = 1` to Play Console → Internal Testing track\n2. Install on device via the Internal Testing link\n3. Upload `versionCode = 2` to Internal Testing (no need to publish)\n4. Open the app — `checkForUpdate()` will now return `updateAvailable: true`\n\n## <img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/IOS_logo.svg/1280px-IOS_logo.svg.png?_=20160930140049\" height=\"20\" alt=\"iOS\" /> iOS testing\n\n`checkForUpdate()` hits the live iTunes Search API. To test:\n\n1. Ensure your app is published on the App Store\n2. Pass your production `bundleId` and the correct `country` code\n3. If the App Store version is higher than `curVersion`, `updateAvailable` will be `true`\n\n## License\n\nMIT\n\n---\n\nMade with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)\n","readmeFilename":"README.md"}