Forzar la actualización de una aplicación de Android cuando hay una nueva versión disponible

100

Tengo una aplicación en Google Play Store. Cuando hay una versión de actualización disponible, la versión anterior quedará inutilizable; es decir, si los usuarios no actualizan la aplicación, no ingresan en la aplicación. ¿Cómo puedo obligar a los usuarios a actualizar la aplicación cuando hay una nueva versión disponible?

ashraful
fuente
1
Este proyecto de GitHub de código abierto (MAHAndroidUpdater) proporciona completamente esta funcionalidad. Pruébalo, muy sencillo. github.com/hummatli/MAHAndroidUpdater
Sattar Hummatli

Respuestas:

99

Estoy de acuerdo con el punto de Scott Helme en otra respuesta aquí. Pero en algunas situaciones extremas (problemas de seguridad, cambios importantes en la API ...) en las que es absolutamente necesario que los usuarios se actualicen para continuar usando la aplicación, puede proporcionar una API de control de versiones simple. La API se vería así:

versionCheck API:

Solicitar parámetros:

  • int appVersion

Respuesta

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

Cuando se inicie su aplicación, puede llamar a esta API que pasa en la versión actual de la aplicación y verificar la respuesta de la llamada a la API de control de versiones.

Si forceUpgradees así true, muestre un cuadro de diálogo emergente con opciones para permitir que el usuario salga de la aplicación o vaya a Google Play Store para actualizar la aplicación.

Else if recommendUpgradees true, mostrar el cuadro de diálogo emergente con opciones para actualizar o continuar usando la aplicación.

Incluso con esta capacidad de actualización forzada en su lugar, debe continuar admitiendo versiones anteriores, a menos que sea absolutamente necesario.

Miguel
fuente
¿Mostrarías una ventana emergente cada vez que se inicia la aplicación y recomendarías que la actualización sea verdadera? (desde el punto de vista de UX) O simplemente muestre la ventana emergente una vez y no vuelva a mostrar si el usuario se niega a actualizar.
Aneesh
8
Para la actualización recomendada, creo que no debería volver a aparecer si el usuario se negó. También puede mostrarlo "una vez cada n veces que el usuario abre la aplicación". Puede decidir el valor n usted mismo e implementarlo.
Michael
3
En mi opinión, una mejor solución es pasar la versión de la aplicación de forma sistemática en el encabezado de todas las llamadas a la API, y luego hacer que la API devuelva un código de estado específico si detecta que la versión es obsoleta. y luego manejarlo dentro de la aplicación. esto es mejor que tener que llamar a otra API dedicada para esta verificación, y tener que averiguar exactamente cuándo / dónde debe realizarse esta llamada API dentro de la aplicación / servicio.
Raphael C
@RaphaelC Esto realmente depende de la implementación del lado del servidor. Tampoco es perfecto agregar un filtro que verifique la versión en todas las API en algunas situaciones.
Septiembre GH
4
@SepGH las cosas han cambiado desde entonces, y Android ahora ofrece una API que puedes usar para forzar al usuario a actualizar y bloquearlo para que no continúe usando la aplicación si no actualiza a una versión mínima: developer.android.com/guide/ paquete de aplicaciones / actualizaciones en la aplicación
Raphael C
55

intente esto: primero debe realizar una llamada de solicitud al enlace de Play Store, obtener la versión actual desde allí y luego compararla con su versión actual.

String currentVersion, latestVersion;
Dialog dialog;
private void getCurrentVersion(){
 PackageManager pm = this.getPackageManager();
        PackageInfo pInfo = null;

        try {
            pInfo =  pm.getPackageInfo(this.getPackageName(),0);

        } catch (PackageManager.NameNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        currentVersion = pInfo.versionName;

   new GetLatestVersion().execute();

}

private class GetLatestVersion extends AsyncTask<String, String, JSONObject> {

        private ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected JSONObject doInBackground(String... params) {
            try {
//It retrieves the latest version by scraping the content of current version from play store at runtime
                Document doc = Jsoup.connect(urlOfAppFromPlayStore).get();
                latestVersion = doc.getElementsByClass("htlgb").get(6).text();

            }catch (Exception e){
                e.printStackTrace();

            }

            return new JSONObject();
        }

        @Override
        protected void onPostExecute(JSONObject jsonObject) {
            if(latestVersion!=null) {
                if (!currentVersion.equalsIgnoreCase(latestVersion)){
                   if(!isFinishing()){ //This would help to prevent Error : BinderProxy@45d459c0 is not valid; is your activity running? error
                    showUpdateDialog();
                    }
                }
            }
            else
                background.start();
            super.onPostExecute(jsonObject);
        }
    }

private void showUpdateDialog(){
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("A New Update is Available");
        builder.setPositiveButton("Update", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse
                        ("market://details?id=yourAppPackageName")));
                dialog.dismiss();
            }
        });

        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                background.start();
            }
        });

        builder.setCancelable(false);
        dialog = builder.show();
    }
