【问题标题】:Supporting both implicit and explicit deep linking with Navigation Component支持导航组件的隐式和显式深度链接
【发布时间】:2021-09-03 01:08:56
【问题描述】:

我正在使用导航组件,并尝试在用户点击通知时触发指向特定目的地的显式深层链接,由片段表示。

根据documentation,可以像这样创建待处理的意图:

val bundle = bundleOf("id" to "1234")

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.myDestination)
    .setArguments(args)
    .createPendingIntent()

其中nav_graph定义如下:

<fragment 
   android:id="@+id/myDestination"
   android:name="MyFragment">

   <argument
      android:name="id"
      app:argType="string" />

   <deepLink app:uri="myApp://myFragment?id={id}" /> // Removing this line it works fine

</fragment>

然后,我会使用 NotificationCompat.Builder 将 pendingIntent 用于通知:

.setContentIntent(pendingIntent) 

当我点击通知时,实际打开了正确的目的地,但值 args.id 将是“null”(不是 null,而是一个具有“null”值的字符串。在我的片段中,我有

private val args by navArgs<MyFragmentArgs>()

...

override fun onCreate(saveInstanceState: Bundle?) {
   args.id // The string value is "null". 
} 

但是,如果我从片段中删除&lt;deepLink&gt;,那么它将起作用。问题是我需要隐式和显式的深层链接。有没有一种方法可以同时支持导航组件?

【问题讨论】:

  • 为了完整起见,请添加您正在使用的每个依赖项的版本,以防有人调查并发现 Android 代码中的相关错误。另外,您是否有重现此内容的示例项目?可以检查并练习同样问题的最小的东西? (又名:两个片段项目或类似项目)。这就是我要开始的地方(假设你在两天内没有找到回复)。如果您要报告错误,这也是 Google 会“问您”的内容。愚蠢的机器人会说:“请提供一个 AStudio 项目……”
  • 换句话说,除非有人确切地知道这种情况,否则解决这个问题的唯一方法是创建一个新项目并开始试验;设置所有这些需要“几个小时”,而且没有人可能会在业余时间这样做。
  • bundleOf("id", "1234") 不是bundleOf() Kotlin extension 的有效语法 - 您使用的是什么bundleOf 方法?还是您的代码实际上使用了正确的bundleOf("id" to "1234") 语法?
  • 是的,对不起,我的代码确实使用了正确的语法。我更新了问题

标签: android android-fragments android-architecture-navigation android-navigation android-navigation-graph


【解决方案1】:
val bundle = bundleOf("id" to "1234")

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.myDestination)
    .setArguments(args)
    .createPendingIntent()

你的args变量是什么,因为你在上面声明了bundle

我已经检查过了,所有代码都运行良好。

我的导航图:

<fragment
        android:id="@+id/navigation_notifications"
        android:name="com.olopa.thefirst.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications">

        <deepLink app:uri="sampleapp://noti?id={id}" />

        <argument
            android:name="id"
            app:argType="string"
            app:nullable="true" />

通过通知导航时:

val bundle = bundleOf("id" to "12")

val pendingIntent = NavDeepLinkBuilder(this)
            .setGraph(R.navigation.mobile_navigation)
            .setDestination(R.id.navigation_notifications)
            .setArguments(bundle)
            .createPendingIntent()

结果:

或通过链接导航:

navController.navigate(Uri.parse("sampleapp://noti?id=1"))

结果:

【讨论】:

    【解决方案2】:

    试试这个方法:

    <fragment
        android:id="@+id/navigation_notifications"
        android:name="NotificationsFragment">
    
        <deepLink app:uri="sampleapp://app/noti?id={id}" /> // host and path is required
    
        <argument
            android:name="id"
            app:argType="string"
            app:nullable="true" />
    </fragment>
    
    

    通过(source)在AndroidManifest.xml中注册深层链接

    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:label="@string/app_name">
        <nav-graph android:value="@navigation/mobile_navigation" />
    
        // other intent filters
    </activity>
    

    并创建隐式待处理意图:

    val intent = Intent(Intent.ACTION_VIEW).apply {
        data = "sampleapp://app/noti?id=fromNotif".toUri()
        flags = Intent.FLAG_ACTIVITY_NEW_TASK
    }
    
    val pendingIntent = PendingIntent.getActivity(context, id, intent, flags)
    
    val notification = NotificationCompat.Builder(context, channelName)
        // ...
        .setContentIntent(pendingIntent)
        .build()
    

    到目前为止,它将启动MainActivity

    如果您在其 xml 布局中使用 &lt;fragment&gt;,它将自动在 NotificationsFragment 上导航。

    <fragment
        android:id="@+id/nav_host_fragment_activity_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/mobile_navigation" />
    

    否则你自己处理:

    if (intent.action == Intent.ACTION_VIEW && intent.data != null)
        navController.navigate(intent.data!!)
    

    【讨论】:

      【解决方案3】:

      如果您的导航图内部包含 sum 包含图,则可能会发生这种情况。 使用深度链接意图数据打开必须具有平面图,您的应用可以在片段中导航。 例如,您的问题的另一种解决方案是使用额外的而不是数据 当您想以可以激活片段深层链接的意图开始您的活动时,您可以使用额外和操作视图。 如果您使用 NavDeepLinkBuilder 这会将深度链接作为数据传递给您的意图,并且当您的活动通过待处理的意图打开时,如果您的图表不是平坦的并且包含导航图表,它可能会崩溃。 请参阅下面的代码以更好地理解解决方案。 首先,这是必须存在平面导航图的硬解决方案

      val intent = Intent(this, MainActivity::class.java)
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      intent.data=Uri.parse("your deeplink url")
      

      您可以使用下面更好的代码,并且您的导航图不会改变

      val intent = Intent(this, MainActivity::class.java)
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      intent.putExtra(INTENT_KEY,"your deeplink url")
      

      你可以像这样在你的活动中处理你的意图数据

      intent?.getStringExtra(INTENT_KEY)?.let {
            navController.navigate(Uri.parse(it))
      }
      

      我更喜欢使用它,因为当您使用 NavDeepLinkBuilder 时,您必须知道您的目标 ID,如果您有很多用于在应用程序中导航的用例,您的问题刚刚开始产生很多 if else。 在此解决方案中,您可以将深层链接作为简单字符串传递

      【讨论】:

        猜你喜欢
        • 2021-11-27
        • 2021-07-04
        • 1970-01-01
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-20
        相关资源
        最近更新 更多