Forza l'aggiornamento di un'app Android quando è disponibile una nuova versione


100

Ho un'app in Google Play Store. Quando è disponibile una versione di aggiornamento, la versione precedente diventerà inutilizzabile, ovvero, se gli utenti non aggiornano l'app, non accedono all'app. Come posso obbligare gli utenti ad aggiornare l'app quando una nuova versione diventa disponibile?


1
Questo progetto GitHub open source (MAHAndroidUpdater) fornisce completamente questa funzionalità. Provalo, molto semplice. github.com/hummatli/MAHAndroidUpdater
Sattar Hummatli

Risposte:


99

Sono d'accordo con il punto di Scott Helme in un'altra risposta qui. Ma in alcune situazioni estreme (problemi di sicurezza, modifiche alle API ...) in cui è assolutamente necessario che gli utenti si aggiornino per continuare a utilizzare l'app, è possibile fornire una semplice API di controllo delle versioni. L'API sarebbe simile a questa:

API versionCheck:

Parametri della richiesta:

  • int appVersion

Risposta

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

Quando la tua app si avvia, puoi chiamare questa API che passa nella versione corrente dell'app e controllare la risposta della chiamata all'API di controllo delle versioni.

In forceUpgradetal caso true, mostra una finestra di dialogo popup con le opzioni per consentire all'utente di uscire dall'app o andare su Google Play Store per aggiornare l'app.

Altrimenti, se recommendUpgradeè true, visualizzare la finestra di pop-up con la possibilità di aggiornare o continuare a utilizzare l'applicazione.

Anche con questa capacità di aggiornamento forzato in atto, dovresti continuare a supportare le versioni precedenti, a meno che non sia assolutamente necessario.


Mostreresti un popup ogni volta che l'app si avvia e consiglieresti che l'aggiornamento sia vero? (dal punto di vista dell'esperienza utente) Oppure mostra semplicemente il popup una volta e non mostrarlo più se l'utente rifiuta di eseguire l'aggiornamento.
Aneesh

8
Per l'aggiornamento consigliato, penso che non dovresti mostrare di nuovo se l'utente ha rifiutato. Puoi anche mostrarlo "una volta ogni n volte che l'utente ha aperto l'app". Potresti decidere tu stesso il valore n e implementarlo.
Michael,

3
una soluzione migliore imo consiste nel passare sistematicamente la versione dell'app nell'intestazione di tutte le chiamate API, quindi fare in modo che l'API restituisca un codice di stato specifico se rileva che la versione è obsoleta. e quindi gestiscilo all'interno dell'app. questo è meglio che dover chiamare un'altra API dedicata per questo controllo e dover capire esattamente quando / dove questa chiamata API dovrebbe essere eseguita all'interno dell'app / servizio.
Raphael C

@RaphaelC Questo dipende davvero dall'implementazione lato server. Inoltre, non è perfetto aggiungere un filtro che controlli la versione su tutte le API in alcune situazioni.
GH settembre

4
@SepGH le cose sono cambiate da allora e Android ora offre un'API che puoi utilizzare per costringere l'utente a eseguire l'aggiornamento e impedirgli di continuare a utilizzare l'app se non esegue l'aggiornamento a una versione minima: developer.android.com/guide/ app-bundle / in-app-updates
Raphael C

55

prova questo: per prima cosa devi effettuare una chiamata di richiesta al link del playstore, recuperare la versione corrente da lì e quindi confrontarla con la tua versione corrente.

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();
    }

1
Immagino che questo richiederebbe l'uso per aggiungere la libreria esterna JSoup?
Abraham Philip il

1
Sì, ma sarebbe per ottenere la pagina div html. Volevo dire che potresti non aver bisogno di utilizzare alcuna libreria di terze parti per ottenere questa funzionalità, se puoi raschiare quell'elemento html senza JSoup, funzionerebbe comunque
AshuKingSharma

1
cosa succede se cambiano il valore di itemprop ??
asok Buzz

1
Se cambiano il valore itemprop, influirà anche sulle mie app, modificherei la mia risposta per supportarlo immediatamente, quindi non preoccuparti fino ad allora :)
AshuKingSharma

Bella serie Annullabile (falso)
Kai Wang

46

