web-dev-qa-db-fra.com

Liens profonds et plusieurs instances d'application

J'ai mis en place un lien profond dans mon application. J'ai ajouté ce filtre d'intention dans mon fichier manifeste et le lien profond fonctionne.

<intent-filter>
    <action Android:name="Android.intent.action.VIEW" /> 
    <category Android:name="Android.intent.category.DEFAULT" /> 
    <category Android:name="Android.intent.category.BROWSABLE" /> 
    <category Android:name="Android.intent.category.VIEW" /> 
    <data
        Android:Host="www.mywebsite.com"
        Android:pathPrefix="/something"
        Android:scheme="http" />
</intent-filter>

Le problème est que grâce à un lien profond, mon application se lance au-dessus de l'application actuelle. Si je suis dans Gmail et que je clique sur un lien, mon application se lance au-dessus de Gmail. Je veux lancer mon application différemment.

Si mon application est déjà en cours d'exécution en arrière-plan et que je clique sur un lien dans Gmail qui redirige vers mon application, j'aurai deux instances de mon application en cours d'exécution en même temps; un en arrière-plan et un autre au-dessus de Gmail. Je souhaite exécuter une seule instance de mon application à la fois, elle n'est donc pas également au-dessus de l'application actuelle (Gmail). Comment puis je faire ça?

44
HariRam

la réponse acceptée n'a pas fonctionné pour moi, voici ce qui a fonctionné:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();

du doc ​​officiel:

S'il est défini et que l'activité en cours de lancement est déjà en cours d'exécution dans la tâche en cours, alors au lieu de lancer une nouvelle instance de cette activité, toutes les autres activités au-dessus seront fermées et cette intention sera livrée au (maintenant haut) ancienne activité en tant que nouvelle intention.

10
user3453281

Vous devez faire les choses suivantes pour votre activité dans votre manifeste.

Android:launchMode="singleTask"

Cela indique au système de toujours lancer l'instance existante de l'activité si elle est déjà créée.

Et vous pouvez alors gérer l'intention en remplaçant la méthode

onNewIntent 

Voir http://developer.Android.com/guide/topics/manifest/activity-element.html pour plus d'informations.

68
Micky

J'ai eu exactement le même problème, sauf que je voulais que l'utilisateur se retrouve dans la tâche principale avec la pile arrière complète, comme s'il venait d'utiliser le sélecteur d'application pour passer à mon application. Pour ce faire, j'ai dû réorganiser les tâches.

1) Autoriser mon application à réorganiser les tâches

<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.company.app">
     <uses-permission Android:name="Android.permission.REORDER_TASKS"/>
</manifest>

2) Gardez une trace de ce que l'ID de tâche principal est

public class MainActivity {
    public static int mainTaskId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
         super(savedInstanceState);
         //set the main task ID
         taskId = getTaskId();
    } 
}

3) Lorsque mon activité de lien profond est lancée, elle enregistre certaines données pour une utilisation ultérieure, puis met la tâche principale au premier plan

public class DeepLinkActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super(savedInstanceState);

        //persist deep link data
        Uri uri = intent.getData();
        String action = intent.getAction();
        saveForLater(uri, action);

        if(isTaskRoot()){
            //I'm in my own task and not the main task
            final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            activityManager.moveTaskToFront(MainActivity.taskId, ActivityManager.MOVE_TASK_NO_USER_ACTION);
            }
        }
    }
}

4) Lorsque n'importe quelle activité en haut de la pile arrière de la tâche principale démarre, il vérifie s'il y a des données enregistrées sur lesquelles travailler et y travaille.

4
etherton

Eh bien, nous avons eu plusieurs problèmes avec les liens profonds. Comme:

  1. cliquez sur le même lien deux fois seulement, le premier clic a déclenché la vue correcte
  2. ouvert plusieurs instances
  3. Les liens dans WhatsApp ou Facebook ont ​​ouvert une vue dans Whatsapp lui-même en raison de leur navigateur Web.
  4. le Android 6 n'a ouvert qu'une seule instance, mais ne gérait que la première intention, la deuxième et la troisième ouvre l'application mais aucune action car les données d'intention n'ont pas changé d'une manière ou d'une autre.

Donc, ce qui suit n'est pas une réponse claire à la question plus une solution globale pour plusieurs problèmes que nous avions.

Notre solution:

a) Créé une nouvelle FragmentActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2); //well can be anything some "loading screen"

    Intent intent = getIntent();
    String intentUrl = intent.getDataString();
    Intent newIntent = new Intent(this, MainActivity.class);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    newIntent.putExtra("intentUrl",intentUrl);
    newIntent.setAction(Long.toString(System.currentTimeMillis()));

    startActivity(newIntent);
    finish();
}

b) Manifeste:

    <activity
        Android:name="YOUR.NEW.FRAGMENT.ACTIVITY"
        Android:label="@string/app_name"
        Android:launchMode="singleTop">
        <intent-filter>
            <action Android:name="Android.intent.action.VIEW" />
            <category Android:name="Android.intent.category.DEFAULT" />
            <category Android:name="Android.intent.category.BROWSABLE" />

            <data Android:scheme="http" />
            <data Android:scheme="https" />
            <data Android:scheme="scheme1" /> <!-- sheme1://-->
            <data Android:Host="yourdomain.com" />
            <data Android:Host="www.yourdomain.com" />
        </intent-filter>
    </activity>

c) gérer la nouvelle intention passée dans vos activités onCreate () et onResume () en appelant l'exemple de fonction suivant:

private void handleUrl(Intent i){
    String intentUrl = null;
    if (i != null) {
        intentUrl = i.getStringExtra("intentUrl");
        if (intentUrl == null){
            //hmm intent is damaged somehow
        } else {
            //because of onResume()
            if ( i.getBooleanExtra("used",false) ) {
                return;
            }
            i.putExtra("used", true);

           //DO SOMETHING WITH YOUR URL HERE
    }       
}
3
Philipp Reddigau

il suffit de résoudre ce problème pour une seule instance

Android: launchMode = "singleInstance"

<activity
    Android:name=".SplashScreen"
    Android:screenOrientation="portrait"
    Android:launchMode="singleInstance"
    Android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
    <intent-filter>
        <action Android:name="Android.intent.action.MAIN" />
        <category Android:name="Android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter Android:autoVerify="true">
        <action Android:name="Android.intent.action.VIEW" />

        <category Android:name="Android.intent.category.DEFAULT" />
        <category Android:name="Android.intent.category.BROWSABLE" />

        <data Android:scheme="nvd.abc" />
    </intent-filter>
</activity>
2
tej shah

Je résous ces problèmes en ajoutant simplement Android: launchMode = "singleTask" dans le fichier manifeste

1
bharat udasi