AshuKingSharma
fuente
1
Supongo que esto requeriría el uso para agregar la biblioteca externa JSoup.
Abraham Philip
1
Sí, pero eso sería para obtener la página div html. Quería decir que es posible que no necesite usar ninguna biblioteca de terceros para lograr esta funcionalidad, si puede raspar ese elemento html sin JSoup, aún funcionaría
AshuKingSharma
1
¿Qué pasa si cambian el valor de itemprop?
asok Buzz
1
Si cambian el valor de itemprop, también afectaría a mis aplicaciones, editaría mi respuesta para respaldar eso de inmediato, así que no se preocupe hasta entonces :)
AshuKingSharma
Buen conjunto Cancelable (falso)
Kai Wang
46

No debe dejar de admitir una versión anterior tan pronto como salga una nueva. Esto resultará en una experiencia de usuario terrible. No conozco ningún proveedor de software que haga esto, por una buena razón.

¿Qué sucede si el usuario no puede actualizar o no quiere hacerlo en ese momento? Simplemente no pueden usar tu aplicación, lo cual es malo.

Google no ofrece ninguna opción para el seguimiento de versiones como ese, por lo que tendría que lanzar la suya propia. Un simple servicio web para devolver la versión actual en vivo que su aplicación puede verificar sería suficiente. Luego, puede actualizar la versión y la aplicación sabrá que está desactualizada. Solo recomendaría usar esto para que sus usuarios sepan que hay una actualización más rápidamente que dependiendo de Google Play. Realmente no debería usarse para evitar que la aplicación funcione, solo para pedirle al usuario que actualice.

Scott Helme
fuente
2
@ashraful si esta o cualquier respuesta ha resuelto su pregunta, considere aceptarla haciendo clic en la marca de verificación. Esto le indica a la comunidad en general que ha encontrado una solución y le da cierta reputación tanto al respondedor como a usted mismo. No hay ninguna obligación de hacer esto.
Sufian
La respuesta depende de la cantidad de proveedores de software que CONOZCA que existen. ¿Puedes cuantificar eso?
Lou Morda
1
¿Es posible obtener la versión actual de la aplicación en la tienda de aplicaciones o en la tienda de juegos? o si necesito mantener la última versión de la aplicación en mi servidor? Porque en este momento tengo una llamada de servicio en mi servidor para devolver la última versión de la aplicación, pero la dificultad es cada vez que necesito actualizar el servidor mientras se publica la aplicación. Por lo tanto, ¿es posible obtener el número de versión actual de las tiendas respectivas?
Subha
2
Supercell solo admite la última versión de sus juegos. Después de que hayan enviado una nueva versión a Google Play, cualquier cliente antiguo que intente conectarse recibirá una respuesta de "necesidad de actualizar" del servidor y verá que la conexión se cierra. Hacen esto varias veces al año. Así que, a menos que no quieras contar una "empresa de juegos" como "proveedor de software", ahora conoces a uno :) Teniendo en cuenta que todavía están ganando un par de millones de dólares cada día, aparentemente esta terrible experiencia de usuario no es un obstáculo. .
Arjan
@Subha Sí, eso es posible. Pero no hay una API oficial para ello, por lo que necesitaría raspar las páginas web. Lo que también significa que puede romperse si cambia la página web. Lo hice en una aplicación de terceros que escribí y publiqué el código bastante simple como respuesta aquí . Actualmente, el código funcionará tanto para las páginas de Play como para las de iTunes. Sin embargo, en un entorno de producción, puede ser mejor buscar una solución que actualice automáticamente la última versión de la aplicación en el servidor, en lugar de tener que depender del formato de las páginas en Google o Apple.
Arjan
27

Solución del equipo de Google

A partir de Android 5.0, eso se puede lograr fácilmente a través del nuevo mecanismo de actualizaciones de Google Play In App. Los requisitos son tener la biblioteca Play Core de la versión 1.5.0+ y usar la distribución de paquetes de aplicaciones en lugar de apks.

