Força a atualização de um aplicativo Android quando uma nova versão estiver disponível

100

Eu tenho um aplicativo na Google Play Store. Quando uma versão de atualização está disponível, a versão mais antiga se torna inutilizável - ou seja, se os usuários não atualizarem o aplicativo, eles não entrarão no aplicativo. Como posso forçar os usuários a atualizar o aplicativo quando uma nova versão estiver disponível?

Ashraful
fonte
1
Este projeto GitHub de código aberto (MAHAndroidUpdater) fornece completamente essa funcionalidade. Experimente, muito simples. github.com/hummatli/MAHAndroidUpdater
Sattar Hummatli

Respostas:

99

Concordo com o ponto de Scott Helme em outra resposta aqui. Mas em algumas situações extremas (problemas de segurança, alterações de quebra de API ...) onde você absolutamente precisa que os usuários atualizem para continuar usando o aplicativo, você pode fornecer uma API de controle de versão simples. A API ficaria assim:

API versionCheck:

Parâmetros de solicitação:

  • int appVersion

Resposta

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

Quando seu aplicativo é iniciado, você pode chamar essa API que passa na versão atual do aplicativo e verificar a resposta da chamada da API de controle de versão.

Se forceUpgradeestiver true, mostre uma caixa de diálogo pop-up com opções para permitir que o usuário saia do aplicativo ou vá para a Google Play Store para atualizar o aplicativo.

Else if recommendUpgradeé true, mostrar a janela pop-up com opções para atualizar ou continuar usando o aplicativo.

Mesmo com essa capacidade de atualização forçada em vigor, você deve continuar a oferecer suporte a versões mais antigas, a menos que seja absolutamente necessário.

Michael
fonte
Você mostraria um pop-up toda vez que o aplicativo fosse iniciado e recomendaria que a atualização fosse verdadeira? (do ponto de vista UX) Ou apenas mostre o pop-up uma vez e não mostre novamente se o usuário recusar a atualização.
Aneesh de
8
Para atualização recomendada, acho que você não deve mostrar novamente se o usuário recusou. Você também pode mostrá-lo "uma vez a cada n vezes que o usuário abre o aplicativo". Você pode decidir o valor de n sozinho e implementá-lo.
Michael
3
uma solução melhor para isso é passar a versão do aplicativo sistematicamente no cabeçalho de todas as chamadas de API e, em seguida, fazer com que a API retorne um código de status específico se detectar que a versão é obsoleta. e manuseie-o dentro do app. isso é melhor do que ter que chamar outra API dedicada para essa verificação e ter que descobrir exatamente quando / onde essa chamada de API deve ser feita dentro do aplicativo / serviço.
Raphael C de
@RaphaelC Isso realmente depende de sua implementação do lado do servidor. Também não é perfeito adicionar um filtro que verifica a versão em todas as APIs em algumas situações.
Set GH
4
@SepGH as coisas mudaram desde então, e o Android agora oferece uma API que você pode usar para forçar o usuário a atualizar e impedi-lo de continuar usando o aplicativo se ele não atualizar para uma versão mínima: developer.android.com/guide/ app-bundle / in-app-updates
Raphael C
55

tente isto: primeiro você precisa fazer uma chamada de solicitação para o link da playstore, buscar a versão atual de lá e compará-la com a sua versão atual.

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
fonte
1
Eu acho que isso exigiria o uso para adicionar a biblioteca externa JSoup?
Abraham Philip
1
Sim, mas isso seria para obter a página div html. Eu quis dizer que você pode não precisar usar nenhuma biblioteca de terceiros para obter essa funcionalidade, se você pode raspar esse elemento html sem JSoup, ainda funcionaria
AshuKingSharma
1
e se eles mudarem o valor do itemprop ??
Asok Buzz
1
Se eles alterassem o valor itemprop, isso afetaria meus aplicativos também. Eu editaria minha resposta para oferecer suporte a isso imediatamente, então não se preocupe até então :)
AshuKingSharma
Nice setCancelable (false)
Kai Wang
46

Você não deve parar de oferecer suporte a uma versão mais antiga assim que uma nova versão for lançada. Isso resultará em uma experiência de usuário terrível. Não conheço nenhum fornecedor de software que faça isso, por um bom motivo.

