web-dev-qa-db-ja.com

アーキテクチャコンポーネントを使用したマルチモジュールナビゲーション

したがって、現在のアプリのモジュールにこの構造があります。

App Module Structure

マルチモジュールナビゲーションに関する公式ドキュメントはまだ見つかりませんが、これについて article を見つけたので、gradleファイルは次のようになります。

機能1-詳細

...
implementation project(":base")
implementation project(":feature-2-detail")
...

機能2-詳細

...
implementation project(":base")
implementation project(":feature-1-detail")
...

機能3-詳細

...
implementation project(":base")
implementation project(":feature-1-detail")
...

そしてこれが私のナビゲーショングラフです:

機能1-詳細

<navigation ...
    Android:id="@+id/graph_feature_1_id">
    <include app:graph="@navigation/graph_feature_2" />
    <fragment ...
        Android:id="@+id/nav_feature_1">
        <action ...
            app:destination="@+id/graph_feature_2_id" />

    </fragment>
</navigation>

機能2-詳細

<navigation ...
    Android:id="@+id/graph_feature_2_id">
    <include app:graph="@navigation/graph_feature_1" />
    <fragment ...
        Android:id="@+id/nav_feature_2">
        <action ...
            app:destination="@+id/graph_feature_1_id" />

    </fragment>
</navigation>

機能3-詳細

<navigation ...
    Android:id="@+id/graph_feature_3_id">
    <include app:graph="@navigation/graph_feature_1" />
    <fragment ...
        Android:id="@+id/nav_feature_3">
        <action ...
            app:destination="@+id/graph_feature_1_id" />

    </fragment>
</navigation>

したがって、すべてがこの種のセットアップで機能しますが、ここでの問題は、モジュールを別のモジュールに接続するために、現在の機能への依存関係として他の機能を追加する必要があることです。私の場合と同様に、機能1-詳細機能2に行くことができます-詳細逆もまた同じで、これを行うと、gradleに循環依存関係ができます。

マルチモジュールナビゲーションを実行する別の方法はありますか?ディープリンクを使用しようとしましたが、役に立ちませんでした。

何か助けていただければ幸いです!ありがとう!

17
Kurt Acosta

これはすでに1年間ですが、ライブラリはこの正確なユースケースをサポートできるようになりました! 2.1.0-alpha 以降、ディープリンクURIを介してナビゲーションできます。

実装の詳細として機能を相互に追加する代わりに、それらを互いに知らないままにして、ディープリンクナビゲーションを使用できます。

機能1-詳細-build.gradle

dependencies {
    implementation project(':base')
}

Feature 2-Detailと同じです。他のモジュールを知る必要はありません。

モジュール間のナビゲーションを行うには、最初にdeepLinkタグを介してその宛先をナビゲートするためのディープリンクを定義する必要があります。

機能1-詳細-ナビゲーショングラフ

<navigation ...
    Android:id="@+id/graph_feature_1_detail_id">
    <fragment ...
        Android:id="@+id/nav_feature_1_detail">
        <deepLink app:uri="myApp://feature1detail"/>

    </fragment>
</navigation>

機能2-詳細-ナビゲーショングラフ

<navigation ...
    Android:id="@+id/graph_feature_2_detail_id">
    <fragment ...
        Android:id="@+id/nav_feature_2_detail">
        <deepLink app:uri="myApp://feature2detail"/>

    </fragment>
</navigation>

URIが設定されたディープリンクが設定されたので、NavControllerでこれを直接使用できます

Feature 1-Detailのフラグメントでは、おそらくボタンをクリックしますか?ナビゲーションを実行する必要がある場所

class Feature1DetailFragment {
   fun onViewCreated(...) {
       ...
       view.setOnClickListener {
           val uri = Uri.parse("myApp://feature2detail")
           findNavController().navigate(uri)
       }
   }
}

そしてFeature 2-Detail

class Feature2DetailFragment {
   fun onViewCreated(...) {
       ...
       view.setOnClickListener {
           val uri = Uri.parse("myApp://feature1detail")
           findNavController().navigate(uri)
       }
   }
}

そして出来上がり!モジュール間のナビゲーション。

執筆時点では、最新の安定版リリースは2.1.0-rc01

私はこれをもっと複雑なプロジェクトで試したことはありませんが、このライブラリが大好きなので、このライブラリがもっと成熟することを期待しています!

これについて Medium article を作成しました。ご覧になれます。乾杯!

10
Kurt Acosta

更新2:

課題追跡からの議論の引用 issue

開発:

同じことを通常のモジュール(非動的機能モジュール)で使用できるかどうか疑問に思いますか?

Googleエンジニア:

はい、非動的モジュールでも使用できます。

開発:

非動的モジュールでの使用にはドキュメントがあるといいでしょう。

非動的モジュールでこれを使用する方法のコード例を教えてもらえますか?

Googleエンジニア:

