├── InAppUpdate.js ├── InAppUpdateModule.java ├── InAppUpdatePackage.java └── README.md /InAppUpdate.js: -------------------------------------------------------------------------------- 1 | import {NativeModules} from 'react-native' 2 | 3 | module.exports = NativeModules.InAppUpdate 4 | -------------------------------------------------------------------------------- /InAppUpdateModule.java: -------------------------------------------------------------------------------- 1 | package com.example.inappupdate; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.IntentSender; 6 | import android.graphics.Color; 7 | 8 | import androidx.annotation.NonNull; 9 | 10 | import com.facebook.react.bridge.ActivityEventListener; 11 | import com.facebook.react.bridge.BaseActivityEventListener; 12 | import com.facebook.react.bridge.LifecycleEventListener; 13 | import com.facebook.react.bridge.ReactApplicationContext; 14 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 15 | import com.facebook.react.bridge.ReactMethod; 16 | import com.google.android.material.snackbar.Snackbar; 17 | import com.google.android.play.core.appupdate.AppUpdateInfo; 18 | import com.google.android.play.core.appupdate.AppUpdateManager; 19 | import com.google.android.play.core.appupdate.AppUpdateManagerFactory; 20 | import com.google.android.play.core.install.InstallState; 21 | import com.google.android.play.core.install.InstallStateUpdatedListener; 22 | import com.google.android.play.core.install.model.AppUpdateType; 23 | import com.google.android.play.core.install.model.InstallStatus; 24 | import com.google.android.play.core.install.model.UpdateAvailability; 25 | import com.google.android.play.core.tasks.Task; 26 | 27 | import java.util.Objects; 28 | 29 | import static android.app.Activity.RESULT_OK; 30 | 31 | public class InAppUpdateModule extends ReactContextBaseJavaModule implements InstallStateUpdatedListener, LifecycleEventListener { 32 | private AppUpdateManager appUpdateManager; 33 | private static ReactApplicationContext reactContext; 34 | private static final int STALE_DAYS = 5; 35 | private static final int MY_REQUEST_CODE = 0; 36 | 37 | private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() { 38 | @Override 39 | public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) { 40 | if (requestCode == MY_REQUEST_CODE) { 41 | if (resultCode != RESULT_OK) { 42 | System.out.println("Update flow failed! Result code: " + resultCode); 43 | // If the update is cancelled or fails, 44 | // you can request to start the update again. 45 | } 46 | } 47 | } 48 | }; 49 | 50 | InAppUpdateModule(ReactApplicationContext context) { 51 | super(context); 52 | reactContext = context; 53 | reactContext.addActivityEventListener(mActivityEventListener); 54 | reactContext.addLifecycleEventListener(this); 55 | 56 | } 57 | 58 | @NonNull 59 | @Override 60 | public String getName() { 61 | return "InAppUpdate"; 62 | } 63 | 64 | @ReactMethod 65 | public void checkUpdate() { 66 | appUpdateManager = AppUpdateManagerFactory.create(reactContext); 67 | appUpdateManager.registerListener(this); 68 | Task appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); 69 | appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> { 70 | if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE 71 | && appUpdateInfo.clientVersionStalenessDays() != null 72 | && appUpdateInfo.clientVersionStalenessDays() > STALE_DAYS 73 | && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) { 74 | try { 75 | appUpdateManager.startUpdateFlowForResult( 76 | appUpdateInfo, 77 | AppUpdateType.IMMEDIATE, 78 | reactContext.getCurrentActivity(), 79 | MY_REQUEST_CODE); 80 | } catch (IntentSender.SendIntentException e) { 81 | e.printStackTrace(); 82 | } 83 | }else{ 84 | if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE 85 | && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { 86 | try { 87 | appUpdateManager.startUpdateFlowForResult( 88 | appUpdateInfo, 89 | AppUpdateType.FLEXIBLE, 90 | reactContext.getCurrentActivity(), 91 | MY_REQUEST_CODE); 92 | } catch (IntentSender.SendIntentException e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | } 97 | 98 | }); 99 | 100 | } 101 | 102 | @Override 103 | public void onStateUpdate(InstallState state) { 104 | if (state.installStatus() == InstallStatus.DOWNLOADED) { 105 | popupSnackbarForCompleteUpdate(); 106 | } 107 | } 108 | 109 | private void popupSnackbarForCompleteUpdate() { 110 | Snackbar snackbar = 111 | Snackbar.make(Objects.requireNonNull(reactContext.getCurrentActivity()).findViewById(android.R.id.content).getRootView(), 112 | "An update has just been downloaded.", 113 | Snackbar.LENGTH_INDEFINITE); 114 | snackbar.setAction("RESTART", view -> appUpdateManager.completeUpdate()); 115 | snackbar.setActionTextColor(Color.GREEN); 116 | snackbar.show(); 117 | } 118 | 119 | @Override 120 | public void onHostResume() { 121 | if (appUpdateManager != null) { 122 | appUpdateManager 123 | .getAppUpdateInfo() 124 | .addOnSuccessListener( 125 | appUpdateInfo -> { 126 | if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) { 127 | popupSnackbarForCompleteUpdate(); 128 | } 129 | if (appUpdateInfo.updateAvailability() 130 | == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) { 131 | try { 132 | appUpdateManager.startUpdateFlowForResult( 133 | appUpdateInfo, 134 | AppUpdateType.IMMEDIATE, 135 | reactContext.getCurrentActivity(), 136 | MY_REQUEST_CODE); 137 | } catch (IntentSender.SendIntentException e) { 138 | e.printStackTrace(); 139 | } 140 | } 141 | 142 | }); 143 | } 144 | } 145 | 146 | @Override 147 | public void onHostPause() { 148 | 149 | } 150 | 151 | @Override 152 | public void onHostDestroy() { 153 | if (appUpdateManager != null) { 154 | appUpdateManager.unregisterListener(this); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /InAppUpdatePackage.java: -------------------------------------------------------------------------------- 1 | package com.example.inappupdate; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.NativeModule; 7 | import com.facebook.react.bridge.ReactApplicationContext; 8 | import com.facebook.react.uimanager.ViewManager; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class InAppUpdatePackage implements ReactPackage { 15 | @NonNull 16 | @Override 17 | public List createNativeModules(@NonNull ReactApplicationContext reactContext) { 18 | 19 | List modules = new ArrayList<>(); 20 | modules.add(new InAppUpdateModule(reactContext)); 21 | return modules; 22 | } 23 | 24 | @NonNull 25 | @Override 26 | public List createViewManagers(@NonNull ReactApplicationContext reactContext) { 27 | return Collections.emptyList(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-inapp-update 2 | 3 | Here is the all steps to achieve in-app update in React Native 4 | 5 | ### How to use ? 6 | 7 | 1. Open `android` folder in your react-native project with `Android Studio` and add `implementation "com.google.android.material:material:1.1.0"` and `implementation 'com.google.android.play:core:1.7.3'` at the end of dependencies section of the `build.gradle(app)` file. Like below, 8 | 9 | ``` 10 | dependencies { 11 | implementation fileTree(dir: "libs", include: ["*.jar"]) 12 | 13 | implementation "com.facebook.react:react-native:+" // From node_modules 14 | 15 | 16 | ....... 17 | implementation "com.google.android.material:material:1.1.0" 18 | implementation 'com.google.android.play:core:1.7.3' // at the end 19 | } 20 | 21 | ``` 22 | 23 | Cick sync after adding the dependency. 24 | 25 | 2. Download `InAppUpdateModule.java` and `InAppUpdatePackage.java` files and place in them in the same directory of `MainActivity.java`(`android/app/src/main/java//`) 26 | 3. Change the package names in both `InAppUpdateModule.java` and `InAppUpdatePackage.java` to your project package name. 27 | 4. Now Open `MainApplication.java` and add our `InAppUpdatePackage` into `getPackages` method like below, 28 | 29 | ``` 30 | @Override 31 | protected List getPackages() { 32 | @SuppressWarnings("UnnecessaryLocalVariable") 33 | List packages = new PackageList(this).getPackages(); 34 | // Packages that cannot be autolinked yet can be added manually here, for example: 35 | // packages.add(new MyReactNativePackage()); 36 | 37 | packages.add(new InAppUpdatePackage()); 38 | return packages; 39 | } 40 | ``` 41 | 42 | 5. Download `InAppUpdate.js` and place it into your `react-native` project. 43 | 6. Import the `InAppUpdate.js` in any `js` file, wherever you want to use. And use it like below. 44 | 45 | ``` 46 | useEffect(() => { 47 | InAppUpdate.checkUpdate() // this is how you check for update 48 | }, []); 49 | 50 | ``` 51 | 52 | 7. That's it. 53 | 54 | ### For testing you can use internal app sharing 55 | 56 | Here is the full desciption where you can go through and see how it works and how we can test this feature. 57 | ->https://developer.android.com/guide/playcore/in-app-updates#internal-app-sharing 58 | 59 | ->https://stackoverflow.com/questions/56087064/how-can-i-test-in-app-updates-in-android 60 | --------------------------------------------------------------------------------