Компоненты навигации: Deeplink с использованием uri в зависимости от buildType

Есть ли способ прочитать константу, зависящую от buildType ${deepLinkHost}?

debug -> deepLinkUri = http://link.debug/
staging -> deepLinkUri = http://link.staging/
release ->  deepLinkUri=  http://link/
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation_home"
    app:startDestination="@id/fragment_home">

    <fragment
        android:id="@+id/fragment_home"
        android:name="..."
        tools:layout="@layout/fragment_home">
        <argument
            android:name="token"
            android:defaultValue="@null"
            app:argType="string"
            app:nullable="true" />
        <deepLink app:uri="${deepLinkUri}/?code={token}" />
</fragment>

Раньше это управлялось с помощью manifestPlaceholder.deepLinkHost в build.gradle и deeplinks по активности в AndroidManifest, но как только Google использует 1 Activity для N фрагментов, как мы можем управлять этим с помощью компонентов навигации?


person rafaelasguerra    schedule 08.09.2019    source источник
comment
Вы хотите читать deepLinkUri или хотите, чтобы в вашем графике использовались разные deepLinkUri в зависимости от типа сборки?   -  person Natig Babayev    schedule 10.09.2019
comment
Мой график для использования разных deepLinkUri в зависимости от моего типа сборки. Например, если я нахожусь в отладке, он должен учитывать uri из отладки   -  person rafaelasguerra    schedule 10.09.2019
comment
Вы уже создали варианты сборки или вам тоже нужна помощь?   -  person Natig Babayev    schedule 11.09.2019


Ответы (3)


Похоже, что в настоящее время он не поддерживается из коробки, но есть довольно простой обходной путь. Обычно для регистрации глубинной ссылки требуется два шага:

  1. Добавьте deepLink в диаграмму навигации. Поскольку мы не можем указать какую-либо замену или ресурс @string в качестве uri, давайте просто определим имя хоста как переменную: <deepLink app:uri="http://{deepLinkHost}/?code={token}" />. Эта ссылка будет соответствовать любому хосту и передавать deepLinkHost в качестве параметра.
  2. Зарегистрируйте фильтр намерений в AndroidManifest.xml, чтобы наши действия фактически реагировали на глубокую ссылку. Рекомендуемый подход для последней версии студии Android - добавить <nav-graph android:value="@navigation/nav_graph" /> в манифест, чтобы он автоматически генерировал необходимый фильтр намерений. Однако он зарегистрирует нашу активность, чтобы принимать ссылки с любого хоста, что, вероятно, не то, что мы хотим. Поэтому вместо этого воспользуемся стандартным подходом. . В основном здесь мы определяем фильтр намерений вручную, а не автоматически генерируем его из навигационного графа. Таким образом, мы можем использовать явные замены, как обычно.

Пример

а также

build.gradle

buildTypes {

        debug {
            manifestPlaceholders.deepLinkUri = "http://link.debug"
        }

        staging {
           manifestPlaceholders.deepLinkUri = "http://link.staging"
        }

        release {
           manifestPlaceholders.deepLinkUri = "http://link"
        }
    }

AndroidManifest.xml

 <activity
     android:name=".HomeActivity">
     <intent-filter>
       <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
     <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:host="${deepLinkUri}"
            android:scheme="https" />
    </intent-filter>   
 </activity>

navigation_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/navigation_home"
    app:startDestination="@id/fragment_home">

    <fragment
        android:id="@+id/fragment_home"
        android:name="..."
        tools:layout="@layout/fragment_home">
        <argument
            android:name="deepLinkUri"
            android:defaultValue="@null"
            app:argType="string"
            app:nullable="true" />
        <argument
            android:name="token"
            android:defaultValue="@null"
            app:argType="string"
            app:nullable="true" />
        <deepLink app:uri="{deepLinkUri}/identification?code={token}" />
</fragment>

    <fragment
        android:id="@+id/fragment_marketing"
        android:name="..."
        tools:layout="@layout/fragment_marketing">
        <argument
            android:name="deepLinkUri"
            android:defaultValue="@null"
            app:argType="string"
            app:nullable="true" />
        <argument
            android:name="id"
            app:argType="integer"
            app:nullable="true" />
        <deepLink app:uri="{deepLinkUri}/banner?id={id}" />
</fragment>

Обновление от 22.05.2020: Начиная с версии 3.6 плагина gradle, uri глубинной ссылки не может содержать параметры в частях схемы и хоста, это приведет к Improper use of wildcards and/or placeholders in deeplink URI host ошибке.

К счастью, можно использовать подстановочный знак, поэтому, чтобы подход снова заработал, просто измените определение deepLink в файле навигационного графика:

<deepLink app:uri="{deepLinkUri}/banner?id={id}" /> to <deepLink app:uri=".*/banner?id={id}" />

