- Adding tools:node=»replace» to Android Manifest application tag causes FCM not working #477
- Comments
- sreejithbnaick commented Apr 25, 2018 •
- Summary:
- Environment
- Description of the problem:
- Steps to reproduce:
- Observed Results:
- Expected Results:
- Adding tools:node=»replace» to Android Manifest application tag causes FCM not working #477
- Comments
- sreejithbnaick commented Apr 25, 2018 •
- Summary:
- Environment
- Description of the problem:
- Steps to reproduce:
- Observed Results:
- Expected Results:
- Что делает атрибут tools: replace в файле манифеста Android?
- 1 ответ
- Android Manifest merge conflict (backup rules) #9
- Comments
- ljwan12 commented Jan 14, 2020
- ljwan12 commented Jan 14, 2020
- elitvynov commented Apr 23, 2020
- elitvynov commented Apr 28, 2020
- syrakozz commented May 3, 2020
- Cotel commented May 8, 2020
- ManakaMichihito commented May 14, 2020
- lfg-ryan commented May 14, 2020
- ManakaMichihito commented May 21, 2020
- ManakaMichihito commented May 22, 2020 •
- VladimirKuzmin-azur commented Jul 14, 2020 •
- m-kul commented Jan 8, 2021
- af-vs commented Jan 14, 2021
- Будущее внедрения зависимостей в Android
- Создание Activity до Android 9 Pie
- Внедрение зависимостей в Android сегодня
- Что не так с текущим подходом?
- Внедрение зависимостей в Android 9 Pie
- Встречайте — Dagger Multi-Binds
- Проблемы внедрения в конструктор
- Заключение
Adding tools:node=»replace» to Android Manifest application tag causes FCM not working #477
Comments
sreejithbnaick commented Apr 25, 2018 •
Summary:
If I add tools:node=»replace» to AndroidManifest Application tag, Android App will never get
FirebaseInstanceIdService onTokenRefresh() callback and FCM doesn’t work.
Environment
- Android device: Emulator or Any device
- Android OS version: 7.1.1
- Google Play Services version: 124510001
- Firebase/Play Services SDK version: 15.0.0 or 12.0.1
Description of the problem:
Adding tools:node=»replace» to AndroidManifest Application tag as below
will cause the app never getting FirebaseInstanceIdService onTokenRefresh() callback.
I can manually call FirebaseInstanceId.getInstance().getToken() to get a token. But this token will never work. Using this token will give success result on first call, but from next call onwards it will give notRegistered error.
Steps to reproduce:
- Create any sample project with FCM messaging
- Just add tools:node=»replace» to application tag in AndroidManifest
- Build and install the app
Observed Results:
- onTokenRefresh never called. Manual call to getToken() will give a token, but will give notRegistered error all the time (except first time)
Expected Results:
- On every fresh install of the app, onTokenRefresh method of FirebaseInstanceIdService implementation will be called everytime and given token will work properly
Please look into this issue, since tools:node=»replace» is used widely for solving manifest merge issues.
Adding tools:node=»replace» to any manifest file (doesn’t need to be main manifest, it can be sub module manifest or library manifest) can cause the issue.
(PS: I was trying to migrate from GCM to FCM. And GCM was working for us, but for some users token was giving notRegistered error. I believe it is because of this.)
The text was updated successfully, but these errors were encountered:
Источник
Adding tools:node=»replace» to Android Manifest application tag causes FCM not working #477
Comments
sreejithbnaick commented Apr 25, 2018 •
Summary:
If I add tools:node=»replace» to AndroidManifest Application tag, Android App will never get
FirebaseInstanceIdService onTokenRefresh() callback and FCM doesn’t work.
Environment
- Android device: Emulator or Any device
- Android OS version: 7.1.1
- Google Play Services version: 124510001
- Firebase/Play Services SDK version: 15.0.0 or 12.0.1
Description of the problem:
Adding tools:node=»replace» to AndroidManifest Application tag as below
will cause the app never getting FirebaseInstanceIdService onTokenRefresh() callback.
I can manually call FirebaseInstanceId.getInstance().getToken() to get a token. But this token will never work. Using this token will give success result on first call, but from next call onwards it will give notRegistered error.
Steps to reproduce:
- Create any sample project with FCM messaging
- Just add tools:node=»replace» to application tag in AndroidManifest
- Build and install the app
Observed Results:
- onTokenRefresh never called. Manual call to getToken() will give a token, but will give notRegistered error all the time (except first time)
Expected Results:
- On every fresh install of the app, onTokenRefresh method of FirebaseInstanceIdService implementation will be called everytime and given token will work properly
Please look into this issue, since tools:node=»replace» is used widely for solving manifest merge issues.
Adding tools:node=»replace» to any manifest file (doesn’t need to be main manifest, it can be sub module manifest or library manifest) can cause the issue.
(PS: I was trying to migrate from GCM to FCM. And GCM was working for us, but for some users token was giving notRegistered error. I believe it is because of this.)
The text was updated successfully, but these errors were encountered:
Источник
Что делает атрибут tools: replace в файле манифеста Android?
Я нашел несколько вопросов об ошибках, связанных с tools:replace , но нигде в Интернете о том, что он делает.
Я нашел справочник по атрибутам инструментов, похоже, это устаревший атрибут это больше не документируется.
Может кто-нибудь объяснить, что он делает? Например, tools:replace=»android:label,android:supportsRtl,android:allowBackup»> находится как атрибут тега application . В том же теге application xml указаны android:label , android:supportsRtl и android:allowBackup , поэтому я могу только предположить , что он переопределит эти атрибуты если они указаны в тегах activity , вложенных в тег application . Эта функция может показаться бесполезной, поскольку я ожидал, что атрибуты application по умолчанию устанавливают свои дочерние атрибуты, если они не установлены.
Изменить: спасибо за ссылку на документы в своем ответе. Лично я считаю, что документация достаточно исчерпывающая, в ней даже приводятся примеры того, когда вы могли бы ее использовать. К сожалению, моя поисковая система не смогла найти это для меня. Эта ссылка была на самом деле первой в Google, но отсутствовала на DuckDuckGo .
1 ответ
tools:replace — это маркер атрибута, который можно использовать для перенастроить основной файл манифеста путем объединения определенных настроек манифеста из разновидностей (варианты сборки).
Допустим, у вас есть следующий узел в главном манифесте, где определенное действие определяется как экспортированное:
Но для определенного варианта (варианта сборки) одно и то же действие не следует экспортировать. Итак, вы определяете файл манифеста barebone в папке аромата и добавляете узел с атрибутом замены:
При выборе целевого варианта в Активном варианте сборки система сборки объединит оба манифеста и заменит в главном узле манифеста атрибут android:exported на атрибут.
Подводя итог, вы используете этот маркер атрибута, когда у вас есть несколько разновидностей проекта, и каждый должен определять разные атрибуты для существующих узлов, определенных в основном файле манифеста.
Обратите внимание, что вы также можете полностью заменить полный узел, добавив вместо него tools:node=»replace» .
Источник
Android Manifest merge conflict (backup rules) #9
Comments
ljwan12 commented Jan 14, 2020
tools:replace specified at line:20 for attribute android:fullBackupContent, but no new value specified
The text was updated successfully, but these errors were encountered:
ljwan12 commented Jan 14, 2020
|
Manifest merger failed : Attribute application@fullBackupContent value=(@xml/vungle_backup_rule) from [com.vungle:publisher-sdk-android:6.4.11] AndroidManifest.xml:19:9-60
is also present at [com.appsflyer:af-android-sdk:4.11.0] AndroidManifest.xml:14:18-73 value=(@xml/appsflyer_backup_rules).
Suggestion: add ‘tools:replace=»android:fullBackupContent»‘ to element at AndroidManifest.xml:19:5-95:19 to override.
elitvynov commented Apr 23, 2020
- What went wrong:
Execution failed for task ‘:android:processReleaseManifest’.
Manifest merger failed : Attribute application@fullBackupContent value=(@xml/vungle_backup_rule) from [com.vungle:publisher-sdk-android:6.4.11] AndroidManifest.xml:19:9-60
is also present at [com.appsflyer:af-android-sdk:4.11.0] AndroidManifest.xml:14:18-73 value=(@xml/appsflyer_backup_rules).
Suggestion: add ‘tools:replace=»android:fullBackupContent»‘ to element at AndroidManifest.xml:19:5-95:19 to override.
Did you find any solution? I have this problem too
elitvynov commented Apr 28, 2020
This is working, thank you
syrakozz commented May 3, 2020
but it takes forever while building
Cotel commented May 8, 2020
I’m having a similar issue 😢
In the main manifest allowBackup is set to false. The task is failing for a dynamic module.
ManakaMichihito commented May 14, 2020
I have the same problem.
fullBackupContent is not only used by AppsFlyer.
There is also a library that dynamically sets fullBackupContent just like AppsFlyer.
We cannot always do a manual merge.
lfg-ryan commented May 14, 2020
I have the same problem. Vungle is also using this and I can’t tell how to merge them in Unity when all of this is auto-generated stuff.
ManakaMichihito commented May 21, 2020
AppsFlyer support only answers manual merges, no matter how many times we explain it, it doesn’t fix the issue.
ManakaMichihito commented May 22, 2020 •
They don’t seem to present anything other than manually merging AndroidManifext.xml.
The answer was an inquiry to Unity technologies.
tools: replace = «android: fullBackupContent»
If there is a person to go and solve
Is required:
android:fullBackupContent=»true»
&
AppsFlyer’s FullBackup rules
(XML : full-backup-content tag)
They said:
«We have to do this in order to do the attribution and tracking accurately, if not, the reinstall will always retrieve the old install data which should be deleted.»
VladimirKuzmin-azur commented Jul 14, 2020 •
android:fullBackupContent=»@xml/appsflyer_backup_rules» tools:replace=»android:fullBackupContent
This works just fine for me. Mediation Debugger also shows that Vungle if fine. But I am little worried for Vungle backup-ing.
Could some android sensei tell if this is fine solution or not?
p.s. doing this from Unity’s main manifest
m-kul commented Jan 8, 2021
This is working, thank you
Can anybody clarify, in which manifest file we need to add this? I cannot find appsflyer’s manifest file.
af-vs commented Jan 14, 2021
We see that this issue is indeed confusing and would like to elaborate a bit extra on this matter.
TL;DR
- If you don’t wantAuto Backup — just set android:allowBackup=»false» in AndroidManifest and you are good to go
- If you wantAuto Backup — you have to:
- Manually merge backup rules from conflicting SDKs such as Vungle and AppsFlyer (there could be more) into your own XML file (e.g. @xml/merged_backup_rules ).
- Specify this file by setting 2 attributes in AndroidManifest:
- android:fullBackupContent=»@xml/merged_backup_rules» (to use your own rules)
- tools:replace=»android:fullBackupContent» (to give your rules higher priority than rules from any SDK) in AndroidManifest
Some background:
Since Android 6.0 (API level 23) Android has an Auto Backup feature that will back up the app’s data into Google Drive every now and then automatically. This is enabled by default but may cause problems to some service providers like AppsFlyer and Vungle. The reason is that we save some data into SharedPreferences which are being backed up by Android, but we don’t expect this data to retain between installs. If this data is restored after the user reinstalls the app, we may report attribution for this app incorrectly. I assume, Vungle SDK has some similar challenges.
Since AppsFlyer uses AAR to distribute the library, together with the library jar we package AndroidManifest in which we specify backup rules that are important for our SDK to function properly. Unfortunately, Android as of today doesn’t have a solid merge mechanism so in case you have 2 libraries with conflicting values for the same attribute in AndroidManifest you get different kinds of merging conflict errors.
The only solution we can see for now without harming other SDKs is to merge such conflicts manually
As a result you should have this file with merged rules:
Источник
Будущее внедрения зависимостей в Android
Предлагаю вашему вниманию перевод оригинальной статьи от Jamie Sanson
Создание Activity до Android 9 Pie
Внедрение зависимостей (DI) — это общая модель, по ряду причин используемая во всех формах разработки. Благодаря проекту Dagger, он взят в качестве шаблона, используемого в разработке для Android. Недавние изменения в Android 9 Pie привели к тому, что теперь у нас есть больше возможностей, когда речь идет о DI, особенно с новым классом AppComponentFactory .
DI очень важно, когда речь заходит о современной разработке Android. Это позволяет сократить общее количество кода при получении ссылок на сервисы, используемые между классами, и в целом хорошо разделяет приложение на компоненты. В этой статье мы сосредоточимся на Dagger 2, самой распространенной библиотеке DI, используемой в разработке Android. Предполагается, что вы уже обладаете базовыми знаниями о том, как это работает, но не обязательно понимать все тонкости. Стоит отметить, что эта статья — нечто вроде авантюры. Это интересно и всё, но на момент её написания Android 9 Pie даже не появлялся на панели версий платформы, поэтому, вероятно, данная тема не будет иметь отношения к повседневной разработке в течение как минимум нескольких лет.
Внедрение зависимостей в Android сегодня
Проще говоря, мы используем DI для предоставления экземпляров классов «зависимости» нашим зависимым классам, то есть тем, которые выполняют работу. Давайте предположим, что мы используем паттерн Репозиторий для обработки нашей логики, связанной с данными, и хотим использовать наш репозиторий в Activity для показа пользователю некоторых данных. Возможно, мы захотим использовать один и тот же репозиторий в нескольких местах, поэтому мы используем внедрение зависимостей, чтобы упростить совместное использование одного и того же экземпляра между кучей разных классов.
Для начала предоставим репозиторий. Мы определим функцию Provides в модуле, позволяющую Dagger знать, что это именно тот экземпляр, который мы хотим внедрить. Обратите внимание, что нашему репозиторию нужен экземпляр контекста для работы с файлами и сетью. Мы предоставим ему контекст приложения.
Теперь нам нужно определить Component для обработки внедрения классов, в которых мы хотим использовать наш Repository .
Наконец, мы можем настроить нашу Activity чтобы использовать наш репозиторий. Предположим, что мы создали экземпляр нашего ApplicationComponent где-то еще.
Вот и всё! Мы только что настроили внедрение зависимостей в рамках приложения с помощью Dagger. Есть несколько способов сделать это, но это кажется самым простым подходом.
Что не так с текущим подходом?
В приведенных выше примерах мы увидели два разных типа инъекций, один очевиднее другого.
Первый, который вы, возможно, пропустили, известен как внедрение в конструктор. Это метод предоставления зависимостей через конструктор класса, означающий, что класс, использующий зависимости, не имеет представления о происхождении экземпляров. Это считается самой чистой формой внедрения зависимостей, так как она прекрасно инкапсулирует нашу логику внедрения в наши классы Module . В нашем примере мы использовали этот подход для предоставления репозитория:
Для этого нужен был Context , который мы предоставили в функции provideApplicationContext() .
Второе, более очевидное, что мы увидели, это внедрение в поле класса. Этот метод использовался в нашей MainActivity для предоставления нашего хранилища. Здесь мы определяем поля как получателей инъекций, используя аннотацию Inject . Затем в нашей функции onCreate мы сообщаем ApplicationComponent что в наши поля надо инжектить зависимости. Выглядит не так чисто, как внедрение в конструктор, поскольку у нас есть явная ссылка на наш компонент, что означает, что концепция внедрения просачивается внутрь наших зависимых классов. Другой недостаток в классах Android Framework, так как мы должны быть уверены, что первое, что мы делаем — это предоставляем зависимости. Если это произойдёт не в той точке жизненного цикла, мы можем случайно попытаться использовать объект, который ещё не был инициализирован.
В идеале, следовало бы полностью избавиться от внедрений в поля класса. Такой подход пропускает информацию о внедрении в классы, которые не должны знать об этом, и потенциально может вызвать проблемы с жизненными циклами. Мы видели попытки сделать это лучше, и Dagger в Android — довольно надежный способ, но в конечном итоге было бы лучше, если бы мы могли просто использовать внедрение в конструктор. В настоящее время мы не можем использовать такой подход для ряда классов фреймворка, таких как «Activity», «Service», «Application» и т. д., поскольку они создаются для нас системой. Кажется, на данный момент мы застряли на внедрении в поля классов. Тем не менее, в Android 9 Pie готовится нечто интересное, что, возможно, в корне всё изменит.
Внедрение зависимостей в Android 9 Pie
Как уже упоминалось в начале статьи, в Android 9 Pie есть класс AppComponentFactory. Документация для него довольно скудная, и размещена просто на сайте разработчика как таковая:
Интерфейс, используемый для управления созданием элементов манифеста.
Это интригует. «Элементы манифеста» здесь относятся к классам, которые мы перечисляем в нашем файле AndroidManifest — таким как Activity, Service и наш Application класс. Это позволяет нам «контролировать создание» этих элементов… так, погодите, мы теперь можем установить правила для создания наших Activity? Прелесть какая!
Давайте копнём глубже. Мы начнём с расширения AppComponentFactory и переопределения метода instantiateActivity .
Теперь нам нужно объявить нашу фабрику компонентов в манифесте внутри тега application.
Наконец мы можем запустить наше приложение… и это работает! Наш NonContextRepository предоставляется через конструктор MainActivity. Изящно!
Обратите внимание, что здесь есть некоторые оговорки. Мы не можем использовать Context здесь, так как ещё до его существования происходит вызов нашей функции — это сбивает с толку! Мы можем пойти дальше, чтобы конструктор внедрил наш класс Application, но давайте посмотрим, как Dagger может сделать это еще проще.
Встречайте — Dagger Multi-Binds
Я не буду вдаваться в подробности работы множественного связывания Dagger под капотом, так как это выходит за пределы данной статьи. Всё, что вам нужно знать, — это то, что он обеспечивает хороший способ внедрения в конструктор класса без необходимости вызова конструктора вручную. Мы можем использовать это, чтобы легко внедрить классы фреймворка масштабируемым способом. Посмотрим, как всё это складывается.
Давайте сначала настроим нашу Activity, чтобы понять, что куда двигаться дальше.
Из этого сразу видно, что почти нет упоминаний о внедрении зависимостей. Единственное, что мы видим, — это аннотацию Inject перед конструктором.
Теперь необходимо изменить компонент и модуль Dagger:
Ничего особенного не изменилось. Теперь нам нужно только внедрить нашу фабрику компонентов, но как нам создать наши элементы манифеста? Здесь нам понадобится ComponentModule . Давайте посмотрим:
Ага, хорошо, всего лишь несколько аннотаций. Здесь мы связываем нашу Activity с мапой, внедряем эту мапу в наш класс ComponentHelper и предоставляем этот ComponentHelper — все в двух инструкциях Binds . Dagger знает, как создать экземпляр нашей MainActivity благодаря аннотации Inject поэтому может «привязать» провайдера к этому классу, автоматически предоставляя необходимые нам зависимости для конструктора. Наш ComponentHelper выглядит следующим образом.
Проще говоря, теперь у нас есть карта классов для поставщиков для этих классов. Когда мы пытаемся разрешить класс по имени, мы просто находим провайдера для этого класса (если он у нас есть), вызываем его, чтобы получить новый экземпляр этого класса, и возвращаем его.
Наконец, нам нужно внести изменения в наш AppComponentFactory чтобы использовать наш новый вспомогательный класс.
Запустите код еще раз. Это всё работает! Прелесть какая.
Проблемы внедрения в конструктор
Такой заголовок может выглядеть не очень впечатляющим. Хотя мы можем внедрить большинство экземпляров в обычном режиме с помощью внедрения в конструктор, у нас нет очевидного способа предоставления контекста для наших зависимостей стандартными способами. А ведь Context в Android — это всё. Он нужен для доступа к настройкам, сети, конфигурации приложения и многому другому. Нашими зависимостями часто являются вещи, которые используют связанные с данными службы, такие как сеть и настройки. Мы можем обойти это, переписав наши зависимости, чтобы они состояли из чистых функций, или инициализируя все с помощью экземпляров контекста в нашем классе Application , но для определения наилучшего способа сделать это требуется гораздо больше усилий.
Другим недостатком этого подхода является определение области видимости. В Dagger одной из ключевых концепций реализации высокопроизводительного внедрения зависимостей с хорошим разделением отношений между классами является модульность графа объекта и использование области видимости. Хотя этот подход не запрещает использование модулей, он ограничивает использование области видимости. AppComponentFactory существует на совершенно ином уровне абстракции относительно наших стандартных классов фреймворка — мы не можем получить ссылку на него программно, поэтому у нас нет способа дать ему указание предоставить зависимости для Activity в другой области видимости.
Существует множество способов решить наши проблемы с областями видимости на практике, одним из которых является использование FragmentFactory для внедрения наших фрагментов в конструктор с областями видимости. Я не буду вдаваться в подробности, но оказывается, что сейчас у нас есть метод управления созданием фрагментов, который не только дает нам гораздо большую свободу с точки зрения области видимости, но и обладает обратной совместимостью.
Заключение
В Android 9 Pie появился способ использования внедрения в конструктор для предоставления зависимостей в наших классах фреймворка, таких как «Activity» и «Application». Мы увидели, что с помощью Dagger Multi-binding мы можем с легкостью предоставлять зависимости на уровне приложения.
Конструктор, внедряющий все наши компоненты, чрезвычайно привлекателен, и мы можем даже сделать что-то, чтобы заставить его работать должным образом с экземплярами контекста. Это многообещающее будущее, но оно доступно только начиная с API 28. Если вы хотите охватить менее 0,5% пользователей — можете попробовать. В противном случае стоит подождать и посмотреть, останется ли такой способ актуальным через несколько лет.
Источник