La biblioteca le ofrece 2 formas diferentes de notificar a los usuarios sobre la actualización:

  1. Flexible, cuando los usuarios pueden seguir usando la aplicación mientras se actualiza en segundo plano.

  2. Inmediato: pantalla de bloqueo que no permite que un usuario ingrese a la aplicación hasta que la actualice.

Hay siguientes pasos para implementarlo:

  1. Consultar disponibilidad de actualizaciones
  2. Iniciar una actualización
  3. Reciba una devolución de llamada para conocer el estado de la actualización
  4. Maneja la actualización

Todas las implementaciones de estos pasos se describen en detalle en el sitio oficial: https://developer.android.com/guide/app-bundle/in-app-updates

Gaket
fuente
16

Las respuestas de Scott y Michael son correctas. Aloje un servicio que proporcione un número de versión mínimo que admita y compárelo con la versión instalada. Con suerte, nunca debería necesitar usar esto, pero es un salvavidas si alguna versión está disponible, debe eliminarla debido a algún defecto grave.

Solo quería agregar el código para saber qué hacer a continuación. A continuación, le mostramos cómo inicia Google Play Intent y lo lleva a su nueva versión en la tienda después de indicarle al usuario que debe actualizar.

public class UpgradeActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_upgrade);
        final String appName = "com.appname";
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id="+appName)));

            }
        });
    }
}

Debería reconsiderar su diseño si tiene que forzar actualizaciones en cada versión.

bsautner
fuente
11