O que acontece se o usuário não puder atualizar ou não quiser naquele momento? Eles simplesmente não podem usar seu aplicativo, o que é ruim.

O Google não fornece nenhuma opção para rastreamento de versão como essa, então você teria que fazer a sua própria. Um serviço da web simples para retornar a versão ativa atual que seu aplicativo pode verificar seria suficiente. Você pode então atualizar a versão e o aplicativo saberá que está desatualizado. Eu só recomendo usar isso para que seus usuários saibam que há uma atualização mais rapidamente do que dependendo do Google Play. Na verdade, não deve ser usado para impedir que o aplicativo funcione, apenas para solicitar que o usuário atualize.

Scott Helme
fonte
2
@ashraful se esta ou qualquer resposta resolveu sua pergunta, considere aceitá-la clicando na marca de seleção. Isso indica para a comunidade mais ampla que você encontrou uma solução e dá alguma reputação para o respondente e para você mesmo. Não há obrigação de fazer isso.
Sufian
A resposta é subjetiva para quantos fornecedores de software VOCÊ SABE que existe. Você pode quantificar isso?
Lou Morda
1
É possível obter a versão atual do aplicativo na app store ou play store? ou se preciso manter a versão mais recente do aplicativo em meu servidor? Porque agora eu tenho uma chamada de serviço em meu servidor para retornar a versão mais recente do aplicativo, mas a dificuldade é cada vez que preciso atualizar o servidor durante a publicação do aplicativo. Portanto, é possível obter o número da versão atual nas respectivas lojas?
subha
2
Supercell suporta apenas a última versão de seus jogos. Depois de enviar uma nova versão ao Google Play, qualquer cliente antigo que tentar se conectar receberá uma resposta de "necessidade de atualização" do servidor e verá a conexão fechada. Eles estão fazendo isso várias vezes por ano. Então, a menos que você não queira contar uma "empresa de jogos" como "fornecedor de software", agora você conhece um :) Considerando que eles ainda estão ganhando alguns milhões de dólares todos os dias, aparentemente essa experiência de usuário terrível não é um obstáculo .
Arjan
@Subha Sim, isso é possível. Mas não há API oficial para isso, então você precisa raspar as páginas da web. O que também significa que pode quebrar se a página da web mudar. Eu fiz isso em um aplicativo de terceiros que escrevi e postei o código bastante simples como resposta aqui . Atualmente, o código funcionará para as páginas do Play e do iTunes. Porém, em um ambiente de produção, pode ser melhor procurar uma solução que atualize automaticamente a versão mais recente do aplicativo no servidor, em vez de depender do formato das páginas do Google ou da Apple?
Arjan
27

Solução da equipe do Google

A partir do Android 5.0, isso é facilmente alcançável por meio do novo mecanismo de atualizações do Google Play In App. Os requisitos são ter a biblioteca Play Core da versão 1.5.0+ e usar a distribuição de App Bundles em vez de apks.

A biblioteca oferece 2 maneiras diferentes de notificar os usuários sobre a atualização:

  1. Flexível, quando os usuários podem continuar usando o aplicativo enquanto ele está sendo atualizado em segundo plano.

  2. Imediato - tela de bloqueio que não permite que um usuário entre no aplicativo até que o atualize.

Existem próximas etapas para implementá-lo:

  1. Verifique a disponibilidade de atualizações
  2. Inicie uma atualização
  3. Receba um retorno de chamada para atualizar o status
  4. Lidar com a atualização

Todas essas implementações de etapas são descritas em detalhes no site oficial: https://developer.android.com/guide/app-bundle/in-app-updates

Gaket
fonte
16

As respostas de Scott e Michael estão corretas. Hospede um serviço que forneça um número mínimo de versão compatível e compare-o com a versão instalada. Espero que você nunca precise usar isso, mas é um salva-vidas se alguma versão estiver disponível, você absolutamente deve matar devido a alguma falha séria.

Eu só queria adicionar o código para o que fazer a seguir. É assim que você inicia o Google Play Intent e leva-o para sua nova versão na loja após avisar ao usuário que deve fazer o 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)));

            }
        });
    }
}

Você deve reconsiderar seu design se precisar forçar atualizações em cada versão.

bsautner
fonte
11