Non dovresti smettere di supportare una versione precedente non appena ne esce una nuova. Ciò si tradurrà in una terribile esperienza utente. Non conosco nessun fornitore di software esistente che lo faccia, per una buona ragione.

Cosa succede se l'utente non può aggiornare o non vuole farlo in quel momento? Semplicemente non possono usare la tua app, il che è male.

Google non fornisce alcuna opzione per il monitoraggio della versione in questo modo, quindi dovresti eseguire il tuo. Sarebbe sufficiente un semplice servizio web per restituire la versione live corrente che la tua app può controllare. È quindi possibile aggiornare la versione e l'app saprà che è obsoleta. Ti consiglio di utilizzarlo solo per far sapere ai tuoi utenti che è disponibile un aggiornamento più rapidamente rispetto a quanto dipende da Google Play. Non dovrebbe essere utilizzato per impedire il funzionamento dell'app, ma solo per richiedere all'utente di eseguire l'aggiornamento.


2
@ashraful se questa o altre risposte hanno risolto la tua domanda, considera di accettarla facendo clic sul segno di spunta. Questo indica alla comunità più ampia che hai trovato una soluzione e dà una certa reputazione sia a chi risponde che a te stesso. Non vi è alcun obbligo in tal senso.
Sufian

La risposta è soggettiva al numero di fornitori di software CHE CONOSCI. Puoi quantificarlo?
Lou Morda

1
È possibile ottenere la versione attuale dell'app da App Store o Play Store? o se devo mantenere l'ultima versione dell'app nel mio server? Perché in questo momento ho una chiamata di servizio nel mio server per restituire l'ultima versione dell'app, ma ogni volta è necessario aggiornare il server durante la pubblicazione dell'app. Quindi è possibile ottenere il numero di versione corrente dai rispettivi negozi?
subha

2
Supercell supporta solo l'ultima versione dei loro giochi. Dopo aver inviato una nuova versione a Google Play, qualsiasi client meno recente che tenta di connettersi riceverà una risposta "necessità di aggiornamento" dal server e vedrà la connessione chiusa. Lo fanno più volte all'anno. Quindi, a meno che tu non voglia considerare una "società di giochi" come "fornitore di software", ora ne conosci uno :) Considerando che stanno ancora guadagnando un paio di milioni di dollari ogni giorno, a quanto pare questa terribile esperienza utente non è un fermo spettacolo .
Arjan

@ Subha Sì, è possibile. Ma non esiste un'API ufficiale, quindi dovresti raschiare le pagine web. Ciò significa anche che potrebbe interrompersi se la pagina web cambia. L'ho fatto in un'app di terze parti che ho scritto e pubblicato il codice piuttosto semplice come risposta qui . Attualmente, il codice funzionerà sia per le pagine Play che per iTunes. In un ambiente di produzione, tuttavia, potrebbe essere meglio cercare una soluzione che aggiorni automaticamente l'ultima versione dell'app sul server, invece di dover fare affidamento sul formato delle pagine di Google o Apple?
Arjan

27

Soluzione del team di Google

A partire da Android 5.0, ciò è facilmente realizzabile tramite il nuovo meccanismo di aggiornamento di Google Play In App. I requisiti sono disporre della libreria Play Core della versione 1.5.0+ e utilizzare gli App Bundle idstribution invece degli apk.

La libreria offre 2 diversi modi per notificare agli utenti l'aggiornamento:

  1. Flessibile, quando gli utenti possono continuare a utilizzare l'app mentre viene aggiornata in background.

  2. Immediato: schermata di blocco che non consente a un utente di accedere all'app finché non la aggiorna.

Ci sono i prossimi passaggi per implementarlo:

  1. Verifica la disponibilità degli aggiornamenti
  2. Avvia un aggiornamento
  3. Richiedi una richiamata per lo stato dell'aggiornamento
  4. Gestisci l'aggiornamento

Tutte le implementazioni di questi passaggi sono descritte in dettaglio sul sito ufficiale: https://developer.android.com/guide/app-bundle/in-app-updates


16

Le risposte di Scott e Michael sono corrette. Ospita un servizio che fornisce un numero di versione minimo supportato e confrontalo con la versione installata. Si spera che non dovresti mai aver bisogno di usarlo, ma è un salvavita se qualche versione è là fuori che devi assolutamente uccidere a causa di qualche grave difetto.