Google introdujo la biblioteca de actualizaciones en la aplicación, ( https://developer.android.com/guide/app-bundle/in-app-updates ) funciona en Lollipop + y le brinda la posibilidad de solicitar al usuario una actualización con un buen diálogo (FLEXIBLE) o con mensaje obligatorio en pantalla completa (INMEDIATO).

Necesita implementar este último. Así es como se verá: ingrese la descripción de la imagen aquí

Cubrí todo el código en esta respuesta: https://stackoverflow.com/a/56808529/5502121

Kirill Karmazin
fuente
1
¡Esta es la mejor respuesta!
fvaldivia
Esta función en realidad depende de que el caché de Play esté actualizado cuando el usuario inicia su aplicación, es decir, si el número de versión de su aplicación en el caché no es el mismo que el número de versión de su última implementación en Playstore, entonces no le preguntará al usuario.
kiran01bm
6

Recomiendo encarecidamente consultar la funcionalidad de Remote Config de Firebase para esto.

Lo implementé usando un parámetro - app_version_enabled - con una condición "Versiones de Android deshabilitadas" que se ve así:

applies if App ID == com.example.myapp and App version regular expression ^(5.6.1|5.4.2) 

El parámetro predeterminado es "verdadero", pero las versiones de Android deshabilitadas tienen el valor falso. En mi expresión regular para versiones de Android deshabilitadas, puede agregar más versiones deshabilitadas simplemente con otra |{version name}dentro de esos paréntesis.

Luego, solo verifico si la configuración dice que la versión está habilitada o no; tengo una actividad que lanzo que obliga al usuario a actualizar. Verifico los únicos dos lugares desde los que se puede iniciar la aplicación externamente (mi actividad de iniciador predeterminada y una actividad de manejo de intenciones). Dado que Remote Config funciona en caché, no capturará de inmediato las versiones "inhabilitadas" de la aplicación si no ha pasado el tiempo necesario para que se invalide la caché, pero eso es como máximo 12 horas si va por su valor de caducidad de caché recomendado.

Chantell Osejo
fuente
Esta es una muy buena opción. Al especificar un subconjunto de versiones "deshabilitadas", puede protegerse rápidamente en caso de que una aplicación tenga problemas de seguridad o problemas importantes de rendimiento. Le permite seguir admitiendo todas las versiones, pero prohibir una versión específica cuando surja la necesidad.
Terry
6

Google proporciona oficialmente una API de Android para esto.

Actualmente, la API se está probando con un puñado de socios y pronto estará disponible para todos los desarrolladores.

La API de actualización ya está disponible: https://developer.android.com/guide/app-bundle/in-app-updates

Chulo
fuente
2
Ver también: android-developers.googleblog.com/2018/11/…
albert c braun
1
¿Está disponible esta API ahora?
Yayayaya
Lo busqué en Google y encontré este developer.android.com/guide/app-bundle/in-app-updates
Chulo
Esta función en realidad depende de que el caché de Play esté actualizado cuando el usuario inicia su aplicación, es decir, si el número de versión de su aplicación en el caché no es el mismo que el número de versión de su última implementación en Playstore, entonces no le preguntará al usuario.
kiran01bm
3

Verifique el código de versión de local y play store apk

try {
        versionChecker VersionChecker = new versionChecker();
        String versionUpdated = VersionChecker.execute().get().toString();
        Log.i("version code is", versionUpdated);


        PackageInfo packageInfo = null;
        try {
            packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        int version_code = packageInfo.versionCode;
        String version_name = packageInfo.versionName;
        Log.i("updated version code", String.valueOf(version_code) + "  " + version_name);
        if (version_name != versionUpdated) {
            String packageName = getApplicationContext().getPackageName();//
            UpdateMeeDialog updateMeeDialog = new UpdateMeeDialog();
            updateMeeDialog.showDialogAddRoute(MainActivity.this, packageName);
            Toast.makeText(getApplicationContext(), "please updated", Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        e.getStackTrace();
    }

implementar la clase para la verificación de la versión

class versionChecker extends AsyncTask<String, String, String> {
String newVersion;

@Override
protected String doInBackground(String... params) {

    try {
        newVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=+YOR_PACKAGE_NAME+&hl=en")
                .timeout(30000)
                .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                .referrer("http://www.google.com")
                .get()
                .select("div[itemprop=softwareVersion]")
                .first()
                .ownText();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return newVersion;
}
}

cuadro de diálogo para actualizar

public class UpdateMeeDialog {

ActivityManager am;
TextView rootName;
Context context;
Dialog dialog;
String key1,schoolId;
public void showDialogAddRoute(Activity activity, final String packageName){
    context=activity;
    dialog = new Dialog(context);

    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setCancelable(false);
    dialog.setContentView(R.layout.dialog_update);
    am = (ActivityManager)activity.getSystemService(Context.ACTIVITY_SERVICE);

    Button cancelDialogue=(Button)dialog.findViewById(R.id.buttonUpdate);
    Log.i("package name",packageName);
    cancelDialogue.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent=new Intent(Intent.ACTION_VIEW);                
    intent.setData(Uri.parse("https://play.google.com/store/apps/details?
    id="+packageName+"&hl=en"));
            context.startActivity(intent);
        }
    });
    dialog.show();
}
}

diseño de diálogo

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d4e9f2">


<TextView
    android:layout_width="match_parent"
    android:layout_height="40dp"

    android:text="Please Update First..!!"
    android:textSize="20dp"
    android:textColor="#46a5df"
    android:textAlignment="center"
    android:layout_marginTop="50dp"
    android:id="@+id/textMessage"
    />
<LinearLayout
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:weightSum="1"
    android:layout_marginTop="50dp"
    android:layout_below="@+id/textMessage"
    android:layout_height="50dp">

    <Button
        android:id="@+id/buttonUpdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Update"
        android:background="#67C6F1"
        android:textAlignment="center" />
</LinearLayout>

Mahesh Pandit
fuente
2

Es mejor definir nuestro propio proceso de actualización.

  1. Cree un servicio web que proporcione la última versión de la aplicación (ios, android) desde nuestro servidor.
  2. O Cualquier servicio web que utilizó en la aplicación (por ejemplo, Inicio de sesión) devolverá la última versión de la aplicación desde el servidor.
  3. Una vez que la aplicación obtendrá la versión # 1 o 2. La aplicación la comprobará con la versión de la aplicación local / actual. si hay diferencia, podemos mostrar la alerta de la siguiente manera,

Android e iOS: si la última versión de la aplicación está disponible, se mostrará una alerta como "Última versión disponible con más funciones. Para actualizar, haga clic en el botón de actualización" (Alerta con el botón "Upgarde" y "No. Gracias"). Luego, la aplicación redirigirá a playstore / Appstore y abrirá la última versión.

 --- we can do upgrade compulsory or optionally.

Antes del proceso de actualización, asegúrese de haber manejado correctamente el proceso de migración de la base de datos si hay algún cambio en el esquema de la base de datos.

Sandeep
fuente
1

Para obligar al usuario de la aplicación a actualizar si hay una actualización disponible en el mercado, primero debe verificar la versión de la aplicación en el mercado y compararla con la versión de la aplicación en el dispositivo. Si son diferentes, puede haber una actualización disponible. En esta publicación, escribí el código para obtener la versión actual del mercado y la versión actual en el dispositivo y las comparé. También mostré cómo mostrar el cuadro de diálogo de actualización y redirigir al usuario a la página de actualización. Visite este enlace: https://stackoverflow.com/a/33925032/5475941 Solo asegúrese de que en el cuadro de diálogo solo muestre el botón de actualización de usuario y no le muestre el botón de cancelar. En este caso, se verá obligado a actualizar antes de poder usar la aplicación.

Mohammad
fuente
1

Lo que definitivamente debería mencionarse aquí es la API de actualizaciones en la aplicación que se lanzará próximamente .

Tendrás dos opciones con esta API; la primera es una experiencia de pantalla completa para actualizaciones críticas cuando espera que el usuario espere a que la actualización se aplique inmediatamente. La segunda opción es una actualización flexible, lo que significa que el usuario puede seguir usando la aplicación mientras se descarga la actualización. Puede personalizar completamente el flujo de actualización para que se sienta como parte de su aplicación.

Marko Gajić
fuente
1

Es una buena idea usar la configuración remota para la versión de la aplicación y siempre verificar la actividad de inicio si la versión actual de la aplicación es la misma que la versión remota o no si no se fuerza la actualización desde la tienda de aplicaciones.

Codificación feliz de lógica simple.

https://firebase.google.com/docs/remote-config/android

Neeraj Singh
fuente
1

Puede utilizar las actualizaciones de la aplicación Play Core Library para abordar esto. Puede verificar la disponibilidad de actualizaciones e instalarlas si están disponibles sin problemas.

Las actualizaciones en la aplicación no son compatibles con las aplicaciones que usan archivos de expansión APK (archivos .obb). Puede optar por descargas flexibles o actualizaciones inmediatas que Google Play se encarga de descargar e instalar por usted.

dependencies {
    implementation 'com.google.android.play:core:1.5.0'
    ...
}

Consulte esta respuesta https://stackoverflow.com/a/58212818/7579041

Amin Pinjari
fuente
0

puede hacer esto haciendo una coincidencia entre un número de versión que se mantiene en la aplicación en una variable y, de manera similar, la versión actual de la aplicación se mantiene en el lado del servidor y cada vez que el usuario abre la aplicación, se debe enviar la primera solicitud para verificar si se encuentra la coincidencia no haga nada, simplemente deje que el usuario use su aplicación; de lo contrario, envíe un intento a Google Play Store o abra una ventana de vista web a su aplicación (window.open (" https://play.google.com/store/apps/details?id= package_name ", '_system', 'location = yes');) y allí automáticamente tendrán el botón que solicita la actualización, eso es lo que hace Google Play Store por ti si no tienes las actualizaciones automáticas activadas.

shiva2492
fuente
0

Puede notificar a sus usuarios que hay una nueva versión de la aplicación actual disponible para actualizar. Además, si esta condición es cierta, puede bloquear el inicio de sesión en la aplicación.

Vea si esto le proporciona la solución.

Vansuita Jr.
fuente
0

Bueno, podría haber muchas soluciones a este problema, como extraer el código de la versión de la página de la aplicación (página de la aplicación Google Play), etc.

Pero les mostraré la solución definitiva que no costará ni un centavo y funcionará como por arte de magia.

  1. Simplemente guarde el código de la versión más reciente de su aplicación en el
    panel de Firebase Remote Config
  2. Obtener ese valor de código de versión cada vez que se abre la aplicación
  3. Compárelo con el código de la versión actual de la aplicación, que puede obtener con el siguiente código

    private int getCurrentVersionCode() {
    try {
        return getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }
    return -1;

    }

Si el código de la versión obtenida es mayor que la versión actual, muestre un AlertDialog solicitando actualizar la aplicación. De lo contrario, la aplicación ya está actualizada.

Por lo tanto, cada vez que implementa la nueva versión, debe colocar ese nuevo código de versión en el panel de configuración de Firebase Remote

Puedes leer el tutorial completo sobre cómo obligar a los usuarios a actualizar la aplicación usando Firebase Remote Config

Waqas Younis
fuente
0

Google lanzó actualizaciones en la aplicación para la biblioteca de Play Core.

Implementé una biblioteca ligera para implementar fácilmente actualizaciones en la aplicación. Puede encontrar en el siguiente enlace un ejemplo sobre cómo obligar al usuario a realizar la actualización.

https://github.com/dnKaratzas/android-inapp-update#force-updates

dKaratzas
fuente