web-dev-qa-db-ja.com

ディープリンクと複数のアプリインスタンス

アプリにディープリンクを実装しました。このインテントフィルターをマニフェストファイルに追加しましたが、ディープリンクは機能しています。

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

問題は、ディープリンクを通じて、私のアプリが現在のアプリの上で起動することです。 Gmailでリンクをクリックすると、Gmailの上でアプリが起動します。アプリを別の方法で起動したい。

アプリが既にバックグラウンドで実行されている場合、Gmailで自分のアプリにリダイレクトするリンクをクリックすると、アプリの2つのインスタンスが同時に実行されます。 1つはバックグラウンドで、もう1つはGmailの上にあります。アプリのインスタンスを一度に1つだけ実行したいので、現在のアプリ(Gmail)の上にもありません。どうやってやるの?

44
HariRam

受け入れられた答えは私にとってはうまくいきませんでした、ここに何があったのですか:

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

公式ドキュメントから:

設定されていて、起動されるアクティビティが現在のタスクで既に実行されている場合、そのアクティビティの新しいインスタンスを起動する代わりに、そのアクティビティの他のすべてのアクティビティが閉じられ、このインテントが(現在top)新しいインテントとしての古いアクティビティ。

10
user3453281

マニフェストでアクティビティを追跡する必要があります。

Android:launchMode="singleTask"

これにより、システムは、アクティビティの既存のインスタンスが既に作成されている場合は常に起動するように指示します。

そして、メソッドをオーバーライドすることで、インテントを処理できます

onNewIntent 

詳細については、 http://developer.Android.com/guide/topics/manifest/activity-element.html をご覧ください。

68
Micky

私はこれとまったく同じ問題を抱えていました。ただし、ユーザーがアプリに移動するためにアプリスイッチャーを使用したかのように、ユーザーがフルバックスタックでメインタスクに戻ることを望んでいました。これを実現するには、タスクを並べ替える必要がありました。

1)アプリにタスクを並べ替える許可を与える

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

2)mainタスクIDが何であるかを追跡する

public class MainActivity {
    public static int mainTaskId;

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

3)ディープリンクアクティビティを起動すると、後で使用するためにデータが保存され、メインタスクが前面に表示されます

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)メインタスクのバックスタックの一番上にあるアクティビティが開始されると、作業する保存データがあるかどうかを確認し、作業します。

4
etherton

ディープリンクにはいくつかの問題がありました。のような:

  1. 同じリンクを2回だけクリックし、最初のクリックで正しいビューがトリガーされた
  2. 複数のインスタンスを開きました
  3. Whatsappまたはfacebookのリンクは、Webブラウザーのためにwhatsapp自体のビューを開きました。
  4. on Android 6は1つのインスタンスのみを開きましたが、最初のインテント、2番目、3番目のアプリを処理するだけで、インテントデータが何らかの形で変更されなかったため、アクションはしませんでした。

したがって、以下は、私たちが抱えていたいくつかの問題に対する包括的な解決策という質問に対する明確な答えではありません。

当社のソリューション:

a)新しい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)マニフェスト:

    <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)次のサンプル関数を呼び出すことにより、アクティビティonCreate()およびonResume()で渡された新しいインテントを処理します。

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

1つのインスタンスについてのみこの問題を解決します

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

マニフェストファイルにAndroid:launchMode = "singleTask"を追加するだけでこれらの問題を解決します

1
bharat udasi