├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json └── src ├── api.js ├── validation.js └── version-check.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | app*.log 4 | *.log 5 | npm-debug.log* 6 | 7 | # Optional npm cache directory 8 | .npm 9 | 10 | # nyc test coverage 11 | .nyc_output 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage/* 15 | test-results.xml 16 | 17 | # Dependency directories 18 | node_modules/ 19 | 20 | # dotenv environment variables file 21 | .env 22 | 23 | # IDE 24 | .idea 25 | .vscode 26 | 27 | # Transpiled JavaScript files from Typescript 28 | dist 29 | 30 | # Cache used by TypeScript's incremental build 31 | *.tsbuildinfo 32 | 33 | # Sonar 34 | .scannerwork -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes will be documented in this file. 4 | 5 | ## [1.0.17] - 2024-05-28 6 | 7 | * Update axios version 8 | 9 | ## [1.0.16] - 2023-08-20 10 | 11 | * Add custom attributes support 12 | 13 | ## [1.0.15] - 2023-04-06 14 | 15 | * Update README docs examples 16 | 17 | ## [1.0.14] - 2023-03-28 18 | 19 | * Update README docs. 20 | 21 | ## [1.0.13] - 2023-03-24 22 | 23 | * Fix launch of store. 24 | 25 | ## [1.0.12] - 2023-03-01 26 | 27 | * Added Google playstore as default fallback marketplace for android. 28 | 29 | ## [1.0.11] - 2023-02-27 30 | 31 | * Added support for Amazon, Huawei and other marketplaces. 32 | 33 | ## [1.0.10] - 2023-02-03 34 | 35 | * Fix url encoding for app name. 36 | * Added request retry for failed requests. 37 | 38 | ## [1.0.9] - 2023-01-16 39 | 40 | * Fix localization backward compatibility. 41 | 42 | ## [1.0.8] - 2023-01-16 43 | 44 | * Add support for update message localization. 45 | 46 | ## [1.0.7] - 2023-01-02 47 | 48 | * Minor changes in console error messages. 49 | 50 | ## [1.0.6] - 2022-08-24 51 | 52 | * Fix force upgrade alert popup disappering if returned from store. 53 | 54 | ## [1.0.5] - 2022-05-10 55 | 56 | * Use appId instead of appStore to redirect to respective app stores. 57 | ## [1.0.4] - 2022-05-10 58 | 59 | * Use appStoreUrl instead of appId to redirect to respective app stores. 60 | ## [1.0.3] - 2022-05-09 61 | 62 | * Add iOS screenshots. 63 | ## [1.0.2] - 2022-05-06 64 | 65 | * Fix issues with Expo. 66 | ## [1.0.1] - 2022-05-06 67 | 68 | * Expo support. 69 | ## [1.0.0] - 2022-04-30 70 | 71 | * Initial release. 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022-23 App Upgrade 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included in all 10 | copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # App Upgrade: React-Native SDK 2 | 3 | React-Native/Expo SDK for [App Upgrade](https://appupgrade.dev) 4 | 5 | App Upgrade is a service let your users know when to upgrade your apps or force them to upgrade the app. 6 | 7 | [![Twitter](https://img.shields.io/twitter/follow/app_upgrade?style=social)](https://twitter.com/app_upgrade) 8 | [![YouTube](https://img.shields.io/youtube/channel/subscribers/UC0ZVJPYHFVuMwEsro4VZKXw?style=social)](https://www.youtube.com/channel/UC0ZVJPYHFVuMwEsro4VZKXw) 9 | 10 | Many times we need to force upgrade mobile apps on users' mobile. Having faced this issue multiple times decided to find a better way to tackle this problem. After doing some research on how people are doing this there are so many custom solutions or checking with the play store or AppStore API if there is a new version available. Although this works if we just want to nudge users that there is a new version available. It doesn't solve the problem where we want to make a decision.. whether it's a soft graceful update or we want to force update. So here is this product that will make developers' life easy. We can set custom messages.. see the versions in beautify dashboard, and many exciting features in the roadmap ahead. 11 | 12 | This SDK communicate with App Upgrade and check the version with store version information in App Upgrade. Based on response it will: 13 | - If app needs force update will show a non-dismissable popup for update. On click it will launch app in app store for user to update. 14 | - If app needs to be updated but not a force update, it will show a dismissable popup. 15 | - If no action is required it won't do anything. 16 | 17 | App Upgrade is a cross platform solution to getting users to easily update your app. 18 | ##### Stores Supported: 19 | Apple App Store | Google Play Store | Amazon App Store | Huawei AppGallery | Other Android Markets 20 | --- | --- | --- | --- | --- 21 | **✓** | **✓** | **✓** | **✓** | **✓** If your app market place isn't one of these you can pass your own store URL. 22 | 23 | ## Installation 24 | Install via npm 25 | ``` 26 | npm i app-upgrade-react-native-sdk --save 27 | ``` 28 | 29 | Or if using Expo than you can use `expo install app-upgrade-react-native-sdk` as well. 30 | 31 | ## How to use it. 32 | 1. Register on App Upgrade and follow the instructions to create project and get the x-api-key. 33 | 34 | 2. Import the SDK and use it. 35 | ### React Native Example 36 | ``` 37 | import {appUpgradeVersionCheck} from 'app-upgrade-react-native-sdk'; 38 | 39 | ..... 40 | 41 | const App: () => Node = () => { 42 | 43 | const xApiKey = "MDNmNmZkNDEtNmNkMi00NzY3LThjOWEtYWYxMGFjZWQ0ZjI2"; // Your project key 44 | const appInfo = { 45 | appId: 'com.android.com' or '1549468967', // Your app id in play store or app store 46 | appName: 'Wallpaper app', // Your app name 47 | appVersion: '1.0.0', // Your app version 48 | platform: 'android', // App Platform, android or ios 49 | environment: 'production', // App Environment, production, development 50 | appLanguage: 'es' //Your app language ex: en, es etc. Optional. 51 | }; 52 | 53 | // Alert config is optional 54 | const alertConfig = { 55 | title: 'Please Update', 56 | updateButtonTitle: 'Update Now', 57 | laterButtonTitle: 'Later', 58 | onDismissCallback: () => { console.log('Dismiss') }, 59 | onLaterCallback: () => { console.log('Later') } 60 | onUpdateCallback: () => { console.log('Update') } 61 | }; 62 | 63 | appUpgradeVersionCheck(appInfo, xApiKey, alertConfig); 64 | 65 | return ( 66 | 67 | ... 68 | 69 | ); 70 | }; 71 | 72 | ``` 73 | 74 | ### Expo Example: 75 | ``` 76 | import {appUpgradeVersionCheck} from 'app-upgrade-react-native-sdk'; 77 | 78 | ..... 79 | 80 | export default function App() { 81 | const xApiKey = "MDNmNmZkNDEtNmNkMi00NzY3LThjOWEtYWYxMGFjZWQ0ZjI2"; // Your project key 82 | const appInfo = { 83 | appId: 'com.android.com' or '1549468967', // Your app id in play store or app store 84 | appName: 'Wallpaper app', // Your app name 85 | appVersion: '1.0.0', // Your app version 86 | platform: 'android', // App Platform, android or ios 87 | environment: 'production', // App Environment, production, development 88 | appLanguage: 'es' //Your app language ex: en, es etc. Optional. 89 | }; 90 | 91 | // Alert config is optional 92 | const alertConfig = { 93 | title: 'Please Update', 94 | updateButtonTitle: 'Update Now', 95 | laterButtonTitle: 'Later', 96 | onDismissCallback: () => { console.log('Dismiss') }, 97 | onLaterCallback: () => { console.log('Later') } 98 | onUpdateCallback: () => { console.log('Update') } 99 | }; 100 | 101 | appUpgradeVersionCheck(appInfo, xApiKey, alertConfig); 102 | 103 | return ( 104 | 105 | Open up App.js to start working on your app! 106 | 107 | 108 | ); 109 | } 110 | 111 | ``` 112 | ### Note: 113 | 1. For opening the app store or play store the app should be live. 114 | 2. It might not be able to open the app store or play store in simulator. You can try it in physical device. 115 | 3. If you are using the same code base for both android and ios than you can detect the platform and provide the appId. 116 | 4. You can find a sample app from here [app-upgrade-react-native-demo-app](https://github.com/appupgrade-dev/app_upgrade_react_native_demo_app) 117 | 5. Read detailed blog on how to integrate from here [How to upgrade/force upgrade React Native app](https://appupgrade.dev/blog/how-to-force-upgrade-react-native-app) 118 | 119 | ### Example with store other than app store or play store. 120 | If you want users to redirect to store other than app store or playstore. You can add these additional parameters **preferredAndroidMarket** see the example below. 121 | ``` 122 | import {appUpgradeVersionCheck, PreferredAndroidMarket } from 'app-upgrade-react-native-sdk'; 123 | 124 | ..... 125 | 126 | const App: () => Node = () => { 127 | 128 | const xApiKey = "MDNmNmZkNDEtNmNkMi00NzY3LThjOWEtYWYxMGFjZWQ0ZjI2"; // Your project key 129 | const appInfo = { 130 | appId: 'com.android.com' or '1549468967', // Your app id in play store or app store 131 | appName: 'Wallpaper app', // Your app name 132 | appVersion: '1.0.0', // Your app version 133 | platform: 'android', // App Platform, android or ios 134 | environment: 'production', // App Environment, production, development 135 | appLanguage: 'es' //Your app language ex: en, es etc. Optional. 136 | preferredAndroidMarket: PreferredAndroidMarket.AMAZON // or PreferredAndroidMarket.HUAWEI or PreferredAndroidMarket.OTHER If not provided default is Google playstore. Optional 137 | }; 138 | 139 | appUpgradeVersionCheck(appInfo, xApiKey); 140 | 141 | return ( 142 | 143 | ... 144 | 145 | ); 146 | }; 147 | 148 | ``` 149 | 150 | - preferredAndroidMarket: PreferredAndroidMarket.AMAZON // or PreferredAndroidMarket.HUAWEI or PreferredAndroidMarket.OTHER If not provided default is Google playstore. If SDK fails to open preferred market place in case marketplace is not available then default Google playstore will be open. 151 | 152 | If you want to redirect user to some other android market place you can add the following fields: 153 | ``` 154 | preferredAndroidMarket: PreferredAndroidMarket.OTHER 155 | otherAndroidMarketUrl: 'https://someotherandroidmarket.com/app/id'// Required if preferredAndroidMarket is Other. 156 | ``` 157 | 158 | ``` 159 | import {appUpgradeVersionCheck, PreferredAndroidMarket } from 'app-upgrade-react-native-sdk'; 160 | 161 | ..... 162 | 163 | const App: () => Node = () => { 164 | 165 | const xApiKey = "MDNmNmZkNDEtNmNkMi00NzY3LThjOWEtYWYxMGFjZWQ0ZjI2"; // Your project key 166 | const appInfo = { 167 | appId: 'com.android.com' or '1549468967', // Your app id in play store or app store 168 | appName: 'Wallpaper app', // Your app name 169 | appVersion: '1.0.0', // Your app version 170 | platform: 'android', // App Platform, android or ios 171 | environment: 'production', // App Environment, production, development 172 | appLanguage: 'es' //Your app language ex: en, es etc. Optional. 173 | preferredAndroidMarket: PreferredAndroidMarket.OTHER 174 | otherAndroidMarketUrl: 'https://someotherandroidmarket.com/app/id'// Required if preferredAndroidMarket is Other. 175 | }; 176 | 177 | appUpgradeVersionCheck(appInfo, xApiKey); 178 | 179 | return ( 180 | 181 | ... 182 | 183 | ); 184 | }; 185 | 186 | ``` 187 | 188 | ## Example Screenshot 189 | ### Android 190 | For force upgrade only Update button is enable and user cannot skip it. 191 | For recommended upgrade Update and Later button is enable. User can skip it. 192 | 193 | ![image](https://raw.githubusercontent.com/appupgrade-dev/app-upgrade-assets/main/images/forceupgrade_android.png) 194 | 195 | ### iOS 196 | 197 | ![image](https://raw.githubusercontent.com/appupgrade-dev/app-upgrade-assets/main/images/forceupgrade_ios.jpg) 198 | 199 | 200 | ### Callbacks Documentations 201 | SDK provides you two callbacks. 202 | 1. onDismissCallback 203 | onDismissCallback callback is called when the dismisses the popup, by clicking elsewhere on the screen. In the non-force upgrade, SDK will show a popup with the Later button and the Update Now button. If the user just clicks outside elsewhere the popup it will dismiss and SDK will call onDismissCallback. 204 | 205 | 2. onLaterCallback 206 | If the user clicks on the Later button the SDK will call the onLaterCallback. You can use these for tracking purposes or for something else. onLaterCallback can be used to set a timer and remind the user later that can be done from the app. 207 | 208 | 3. onUpdateCallback 209 | If the user clicks on the Update button the SDK will call the onUpdateCallback. You can use these for tracking purposes or for something else. 210 | 211 | ## App Upgrade Docs 212 | For more information visit [App Upgrade](https://appupgrade.dev) 213 | 214 | ### Changelog 215 | 216 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 217 | 218 | ### Contributing 219 | 220 | Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE OF CONDUCT](CODE_OF_CONDUCT.md) for details. 221 | 222 | ### License 223 | 224 | The MIT License (MIT). Please see [License File](LICENSE) for more information. 225 | 226 | ## Need help? 227 | 228 | If you're looking for help, try our [Documentation](https://appupgrade.dev/docs/) or our [FAQ](https://appupgrade.dev/docs/app-upgrade-faq). 229 | If you need support please write to us at support@appupgrade.dev 230 | 231 | ### Happy Coding!!! 232 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { versionCheck } from "./src/version-check"; 2 | 3 | const PreferredAndroidMarket = { 4 | GOOGLE: 'Google', 5 | HUAWEI: 'Huawei', 6 | AMAZON: 'Amazon', 7 | OTHER: 'Other', 8 | } 9 | 10 | function appUpgradeVersionCheck(appInfo, xApiKey, alertInfo) { 11 | versionCheck(appInfo, xApiKey, alertInfo); 12 | } 13 | 14 | export { appUpgradeVersionCheck, PreferredAndroidMarket }; 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-upgrade-react-native-sdk", 3 | "version": "1.0.17", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/runtime": { 8 | "version": "7.20.13", 9 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", 10 | "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", 11 | "requires": { 12 | "regenerator-runtime": "^0.13.11" 13 | } 14 | }, 15 | "asynckit": { 16 | "version": "0.4.0", 17 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 18 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 19 | }, 20 | "axios": { 21 | "version": "1.7.2", 22 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", 23 | "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", 24 | "requires": { 25 | "follow-redirects": "^1.15.6", 26 | "form-data": "^4.0.0", 27 | "proxy-from-env": "^1.1.0" 28 | } 29 | }, 30 | "axios-retry": { 31 | "version": "3.4.0", 32 | "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.4.0.tgz", 33 | "integrity": "sha512-VdgaP+gHH4iQYCCNUWF2pcqeciVOdGrBBAYUfTY+wPcO5Ltvp/37MLFNCmJKo7Gj3SHvCSdL8ouI1qLYJN3liA==", 34 | "requires": { 35 | "@babel/runtime": "^7.15.4", 36 | "is-retry-allowed": "^2.2.0" 37 | } 38 | }, 39 | "combined-stream": { 40 | "version": "1.0.8", 41 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 42 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 43 | "requires": { 44 | "delayed-stream": "~1.0.0" 45 | } 46 | }, 47 | "delayed-stream": { 48 | "version": "1.0.0", 49 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 50 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" 51 | }, 52 | "follow-redirects": { 53 | "version": "1.15.6", 54 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 55 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" 56 | }, 57 | "form-data": { 58 | "version": "4.0.0", 59 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 60 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 61 | "requires": { 62 | "asynckit": "^0.4.0", 63 | "combined-stream": "^1.0.8", 64 | "mime-types": "^2.1.12" 65 | } 66 | }, 67 | "is-retry-allowed": { 68 | "version": "2.2.0", 69 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", 70 | "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==" 71 | }, 72 | "mime-db": { 73 | "version": "1.52.0", 74 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 75 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 76 | }, 77 | "mime-types": { 78 | "version": "2.1.35", 79 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 80 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 81 | "requires": { 82 | "mime-db": "1.52.0" 83 | } 84 | }, 85 | "proxy-from-env": { 86 | "version": "1.1.0", 87 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 88 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 89 | }, 90 | "regenerator-runtime": { 91 | "version": "0.13.11", 92 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 93 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-upgrade-react-native-sdk", 3 | "version": "1.0.17", 4 | "description": "Official App Upgrade react-native sdk", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "App Upgrade (https://appupgrade.dev)", 10 | "homepage": "https://github.com/appupgrade-dev/app-upgrade-react-native-sdk", 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/appupgrade-dev/app-upgrade-react-native-sdk.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/appupgrade-dev/app-upgrade-react-native-sdk.git/issues" 17 | }, 18 | "license": "MIT", 19 | "dependencies": { 20 | "axios": "^1.6.0", 21 | "axios-retry": "^3.4.0" 22 | }, 23 | "peerDependencies": { 24 | "react": ">=16.9.0", 25 | "react-native": ">=0.59.9" 26 | }, 27 | "keywords": [ 28 | "app-update", 29 | "react-native", 30 | "force-update", 31 | "version", 32 | "app-upgrade", 33 | "force-upgrade" 34 | ], 35 | "devDependencies": {} 36 | } 37 | -------------------------------------------------------------------------------- /src/api.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import axiosRetry from "axios-retry"; 3 | 4 | async function checkVersionWithAppUpgrade(appInfo, xApiKey) { 5 | try { 6 | const appUpgradeBaseUrl = "https://appupgrade.dev"; 7 | const { appName, appVersion, platform, environment, appLanguage } = appInfo; 8 | 9 | const { customAttributes } = appInfo; 10 | 11 | axiosRetry(axios, { 12 | retries: 3, 13 | retryDelay: axiosRetry.exponentialDelay, 14 | retryCondition: () => true, 15 | }); 16 | 17 | const params = { 18 | app_name: appName, 19 | app_version: appVersion, 20 | platform: platform, 21 | environment: environment, 22 | app_language: appLanguage, 23 | }; 24 | 25 | for (const key in customAttributes) { 26 | params[key] = customAttributes[key]; 27 | } 28 | 29 | const response = await axios.get( 30 | `${appUpgradeBaseUrl}/api/v1/versions/check`, 31 | { 32 | headers: { 33 | "x-api-key": xApiKey, 34 | sdk: "react-native", //Telemetry purposes 35 | }, 36 | params, 37 | validateStatus: function (status) { 38 | return status >= 200 && status < 500; // default 39 | }, 40 | } 41 | ); 42 | 43 | if (response.status === 200) { 44 | console.info( 45 | "App Upgrade: Api Response: ", 46 | JSON.stringify(response.data) 47 | ); 48 | return response.data; 49 | } else { 50 | console.error("App Upgrade:", response.data.message); 51 | } 52 | } catch (e) { 53 | console.error("App Upgrade Error:", e.message); 54 | } 55 | } 56 | 57 | export { checkVersionWithAppUpgrade }; 58 | -------------------------------------------------------------------------------- /src/validation.js: -------------------------------------------------------------------------------- 1 | import { PreferredAndroidMarket } from "app-upgrade-react-native-sdk"; 2 | 3 | function validate(appInfo, xApiKey) { 4 | if (!xApiKey || xApiKey === undefined || xApiKey === "") { 5 | console.error("App Upgrade Validation Error: xApiKey is required."); 6 | return false; 7 | } else if (appInfo === undefined || appInfo === "" || !appInfo) { 8 | console.error( 9 | "App Upgrade Validation Error: Please provide valid app info object." 10 | ); 11 | return false; 12 | } else if ( 13 | !appInfo.appId || 14 | appInfo.appId === undefined || 15 | appInfo.appId === "" 16 | ) { 17 | console.error("App Upgrade Validation Error: appId is required."); 18 | return false; 19 | } else if ( 20 | !appInfo.appName || 21 | appInfo.appName === undefined || 22 | appInfo.appName === "" 23 | ) { 24 | console.error("App Upgrade Validation Error: appName is required."); 25 | return false; 26 | } else if ( 27 | !appInfo.appName || 28 | appInfo.appVersion === undefined || 29 | appInfo.appVersion === "" 30 | ) { 31 | console.error("App Upgrade Validation Error: appVersion is required."); 32 | return false; 33 | } else if ( 34 | !appInfo.platform || 35 | appInfo.platform === undefined || 36 | appInfo.platform === "" 37 | ) { 38 | console.error("App Upgrade Validation Error: platform is required."); 39 | return false; 40 | } else if ( 41 | !appInfo.environment || 42 | appInfo.environment === undefined || 43 | appInfo.environment === "" 44 | ) { 45 | console.error("App Upgrade Validation Error: environment is required."); 46 | return false; 47 | } else if ( 48 | appInfo.preferredAndroidMarket && 49 | appInfo.preferredAndroidMarket === PreferredAndroidMarket.OTHER && 50 | !appInfo.otherAndroidMarketUrl 51 | ) { 52 | console.error( 53 | "App Upgrade Validation Error: otherMarketUrl is required when prefferedAndroidMarket is Other." 54 | ); 55 | return false; 56 | } else if ( 57 | appInfo.preferredAndroidMarket && 58 | !Object.values(PreferredAndroidMarket).includes( 59 | appInfo.preferredAndroidMarket 60 | ) 61 | ) { 62 | console.error( 63 | "App Upgrade Validation Error: Unsupported prefferedAndroidMarket value." 64 | ); 65 | return false; 66 | } else { 67 | return true; 68 | } 69 | } 70 | 71 | export { validate }; 72 | -------------------------------------------------------------------------------- /src/version-check.js: -------------------------------------------------------------------------------- 1 | import { validate } from "./validation"; 2 | import { checkVersionWithAppUpgrade } from "./api"; 3 | import { Platform, Alert, Linking } from "react-native"; 4 | import { PreferredAndroidMarket } from "app-upgrade-react-native-sdk"; 5 | 6 | async function versionCheck(appInfo, xApiKey, alertInfo) { 7 | const isValid = validate(appInfo, xApiKey); 8 | 9 | if (isValid) { 10 | const version = await checkVersionWithAppUpgrade(appInfo, xApiKey); 11 | if (!version) { 12 | console.error("App Upgrade Error: Version is null."); 13 | } else if (version && version.found === true) { 14 | if (version.forceUpgrade === true) { 15 | console.info("App Upgrade: Version force upgrade is required."); 16 | // show force upgrade alert 17 | showForceUpgradeAlert(appInfo, alertInfo, version.message); 18 | } else { 19 | console.info( 20 | "App Upgrade: Version force upgrade is not required but upgrade is recommended." 21 | ); 22 | // show upgrade alert 23 | showUpgradeAlert(appInfo, alertInfo, version.message); 24 | } 25 | } else { 26 | console.info( 27 | "App Upgrade: Version information not found. No action required." 28 | ); 29 | } 30 | } 31 | } 32 | 33 | function showForceUpgradeAlert(appInfo, alertInfo, msg) { 34 | Alert.alert( 35 | alertInfo.title ? alertInfo.title : "Please update", 36 | msg, 37 | [ 38 | { 39 | text: alertInfo.updateButtonTitle 40 | ? alertInfo.updateButtonTitle 41 | : "Update Now", 42 | onPress: () => { 43 | showForceUpgradeAlert(appInfo, alertInfo, msg); 44 | redirectToStore(appInfo); 45 | }, 46 | }, 47 | ], 48 | { 49 | cancelable: false, 50 | } 51 | ); 52 | } 53 | 54 | function showUpgradeAlert(appInfo, alertInfo, msg) { 55 | Alert.alert( 56 | alertInfo.title ? alertInfo.title : "Please update", 57 | msg, 58 | [ 59 | { 60 | text: alertInfo.laterButtonTitle ? alertInfo.laterButtonTitle : "Later", 61 | onPress: () => 62 | alertInfo.onLaterCallback ? alertInfo.onLaterCallback() : null, 63 | }, 64 | { 65 | text: alertInfo.updateButtonTitle 66 | ? alertInfo.updateButtonTitle 67 | : "Update Now", 68 | onPress: () => { 69 | alertInfo.onUpdateCallback ? alertInfo.onUpdateCallback() : null; 70 | redirectToStore(appInfo); 71 | }, 72 | }, 73 | ], 74 | { 75 | cancelable: true, 76 | onDismiss: () => 77 | alertInfo.onDismissCallback ? alertInfo.onDismissCallback() : null, 78 | } 79 | ); 80 | } 81 | 82 | function redirectToStore(appInfo) { 83 | if (Platform.OS === "android") { 84 | const defaultGooglePlaystoreUrl = `https://play.google.com/store/apps/details?id=${appInfo.appId}`; 85 | 86 | if (appInfo.preferredAndroidMarket === PreferredAndroidMarket.GOOGLE) { 87 | const url = `https://play.google.com/store/apps/details?id=${appInfo.appId}`; 88 | openPreferredAndroidMarket(url, defaultGooglePlaystoreUrl); 89 | } else if ( 90 | appInfo.preferredAndroidMarket === PreferredAndroidMarket.HUAWEI 91 | ) { 92 | const url = `appmarket://details?id=${appInfo.appId}`; 93 | openPreferredAndroidMarket(url, defaultGooglePlaystoreUrl); 94 | } else if ( 95 | appInfo.preferredAndroidMarket === PreferredAndroidMarket.AMAZON 96 | ) { 97 | const url = `https://www.amazon.com/gp/mas/dl/android?p=${appInfo.appId}`; 98 | openPreferredAndroidMarket(url, defaultGooglePlaystoreUrl); 99 | } else if ( 100 | appInfo.preferredAndroidMarket === PreferredAndroidMarket.OTHER 101 | ) { 102 | openPreferredAndroidMarket(appInfo.otherAndroidMarketUrl); 103 | } else { 104 | openPreferredAndroidMarket( 105 | `https://play.google.com/store/apps/details?id=${appInfo.appId}` 106 | ); 107 | } 108 | } else { 109 | Linking.openURL(`https://apps.apple.com/app/id/${appInfo.appId}`); 110 | } 111 | } 112 | 113 | function openPreferredAndroidMarket(url, defaultGooglePlaystoreUrl) { 114 | Linking.openURL(url).catch((err) => { 115 | console.debug( 116 | "App Upgrade Error: Could not open the preferred android market. Defaulting to Google Playstore.", 117 | err.message 118 | ); 119 | Linking.openURL(defaultGooglePlaystoreUrl); 120 | }); 121 | } 122 | 123 | export { versionCheck }; 124 | --------------------------------------------------------------------------------