Volevo solo aggiungere il codice per cosa fare dopo. Ecco come avviare quindi Google Play Intent e portarli alla nuova versione nello store dopo aver chiesto all'utente che devono eseguire l'upgrade.

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)));

            }
        });
    }
}

Dovresti riconsiderare il tuo progetto se devi forzare gli aggiornamenti su ogni versione.


11

Google ha introdotto gli aggiornamenti in-app lib, ( https://developer.android.com/guide/app-bundle/in-app-updates ) funziona su Lollipop + e ti dà la possibilità di chiedere all'utente un aggiornamento con un simpatico dialogo (FLESSIBILE) o con messaggio a schermo intero obbligatorio (IMMEDIATO).

È necessario implementare quest'ultimo. Ecco come apparirà: inserisci qui la descrizione dell'immagine

Ho coperto tutto il codice in questa risposta: https://stackoverflow.com/a/56808529/5502121


1
Questa è la migliore risposta!
fvaldivia

Questa funzione in realtà si basa sul fatto che la cache di riproduzione sia aggiornata quando l'utente avvia la tua app, ad esempio se il numero di versione della tua app nella cache non è lo stesso del numero di versione della tua ultima distribuzione su Playstore, non lo chiederà all'utente.
kiran01bm

6

Consiglio vivamente di controllare la funzionalità Remote Config di Firebase per questo.

L'ho implementato utilizzando un parametro - app_version_enabled - con una condizione "Versioni Android disabilitate" che assomiglia a questa:

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

L'impostazione predefinita per il parametro è "true", ma le versioni Android disabilitate hanno un valore false. Nella mia regex per le versioni Android disabilitate, puoi aggiungere più versioni disabilitate semplicemente con un'altra |{version name}tra quelle parentesi.

Quindi controllo solo se la configurazione dice che la versione è abilitata o meno: ho un'attività che avvio che costringe l'utente a eseguire l'aggiornamento. Controllo gli unici due punti in cui è possibile avviare l'app dall'esterno (la mia attività di avvio predefinita e un'attività di gestione degli intenti). Poiché Remote Config funziona su base cache, non acquisirà immediatamente le versioni "disabilitate" dell'app se non è trascorso il tempo necessario per l'invalidazione della cache, ma è al massimo 12 ore se stai passando il valore di scadenza della cache consigliato.


Questa è un'ottima opzione. Specificando un sottoinsieme di versioni "disabilitate", puoi proteggerti rapidamente nel caso in cui un'app abbia problemi di sicurezza o problemi di prestazioni importanti. Ti consente di continuare a supportare tutte le versioni ma vietare versioni specifiche in caso di necessità.
Terry

6

Ufficialmente Google fornisce un'API Android per questo.

L'API è attualmente in fase di test con una manciata di partner e sarà presto disponibile per tutti gli sviluppatori.

L' API di aggiornamento è ora disponibile: https://developer.android.com/guide/app-bundle/in-app-updates



1
Questa API è ora disponibile?
Yayayaya

Ho cercato su Google e ho trovato questo developer.android.com/guide/app-bundle/in-app-updates
Chulo

Questa funzione in realtà si basa sul fatto che la cache di riproduzione sia aggiornata quando l'utente avvia la tua app, ad esempio se il numero di versione della tua app nella cache non è lo stesso del numero di versione della tua ultima distribuzione su Playstore, non lo chiederà all'utente.
kiran01bm

3

controlla il codice della versione dell'apk locale e del Play Store

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();
    }

implementare la classe per il controllo della versione

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;
}
}

scatola dialob per l'aggiornamento

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();
}
}

layout di dialogo

<?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>


2

È meglio definire il nostro processo per l'aggiornamento.

  1. Crea un servizio web che fornisce l'ultima versione per app (ios, android) dal nostro server.
  2. Oppure Qualsiasi servizio web che hai utilizzato nell'app (ad esempio Login) restituirà l'ultima versione dell'app dal server.
  3. Una volta che l'app otterrà la versione da # 1 o 2. L'app la verificherà in modo incrociato con l'appversion locale / cuurent. se c'è differenza, possiamo mostrare l'avviso come segue,

