Core Android

Android force update using Firebase

In this post, we’ll learn android force update app when a new version is available on play store. What is the need for android force update app? this is a valid question mobile apps are not like just websites. In Android, mostly people download app from play store and update them if there is a new version.

Let’s suppose your older version of your app is not functional anymore. Then you have to update the current app with newer version. How can I force users to update the old app when older version is not functional. In this app tutorial, I’ll tell you how to force an update mechanism to protect your app from bad comments. So lets started

1. Create a sample project

If you are an android developer, you know well one application can have many activities. One possible solution is we will compare the latest version from server. But It’s not an optimized solution. So my idea is we should write a single class code that responsible for manage force upgrades. How will we do that let see?

For doing that I’m going to use firebase for getting latest version. You can check with Rest APIs as well. Let’s create a sample project with some default class.

2. Create an application class

Create a subclass of application class named is ForceUpdateApp. Basically this is an app name, you can choose based on your choice. This class we need to add ProcessLifecycleOwner that simply means you have to implements LifecycleObserver. just like below.

package com.androidforceupdate;

import android.app.Application;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.ProcessLifecycleOwner;

public class ForceUpdateApp extends Application implements LifecycleObserver {

  private ForceUpgradeManager forceUpgradeManager;

  private static ForceUpdateApp application;

  @Override public void onCreate() {
    super.onCreate();
    application = this;
    initForceUpgradeManager();
    ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
  }

  public void initForceUpgradeManager() {
    if (forceUpgradeManager == null) {
      forceUpgradeManager = new ForceUpgradeManager(application);
    }
  }
}

3. Create a class named ForceUpgradeManager

ForceUpgradeManager is responsible to manage all force upgrade jobs. Now I’m breaking all job into smaller ones. These are followings

  • Observe the lifecycle of activities.
  • Check force update is needed or not.
  • Compare current version to server version
  • Show Alert Dialog
  • Redirect to play store
3.1 Observe the lifecycle of Activities

Observe the lifecycle of activity in a single place. so you able to show force update dialog any activity inside the app.

public class ForceUpgradeManager implements LifecycleObserver {
  private static final String TAG = "ForceUpgradeManager";

  private final Context context;

  @Nullable
  private WeakReference<Activity> activityWeakReference;

  public ForceUpgradeManager(ForceUpdateApp application) {
    this.context = application.getApplicationContext();
    application.registerActivityLifecycleCallbacks(callbacks);
    ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  public void appStarted() {
    checkForceUpdateNeeded();
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  public void appStopped() {
    if (activityWeakReference != null) {
      activityWeakReference.clear();
    }
  }

  @Nullable
  private Activity getCurrentActivity() {
    return activityWeakReference != null && activityWeakReference.get() != null
        ? activityWeakReference.get() : null;
  }

  private final Application.ActivityLifecycleCallbacks callbacks =
      new Application.ActivityLifecycleCallbacks() {

        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
        }

        @Override public void onActivityStarted(@NonNull Activity activity) {
          ForceUpgradeManager.this.activityWeakReference = new WeakReference<>(activity);
        }

        @Override public void onActivityResumed(@NonNull Activity activity) {

        }

        @Override public void onActivityPaused(@NonNull Activity activity) {

        }

        @Override public void onActivityStopped(@NonNull Activity activity) {

        }

        @Override public void onActivitySaveInstanceState(@NonNull Activity activity,
            @NonNull Bundle bundle) {

        }

        @Override public void onActivityDestroyed(@NonNull Activity activity) {

        }
      };
}
3.2 Check force update is needed or not

For checking latest version we can use firebase or RestAPI. So we can fetch latest version and make a decision whether force upgrade is needed or not. In this tutorial, I’m using Firebase only.

 private void checkForceUpdateNeeded() {
    final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.getInstance();
   // long cacheExpiration = 12 * 60 * 60; // fetch every 12 hours
    // set in-app defaults
    Map<String, Object> remoteConfigDefaults = new HashMap();
    remoteConfigDefaults.put(KEY_UPDATE_REQUIRED, false);
    remoteConfigDefaults.put(KEY_CURRENT_VERSION, "1.0.0");

    remoteConfig.setDefaults(remoteConfigDefaults);
    remoteConfig.fetch(0)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
          @Override
          public void onComplete(@NonNull Task<Void> task) {
            if (task.isSuccessful()) {
              Log.d(TAG, "remote config is fetched.");
              remoteConfig.activateFetched();
            }
          }
        });
  }
3.3 Compare current version to server version

if server version is higher than lower version than show upgrade alert dialog

if (remoteConfig.getBoolean(KEY_UPDATE_REQUIRED)) {
              String currentVersion = remoteConfig.getString(KEY_CURRENT_VERSION);
              String appVersion = getAppVersion(context);
              if (!TextUtils.equals(currentVersion, appVersion)) {
                onUpdateNeeded();
              }
 }
private String getAppVersion(Context context) {
    String result = "";
    try {
      result = context.getPackageManager()
          .getPackageInfo(context.getPackageName(), 0)
          .versionName;
      result = result.replaceAll("[a-zA-Z]|-", "");
    } catch (PackageManager.NameNotFoundException e) {
      Log.e(TAG, e.getMessage());
    }

    return result;
  }
