【问题标题】:Android - My app replaces the app which shared its contentAndroid - 我的应用替换了共享其内容的应用
【发布时间】:2020-08-11 18:07:52
【问题描述】:

我正在开发一个使用意图(ACTION_SEND)接收数据的应用。我从 Chrome 共享内容时发现了一个奇怪的问题(仅在 Chrome 83 或更高版本中发生,旧版本无法重现该问题)例如,如果内容仅是选定的文本,例如,数据到达我的应用程序正确,但如果共享的内容是 URL,它会到达我的应用程序,但突然我的应用程序替换了应用程序切换器中的 Chrome。因此,如果我打开了我的应用和 Chrome,则在数据共享后我有两个我的应用实例(即使 Chrome 图标出现在该窗口的顶部,如果我点击它,就会打开我的应用)。

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

我的活动代码:

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:我添加了这个活动转储,在问题出现时生成: https://gist.github.com/Leprosy/f63bf02bb1c2887f0e419799d98635ab

【问题讨论】:

  • 您可以使用adb shell dumpsys activity activities 获取有关正在发生的事情的更多信息。这将显示所有正在运行的任务以及这些任务中的所有活动。如果你有一个 singleInstance Activity 并且 Chrome 正在将 Activity 启动到它自己的任务中,那么这是非常错误的。您能否重现问题并将adb 命令的输出复制到问题中(或将其放在云中某处并发布指向它的链接)?
  • 我已编辑问题并将链接添加到包含日志的要点。感谢您的帮助!

标签: android kotlin android-intent


【解决方案1】:

您的应用实际上并没有替换 chrome,而是来自您的应用的共享链接意图接收器活动到达了 chrome task 的顶部。它仍然是 chrome 任务,只是最重要的活动来自您的应用程序。这样可以确保按返回会返回到 Chrome,即使您先切换应用几次也是如此。

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

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

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 打开多个任务。

【讨论】:

  • 我想过做这样的事情,但我的代码总是在我的应用程序替换 Chrome 的上下文中开始,所以我根本无法检测到这种情况。
  • 我编辑了答案以添加有关如何解决此问题的示例代码。
【解决方案2】:

更新 2

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

原答案

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

更新

这是官方文档对您正在使用的隐式深层链接所说的:

隐式深层链接是指向应用程序中特定目标的 URI。当一个 URI 被调用时——例如,当用户点击一个链接时——Android 可以打开你的应用到相应的目的地。

触发隐式深层链接时,后退栈的状态取决于是否使用Intent.FLAG_ACTIVITY_NEW_TASK标志启动了隐式Intent:

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

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

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

【讨论】:

  • 有趣...我还没有找到任何关于此的文档,正如我之前所说,83 之前的任何版本的 Chrome 都不会发生这种情况。
  • 可能在 83 之前被 chrome 处理过
  • 这不仅发生在您的应用中
  • 我正在尝试找到一种方法来禁用此“功能”......这很奇怪
  • 当您从手机上的任何位置打开链接时,如果您的手机上安装了可以处理此链接的应用程序,系统将提示您选择是否要在该应用程序中打开它。简化这称为深度链接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
相关资源
最近更新 更多