Android - 我的应用程序替换了共享其内容的应用程序

Android - My app replaces the app which shared its content

我正在开发一个使用 intents(ACTION_SEND) 接收数据的应用程序。我在分享来自 Chrome 的内容时发现了一个奇怪的问题(只发生在 Chrome 83 或更高版本,旧版本无法重现该问题)例如,如果仅选择内容文本,例如,数据正确到达我的应用程序,但如果共享的内容是 URL,它到达我的应用程序,但突然我的应用程序替换了应用程序切换器中的 Chrome。所以,如果我有我的应用程序并打开 Chrome,在数据共享之后我有我的应用程序的两个实例(即使 Chrome 图标出现在那个 window 的顶部,如果我点击它,打开我的应用程序)。

对这里发生的事情有什么想法吗?值得注意的是,我无法使用 Firefox 重现此内容。

我的activity代码:

class MainActivity : HybridActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d("MyApp", "onCreate")
        super.onCreate(savedInstanceState)
        val testButton = Button(this)
        setContentView(testButton)
    }

    override fun onStart(){
        super.onStart()
        var bundle = intent.getExtras();
        Log.d("MyApp", "onStart intent tostr: " + intent.toString())

        if (bundle != null) {
            bundle.keySet().forEach {
                Log.d("MyApp", "EXTRA:" + it + "=" + bundle.get(it));
            }
        }
    }

    override fun onResume() {
        super.onResume()
        Log.d("MyApp", "onResume")
    }
}

意图过滤器在清单中定义如下:

<intent-filter>
          <action android:name="android.intent.action.SEND" />
          <category android:name="android.intent.category.DEFAULT" />
          <data android:mimeType="text/plain" />
          <data android:mimeType="image/*" />
          <data android:mimeType="video/*" />
        </intent-filter>

PS:不知道这是否相关,但我已将清单中的启动模式更改为 singleInstance,问题仍然可重现...

PS2:我添加了这个 activity 转储,它是在问题出现时生成的: https://gist.github.com/Leprosy/f63bf02bb1c2887f0e419799d98635ab

更新 2

所以我做了更多的研究,似乎只有在使用 android 共享表时才会发生这种情况。当共享数据的应用程序使用意图解析器时,activity 在新的 task/instance 中打开。例如 firefox 中的共享功能确实可以正确处理它。不幸的是,我找不到与此相关的任何内容以及如何解决它。

原答案

我认为这是一个需要的行为,因为您的应用程序正在处理 url 并且它没有在您的应用程序中打开。

更新

这是官方文档对您正在使用的隐式深度 links 的描述:

隐式深度 link 是指代应用程序中特定目的地的 URI。当调用 URI 时——例如,当用户单击 link——Android 然后可以将您的应用程序打开到相应的目的地。

触发隐式深度 link 时,返回堆栈的状态取决于隐式 Intent 是否使用 Intent.FLAG_ACTIVITY_NEW_TASK 标志启动:

  • 如果设置了标志,任务返回堆栈将被清除并替换为深度 link 目的地。与显式深度 linking 一样,在嵌套图形时,每个嵌套级别的起始目的地——即层次结构中每个元素的起始目的地——也被添加到堆栈中。这意味着当用户从深层 link 目的地按下后退按钮时,他们会导航回导航堆栈,就像他们从入口点进入您的应用程序一样。
  • 如果未设置标志,您将保留在前一个应用程序的任务堆栈中,其中触发了隐式深度 link。在这种情况下,“后退”按钮会将您带回到上一个应用程序,而“向上”按钮会在您的导航图中的分层父目标上启动您的应用程序任务。

据我了解,这意味着只有启动您的应用的应用才能更改此行为。

来源:https://developer.android.com/guide/navigation/navigation-deep-link#implicit

您的应用实际上并没有替换 chrome,而是来自您应用的共享 link 意图接收器 activity 到达 chrome [=14] 的顶部=].它仍然是 chrome 任务,只是最重要的活动来自您的应用程序。这确保了按返回键会返回到 chrome,即使您会先切换应用几次。

作为一种解决方法,您可以检测到这一点,在这种情况下,创建一个新的意图来启动一个新的 activity 并关闭直接接收它的意图。

编辑:我对此进行了测试,可以通过以下方式完成:

import android.app.Activity
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.os.Bundle

class ExternalTextReceiverActivity : Activity() {
    val CUSTOM_EXTRA_NAME = "RELAUNCHED"

    override fun onCreate(savedInstanceState: Bundle?) {
        if (!intent.getBooleanExtra(CUSTOM_EXTRA_NAME, false)) {
            this.finish()
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(CUSTOM_EXTRA_NAME, true);
            startActivity(intent);
        }
        super.onCreate(savedInstanceState);
        // The rest of your onCreate code here

    }
}

如果您只希望 chrome 使用此代码,则可以使用此代码:

import android.app.Activity
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.os.Bundle

class ExternalTextReceiverActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        if (intent.getIntExtra("org.chromium.chrome.extra.TASK_ID", -1) == this.taskId) {
            this.finish()
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
        super.onCreate(savedInstanceState);
        // The rest of your onCreate code here
    }
}

在 Android 清单中为您的 Activity 结合 android:launchMode="singleInstance"android:launchMode="singleTask" 以确保它不会为同一个 activity.