person esentsov    schedule 10.09.2019
comment
если я использую традиционный способ, мне нужно управлять всеми диплинками для одного действия. Как только компонент навигации просто рекомендует иметь одно действие и N фрагментов @esentsov - person rafaelasguerra; 15.09.2019
comment
@rguerra вышеупомянутый подход заставляет компоненты навигации работать с глубокими ссылками с традиционным способом регистрации ссылок. Таким образом, вам не нужно обрабатывать ссылки в действии, библиотека сделает это за вас и откроет правый экран. - person esentsov; 15.09.2019
comment
треп, спасибо. К сожалению, это работает только для простых диплинков. В моем случае я использую динамические ссылки firebase и не знаю, как управлять длинными ссылками stackoverflow.com/questions/57868086/ - person rafaelasguerra; 20.09.2019
comment
Ребятам прочтите этот ответ: вставьте переменные сборки в манифест developer.android.com/ studio / build / manifest-build-переменные - person li2; 27.11.2019
comment
@esentsov <deepLink app:uri="${deepLinkUri} у меня не работает, пока я не обновлюсь до <deepLink app:uri="{deepLinkUri}, удалив $ - person li2; 27.11.2019
comment
Спасибо @ li2, исправил в ответе - person esentsov; 27.11.2019
comment
@esentsov Я следил за вашим ответом и обнаружил проблему. У меня есть только одно действие (MainActivity), в котором размещено несколько фрагментов. Если режим запуска MainActivity является стандартным, приложение откроет глубоко связанный фрагмент, но будет открыто несколько экземпляров приложения. Если режим запуска MainActivity - singleTask, будет открыто одно приложение, но фрагмент с глубокой связью не будет перемещен. - person Hau Luu; 05.03.2020
comment
@HauLuu Когда вы устанавливаете режим запуска на singleTask, вам также необходимо переопределить onNewIntent в своей деятельности и передать намерение NavController.handleDeepLink - person esentsov; 05.03.2020
comment
О, да. Я тоже это понимаю. Но вместо этого я использую NavController.navigate (Uri). - person Hau Luu; 05.03.2020
comment
У меня Improper use of wildcards and/or placeholders in deeplink URI host ошибка, потому что я забыл удалить <nav-graph android:value="@navigation/nav_graph_main" /> из тега активности в манифесте. Помните это, ребята! - person wrozwad; 19.03.2020
comment
А в аргументе app:uri в теге навигации deepLink вы можете использовать любое имя для имени вашего хоста, например. {anyAwesomePlaceholderName}/identification?code={token} - person wrozwad; 19.03.2020
comment
С навигационными компонентами версия 2.2.2, по-видимому, невозможна. - person Leandro Ocampo; 20.05.2020
comment
@LeandroOcampo, пожалуйста, посмотрите ответ на обновления, может быть, это решает проблему - person esentsov; 22.05.2020
comment
@esentsov спасибо! Работая над этой функцией, я заметил странное поведение библиотеки. Это не имеет отношения к этому вопросу. Если вам интересно: stackoverflow.com/questions/61951850/ - person Leandro Ocampo; 22.05.2020
comment
@esentsov У меня есть URI типа https://staging.example.com/invite/email для постановки и https://example.com/invite/email для производства. У меня */invite/email не работает. Он думает, что не может справиться с deeplink. К вашему сведению, у меня нет навигационного графика в манифесте. - person Bhavin Desai; 05.10.2020
comment
@BhavinDesai, проверь, не упустил ли ты точку .*/invite/email - person esentsov; 05.10.2020
comment
@esentsov Спас мой день! Фактически, в принятом ответе это *., которое следует исправить на .* - person Bhavin Desai; 05.10.2020
comment
@esentsov в моем случае, когда я использую подстановочный знак .*, он просто открывает приложение и не открывает фрагмент ... похоже, что подстановочный знак по какой-то причине не работает - person Buntupana; 16.11.2020
comment
только что проверил и со схемой, установленной как app, не работает должным образом ... если я изменю его на https, он будет работать ... в чем может быть причина? - person Buntupana; 16.11.2020
comment
@Buntupana, если вы не укажете схему, библиотека навигации автоматически установит http[s]. Попробуйте использовать что-то вроде этого app://.*/deep-link - person esentsov; 16.11.2020
comment
как насчет android:autoVerify="true" с подстановочными знаками хоста? Это возможно? Я так не думаю, или у меня проблема с моим приложением ... - person mtrakal; 12.05.2021
comment
android:autoVerify работает путем чтения файла манифеста вашего apk. Итак, если у вас есть правильный URL-адрес в объединенном манифесте (например, используя замены во время сборки, как в этом ответе), все должно быть в порядке - person esentsov; 12.05.2021
comment
а как насчет только схем? В моем сценарии у меня разные схемы для каждого аромата, я пробую этот подход, но, похоже, не работает - person extmkv; 11.06.2021
comment
Я также ищу решение, поддерживающее индивидуальные схемы для каждого аромата. - person G_comp; 14.06.2021
comment
Подстановочные знаки не поддерживаются в части схемы. Таким образом, самый простой способ - добавить как <deepLink app:uri="flavor1://host.com/deep-link" />, так и <deepLink app:uri="flavor2://host.com/deep-link" /> в навигационный граф и определить, какой из них обрабатывается конкретным вкусом, добавив подстановку в манифесте: <data android:host="host.com" android:scheme="${deepLinkScheme}" /> - person esentsov; 15.06.2021

Просто добавив -

<deepLink app:uri=".*/{my_token}" />

Сработало у меня !!! Что меня также удивило, что для этого не требовалось никакого дополнительного кода.

Изменить 1: но приведенный выше код также открывает другие URL-адреса из других приложений с помощью моего приложения. Это ХОРОШО, если вы действительно хотите, чтобы люди открывали свои URL-адреса в вашем приложении. Но если вам это не нравится, вы можете попробовать исправить это ниже. Я исправил это, просто добавив две глубокие ссылки для двух моих вариантов моего URL-адреса, например:

<deepLink
    app:uri="http://www.stage.com/{token}" />

<deepLink
    app:uri="http://www.production.com/{token}" />
person Gk Mohammad Emon    schedule 27.03.2021

Для него до сих пор нет действительного решения.

Пожалуйста, пометьте эти две проблемы для более быстрого решения (не думаю, что это поможет, но, возможно ...):

https://issuetracker.google.com/issues/36994900

https://issuetracker.google.com/issues/110237825

person mtrakal    schedule 12.05.2021