すべてのnavigation-dynamic-*コンポーネントは、非動的コンポーネントから拡張されます。ナビゲーションライブラリを使用する場合と同じように使用できます。そのパスでバグが発生した場合は、 問題を提出する でお知らせください。

navigation-dynamic-*の制限は ここで説明 です。


更新1:

現在Dynamic Navigatorライブラリは開発段階にあります。

セットアップ

dependencies {
    def nav_version = "2.3.0-alpha01"

    api "androidx.navigation:navigation-fragment-ktx:$nav_version"
    api "androidx.navigation:navigation-ui-ktx:$nav_version"
    api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
}

基本的な使い方

動的機能モジュールをサポートするには、まずアプリ内のNavHostFragmentのすべてのインスタンスをandroidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragmentに変更します。

<fragment
    Android:id="@+id/nav_Host_fragment"
    Android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
    app:navGraph="@navigation/nav_graph"
    ... />

次に、DynamicNavHostFragmentに関連付けられているナビゲーショングラフのapp:moduleName<activity>、または<fragment>の宛先に<navigation>属性を追加します。この属性は、宛先が指定した名前の動的機能モジュールに属していることをDynamic Navigatorライブラリに通知します。

<fragment
    app:moduleName="myDynamicFeature"
    Android:id="@+id/featureFragment"
    Android:name="com.google.Android.samples.feature.FeatureFragment"
    ... />

詳細は docs を参照してください。


= 開発レベルのソリューション があり、動的機能モジュール間をAndroidチームでナビゲートできます。ただし、これは通常の機能モジュール間をナビゲートするためにも使用できるようです。

3
user158

役立つ可能性のあるアプローチの1つは、完全に新しい独立したモジュール(たとえば、「:navigation」モジュール)を作成し、すべてのnavigation.xmlファイルを他のすべてのモジュールからそのモジュールに移動することです。次に、ナビゲーション関連のものが必要な他のすべてのモジュールの新しい( ":navigation")モジュールに依存し、R.navigationまたは生成された引数クラスなどにアクセスできるようになります。

新しい( ":navigation")モジュールはプロジェクト内の他の何も知らないので、IDEは、navigation.xmlファイルで使用するフラグメント、アクティビティ、その他のクラスを赤でマークします。他のモジュールの外部で定義されていますが、完全なクラス名(com.exampel.MyFragment)を使用している限り、コンパイルして機能します。

<?xml version="1.0" encoding="utf-8"?>
<navigation 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/nav_graph_id"
    app:startDestination="@id/some_navigation_id">

    <fragment
        Android:id="@+id/some_navigation_id"
        Android:name="com.exampel.MyFragment".../>
        // com.exampel.MyFragment will be marked red since IDE can't link it
        // to the existing class because it is in the other module

これにより、クラス名と引数の可能性を知る必要がある方法でナビゲートするすべてのクラスに「非表示」の依存関係が作成されます。手動で維持する必要がありますが、独立したモジュールでナビゲーションを簡単に分離できます。

1
doolle89

基本機能で各機能ナビゲーショングラフIDを明示的に宣言すると、Gradleの機能間の依存関係をすべて削除できます。これらのIDは「隠された」機能間の依存関係を作成するため、私はこのソリューションに100%満足していませんが、それ以外の場合は正常に機能します。

このセットアップの重要な部分は次のとおりです。

:app

build.gradle

dependencies {
    implementation project(':features:feature-base')
    implementation project(':features:feature-one')
    implementation project(':features:feature-two')
}

:features:feature-base

build.gradle

dependencies {
    application project(':app')
    feature project(':features:feature-one')
    feature project(':features:feature-two')
}

navigation/feature_base_nav_graph.xml

<navigation ...>
    <include app:graph="@navigation/feature_one_nav_graph" />
    <include app:graph="@navigation/feature_two_nav_graph" />
</navigation>

values/feature_base_ids.xml

<resources>
    <item name="feature_one_nav_graph" type="id" />
    <item name="feature_two_nav_graph" type="id" />
</resources>

:features:feature-one

build.gradle

dependencies {
    implementation project(':features:feature-base')
}

navigation/feature_one_nav_graph.xml

<navigation
    Android:id="@id/feature_one_nav_graph"
    ...>

    <fragment
        Android:id="@+id/oneFragment"
        ...>
        <action
            Android:id="@+id/navigateToFeatureTwo"
            app:destination="@id/feature_two_nav_graph"
            ... />
    </fragment>

</navigation>

ナビゲート

findNavController().navigate(R.id.navigateToFeatureTwo)

:features:feature-two

build.gradle

dependencies {
    implementation project(':features:feature-base')
}

navigation/feature_two_nav_graph.xml

<navigation
    Android:id="@id/feature_two_nav_graph"
    ...>

    <fragment
        Android:id="@+id/twoFragment"
        ...>
        <action
            Android:id="@+id/navigateToFeatureOne"
            app:destination="@id/feature_one_nav_graph"
            ... />
    </fragment>

</navigation>

ナビゲート

findNavController().navigate(R.id.navigateToFeatureOne)
0
laenger