O Google introduziu atualizações lib no aplicativo, ( https://developer.android.com/guide/app-bundle/in-app-updates ) que funciona no Lollipop + e oferece a capacidade de solicitar ao usuário uma atualização com um bom diálogo (FLEXÍVEL) ou com mensagem obrigatória em tela cheia (IMEDIATA).

Você precisa implementar o último. É assim que vai ficar: insira a descrição da imagem aqui

Abordei todo o código nesta resposta: https://stackoverflow.com/a/56808529/5502121

Kirill Karmazin
fonte
1
Esta é a melhor resposta!
fvaldivia
Na verdade, esse recurso depende do cache do Play estar atualizado quando o usuário inicia seu aplicativo, ou seja, se o número da versão do seu aplicativo no cache não for o mesmo que o número da versão de sua implementação mais recente no Playstore, ele não avisará o usuário.
kiran01bm
6

Eu recomendo fortemente verificar a funcionalidade de configuração remota do Firebase para isso.

Eu implementei usando um parâmetro - app_version_enabled - com uma condição "Disabled Android Versions" que se parece com isto:

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

O padrão para o parâmetro é "true", mas Disabled Android Versions tem um valor false. No meu regex para versões desativadas do Android, você pode adicionar mais versões desativadas simplesmente com outra |{version name}dentro desses parênteses.

Então, eu apenas verifico se a configuração diz que a versão está habilitada ou não - eu tenho uma atividade que inicio que força o usuário a atualizar. Eu verifico os únicos dois lugares em que o aplicativo pode ser iniciado externamente (minha atividade de iniciador padrão e uma atividade de manipulação de intenção). Como o Remote config funciona com base em cache, ele não capturará imediatamente as versões "desativadas" do aplicativo se não tiver passado o tempo necessário para o cache ser invalidado, mas isso é no máximo 12 horas se você estiver passando seu valor de expiração de cache recomendado.

Chantell Osejo
fonte
Esta é uma opção muito boa. Ao especificar um subconjunto de versões "desabilitadas", você pode se proteger rapidamente, caso um aplicativo tenha problemas de segurança ou problemas graves de desempenho. Ele permite que você continue apoiando todas as versões, mas proíba versões específicas quando surgir a necessidade.
Terry
6

Oficialmente, o Google fornece uma API Android para isso.

A API está sendo testada com vários parceiros e estará disponível para todos os desenvolvedores em breve.

A API de atualização já está disponível - https://developer.android.com/guide/app-bundle/in-app-updates

Chulo
fonte
2
Consulte também: android-developers.googleblog.com/2018/11/…
albert c braun
1
Esta API já está disponível?
Yayayaya
Pesquisei no google e encontrei este developer.android.com/guide/app-bundle/in-app-updates
Chulo
Na verdade, esse recurso depende do cache do Play estar atualizado quando o usuário inicia seu aplicativo, ou seja, se o número da versão do seu aplicativo no cache não for o mesmo que o número da versão de sua implementação mais recente no Playstore, ele não avisará o usuário.
kiran01bm
3

verifique o código da versão do apk local e da 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();
    }

implementar classe para verificação de versão

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

caixa dialob para atualização

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 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
fonte
2

É melhor definir nosso próprio processo para atualização.

  1. Crie um serviço web que forneça a versão mais recente do aplicativo (ios, android) de nosso servidor.
  2. Ou Qualquer serviço da web que você usou no aplicativo (por exemplo, Login) retornará a versão mais recente do aplicativo do servidor.
  3. Uma vez que o aplicativo obterá a versão # 1 ou 2. O aplicativo fará a verificação cruzada com a versão do aplicativo local / cuurent. se houver diferença, podemos mostrar o alerta da seguinte maneira,

Android e iOS: se a versão mais recente do aplicativo estiver disponível, ele mostrará um alerta como “Última versão disponível com mais recursos. Para atualizar, clique no botão de atualização” (Alerta com “Upgarde” e o botão “Não. Obrigado”.) Em seguida, o aplicativo redirecionará para playstore / Appstore e abrirá a versão mais recente.

 --- we can do upgrade compulsory or optionally.

Antes do processo de atualização, certifique-se de lidar com o processo de migração de banco de dados adequado se houver qualquer alteração no esquema de banco de dados.

Sandeep
fonte
1