Android e iOS: se è disponibile l'ultima versione dell'app, verrà visualizzato un avviso come "Ultima versione disponibile con più funzionalità, per aggiornare fare clic sul pulsante di aggiornamento" (Avviso con il pulsante "Upgarde" e "No. Grazie".) Quindi l'app verrà reindirizzata a playstore / Appstore e aprirà l'ultima versione.

 --- we can do upgrade compulsory or optionally.

Prima del processo di aggiornamento, assicurarsi di aver gestito il corretto processo di migrazione del database in caso di modifiche allo schema del database.


1

Per forzare l'utente dell'app ad aggiornare se un aggiornamento è disponibile sul mercato, è necessario prima controllare la versione dell'app sul mercato e confrontarla con la versione dell'app sul dispositivo. Se sono diversi, potrebbe essere disponibile un aggiornamento. In questo post ho annotato il codice per ottenere la versione corrente del mercato e la versione corrente sul dispositivo e confrontarli insieme. Ho anche mostrato come mostrare la finestra di dialogo di aggiornamento e reindirizzare l'utente alla pagina di aggiornamento. Visita questo link: https://stackoverflow.com/a/33925032/5475941 Assicurati solo che nella finestra di dialogo mostri solo il pulsante di aggiornamento utente e non mostrargli il pulsante Annulla. In questo caso sarà costretto ad aggiornare, prima di poter utilizzare l'app.


1

Ciò che dovrebbe assolutamente essere menzionato qui è l' API degli aggiornamenti in-app di prossima uscita .

Avrai due opzioni con questa API; il primo è un'esperienza a schermo intero per gli aggiornamenti critici quando ci si aspetta che l'utente attenda l'applicazione immediata dell'aggiornamento. La seconda opzione è un aggiornamento flessibile, il che significa che l'utente può continuare a utilizzare l'app durante il download dell'aggiornamento. Puoi personalizzare completamente il flusso di aggiornamento in modo che sembri parte della tua app.



1

Puoi utilizzare gli aggiornamenti in-app della Play Core Library per risolvere questo problema. Puoi verificare la disponibilità degli aggiornamenti e installarli senza problemi se disponibili.

Gli aggiornamenti in-app non sono compatibili con le app che utilizzano file di espansione APK (file .obb). Puoi scegliere download flessibili o aggiornamenti immediati che Google Play si occupa di scaricare e installare l'aggiornamento per te.

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

Fai riferimento a questa risposta https://stackoverflow.com/a/58212818/7579041


0

puoi farlo facendo una corrispondenza tra un numero di versione che è mantenuto nell'app in una variabile e allo stesso modo la versione corrente dell'app viene mantenuta sul lato server e ogni volta che l'utente apre l'app la prima richiesta dovrebbe essere inviata per verificare che se la trova abbinamento non fare nulla semplicemente consentire all'utente di utilizzare la tua app altrimenti lancia un intento al Google Playstore o apri una finestra di visualizzazione web per la tua app (window.open (" https://play.google.com/store/apps/details?id= package_name ", '_system', 'location = yes');) e lì avranno automaticamente il pulsante che chiede l'aggiornamento che è ciò che Google Playstore fa per te se non hai aggiornamenti automatici.


0

Puoi avvisare i tuoi utenti che è disponibile una nuova versione dell'app corrente per l'aggiornamento. Inoltre, se questa condizione è vera, puoi bloccare l'accesso nell'app.

Verifica se questo ti fornisce la soluzione.


0

Bene, potrebbero esserci molte soluzioni a questo problema come lo scraping del codice della versione dalla pagina dell'app (pagina dell'app Google Play), ecc.

Ma ti mostrerò la soluzione definitiva che non costerà un centesimo e funzionerà come per magia.

  1. Salva semplicemente il codice della versione più recente della tua app sul
    pannello Firebase Remote Config
  2. Recupera il valore del codice della versione ogni volta che l'app viene aperta
  3. Confrontalo con il codice della versione corrente dell'app, che puoi ottenere dal codice seguente

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

    }

Se il codice della versione recuperato è maggiore della versione corrente, mostra un AlertDialog che chiede di aggiornare l'app. In caso contrario, l'app è già aggiornata.

Pertanto, ogni volta che si distribuisce la nuova versione, è necessario inserire il codice della nuova versione nel pannello di configurazione di Firebase Remote

Puoi leggere l'intero tutorial su come obbligare gli utenti ad aggiornare l'app utilizzando Firebase Remote Config


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.