3.4 Show Alert Dialog
 /**
   * Gets update alert.
   */
  private void onUpdateNeeded() {
    Activity temp = getCurrentActivity();
    if (temp != null) {
      AlertDialog dialog = new AlertDialog.Builder(temp)
          .setTitle("New version available")
          .setMessage("Please update app for seamless experience.")
          .setPositiveButton("Continue",
              new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                  redirectStore();
                }
              }).create();
      dialog.show();
    }
  }
3.5 Redirect to play store
  /**
   * Redirect to play store
   */
  private void redirectStore() {
    Uri updateUrl = Uri.parse("market://details?id=" + context.getPackageName());
    final Intent intent = new Intent(Intent.ACTION_VIEW, updateUrl);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);
  }
4. The complete source code of ForceUpdateApp

The complete source code of ForceUpgradeManager class.

package com.androidforceupdate;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

public class ForceUpgradeManager implements LifecycleObserver {

  private static final String KEY_UPDATE_REQUIRED = "force_update_required";
  private static final String KEY_CURRENT_VERSION = "force_update_current_version";

  private static final String TAG = "ForceUpgradeManager";

  private final Context context;

  @Nullable
  private WeakReference<Activity> activityWeakReference;

  public ForceUpgradeManager(ForceUpdateApp application) {
    this.context = application.getApplicationContext();
    application.registerActivityLifecycleCallbacks(callbacks);
    ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  public void appStarted() {
    checkForceUpdateNeeded();
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  public void appStopped() {
    if (activityWeakReference != null) {
      activityWeakReference.clear();
    }
  }

  @Nullable
  private Activity getCurrentActivity() {
    return activityWeakReference != null && activityWeakReference.get() != null
        ? activityWeakReference.get() : null;
  }

  private final Application.ActivityLifecycleCallbacks callbacks =
      new Application.ActivityLifecycleCallbacks() {

        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
        }

        @Override public void onActivityStarted(@NonNull Activity activity) {
          ForceUpgradeManager.this.activityWeakReference = new WeakReference<>(activity);
        }

        @Override public void onActivityResumed(@NonNull Activity activity) {

        }

        @Override public void onActivityPaused(@NonNull Activity activity) {

        }

        @Override public void onActivityStopped(@NonNull Activity activity) {

        }

        @Override public void onActivitySaveInstanceState(@NonNull Activity activity,
            @NonNull Bundle bundle) {

        }

        @Override public void onActivityDestroyed(@NonNull Activity activity) {

        }
      };

  /**
   * Gets update alert.
   */
  private void onUpdateNeeded() {
    Activity temp = getCurrentActivity();
    if (temp != null) {
      AlertDialog dialog = new AlertDialog.Builder(temp)
          .setTitle("New version available")
          .setMessage("Please update app for seamless experience.")
          .setPositiveButton("Continue",
              new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                  redirectStore();
                }
              }).create();
      dialog.show();
    }
  }

  /**
   * Redirect to play store
   */
  private void redirectStore() {
    Uri updateUrl = Uri.parse("market://details?id=" + context.getPackageName());
    final Intent intent = new Intent(Intent.ACTION_VIEW, updateUrl);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);
  }

  private void checkForceUpdateNeeded() {
    final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.getInstance();
    // long cacheExpiration = 12 * 60 * 60; // fetch every 12 hours
    // set in-app defaults
    Map<String, Object> remoteConfigDefaults = new HashMap();
    remoteConfigDefaults.put(KEY_UPDATE_REQUIRED, false);
    remoteConfigDefaults.put(KEY_CURRENT_VERSION, "1.0.0");

    remoteConfig.setDefaults(remoteConfigDefaults);
    remoteConfig.fetch(0)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
          @Override
          public void onComplete(@NonNull Task<Void> task) {
            if (task.isSuccessful()) {
              Log.d(TAG, "remote config is fetched.");
              remoteConfig.activateFetched();
            }
            if (remoteConfig.getBoolean(KEY_UPDATE_REQUIRED)) {
              String currentVersion = remoteConfig.getString(KEY_CURRENT_VERSION);
              String appVersion = getAppVersion(context);
              if (!TextUtils.equals(currentVersion, appVersion)) {
                onUpdateNeeded();
              }
            }
          }
        });
  }

  private String getAppVersion(Context context) {
    String result = "";
    try {
      result = context.getPackageManager()
          .getPackageInfo(context.getPackageName(), 0)
          .versionName;
      result = result.replaceAll("[a-zA-Z]|-", "");
    } catch (PackageManager.NameNotFoundException e) {
      Log.e(TAG, e.getMessage());
    }

    return result;
  }
}

Conclusion

In this android tutorial, We have learned how to perform upgrade the force upgrade in Android App. I hope it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.

If you have any queries please put your comment below. If you looking to integrate the user force upgrade in your android project, Feel free to content us

https://paypal.me/
droidwave?locale.x=en_GB