Para forçar o usuário do aplicativo a atualizar se uma atualização estiver disponível no mercado, você deve primeiro verificar a versão do aplicativo no mercado e compará-la com a versão do aplicativo no dispositivo. Se forem diferentes, pode haver uma atualização disponível. Neste post eu escrevi o código para obter a versão atual do market e a versão atual do dispositivo e compará-las. Também mostrei como mostrar a caixa de diálogo de atualização e redirecionar o usuário para a página de atualização. Visite este link: https://stackoverflow.com/a/33925032/5475941 Apenas certifique-se de que na caixa de diálogo você mostre apenas o botão de atualização do usuário e não mostre a ele o botão cancelar. Nesse caso, ele será forçado a atualizar, antes de usar o aplicativo.

Maomé
fonte
1

O que definitivamente deve ser mencionado aqui é a API de atualizações no aplicativo que será lançada em breve .

Você terá duas opções com esta API; a primeira é uma experiência de tela inteira para atualizações críticas quando você espera que o usuário espere a atualização ser aplicada imediatamente. A segunda opção é uma atualização flexível, o que significa que o usuário pode continuar usando o aplicativo enquanto a atualização é baixada. Você pode personalizar completamente o fluxo de atualização para que pareça parte do seu aplicativo.

Marko Gajić
fonte
1

É uma boa ideia usar a configuração remota para a versão do aplicativo e sempre verificar a atividade de inicialização se a versão atual do aplicativo é a mesma que a versão remota ou não, se não forçar para atualização da app store.

Codificação feliz lógica simples ..

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

Neeraj Singh
fonte
1

Você pode usar as atualizações do aplicativo Play Core Library para resolver isso. Você pode verificar a disponibilidade de atualizações e instalá-las perfeitamente.

As atualizações no aplicativo não são compatíveis com aplicativos que usam arquivos de expansão APK (arquivos .obb). Você pode ir para downloads flexíveis ou atualizações imediatas que o Google Play se encarrega de baixar e instalar a atualização para você.

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

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

Amin Pinjari
fonte
0

você pode fazer isso fazendo uma correspondência entre um número de versão que é mantido no aplicativo em uma variável e da mesma forma a versão atual do aplicativo é mantida no lado do servidor e cada vez que o usuário abre o aplicativo, a primeira solicitação deve ser enviada para verificar se ele encontra a correspondência não faz nada, simplesmente permite que o usuário use seu aplicativo, caso contrário, acione um intent no google playstore ou abra uma janela de visualização da web para seu aplicativo (window.open (" https://play.google.com/store/apps/details?id= package_name ", '_system', 'location = yes');) e lá eles terão automaticamente o botão pedindo atualização que é o que o google playstore faz por você se você não tiver as atualizações automáticas ativadas.

shiva2492
fonte
0

Você pode notificar seus usuários de que há uma nova versão do aplicativo atual disponível para atualização. Além disso, se essa condição for verdadeira, você pode bloquear o login no aplicativo.

Por favor, veja se isso fornece a você a solução.

Vansuita Jr.
fonte
0

Bem, pode haver muitas soluções para esse problema, como copiar o código da versão da página do aplicativo (página do aplicativo do Google Play), etc.

Mas vou mostrar a solução definitiva que não custará um centavo e funcionará como mágica.

  1. Basta salvar o código da versão mais recente do seu aplicativo no
    painel do Firebase Remote config
  2. Busque o valor do código da versão sempre que o aplicativo for aberto
  3. Compare-o com o código da versão atual do aplicativo, que você pode obter pelo seguinte código

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

    }

Se o código da versão buscada for maior que a versão atual, mostre um AlertDialog pedindo para atualizar o aplicativo. Caso contrário, o aplicativo já está atualizado.

Portanto, sempre que lançar a nova versão, você precisará colocar o código da nova versão no painel de configuração remota do Firebase

Você pode ler todo o tutorial sobre como forçar os usuários a atualizar o aplicativo usando o Firebase Remote config

Waqas Younis
fonte
0

O Google lançou atualizações no aplicativo para a biblioteca Play Core.

Implementei uma biblioteca leve para implementar facilmente atualizações no aplicativo. Você pode encontrar no link a seguir um exemplo sobre como forçar o usuário a realizar a atualização.

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

dKaratzas
fonte