Предисловие
Мне довольно часто задают этот вопрос:
Почему в моём приложении добавлены дополнительные разрешения в файл AndroidManifest.xml?
Многие разработчики уверены: эта проблема имеет какое-то отношение к Xamarin.Android, но они в действительности не представляют, что же на самом деле происходит со сторонними библиотеками и их приложениями.
Чтобы распутать этот клубок загадок, давайте сначала поговорим об общем процессе.
Как правило, если у Вас есть внешние библиотеки, то у них имеются собственные манифесты. И эти манифесты могут содержать различные элементы <uses-permission> или же они способны даже указывать их в AssemblyInfo.cs как на следующем примере:
1 | [assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)] |
В любом случае эти разрешения в конечном счёте будут выставляться в AndroidManifest.xml этой библиотеки, а по прошествии некоторого времени и в AndroidManifest.xml Вашего приложения.
Manifest Merging
Что на данный момент нам известно о разработке на Android? Ну, мы знаем, что каждый файл .apk может содержать только один определённый AndroidManifest.xml. Стало быть, в итоге всё требуется объединять в главную ветвь разработки — AndroidManifest.xml.
У каждого приложения в корневом каталоге должен быть файл AndroidManifest.xml (именно с таким именем). Файл манифеста обеспечивает систему Android важной информацией о приложении, ведь эти данные необходимы ей ещё до начала запуска любого его кода.
https://developer.android.com/guide/topics/manifest/manifest-intro.html
Отлично! Теперь мы продвинулись вперед ещё на один шаг, и сейчас можем понять немного о процессе сборки на Android. Однако, это приводит нас к одному вопросу… Осуществляет ли Xamarin.Android процесс сборки таким же образом, как нативный Android?
Ответ — нет. Они оба обладают собственными, уникальными процессами сборки, и, таким образом, не всё, что нам известно о нативном Android может быть конвертировано непосредственно в Xamarin.Android. В данном конкретном случае, если бы мы начали разбираться в том, как нативный Android объединяет несколько файлов манифеста, то обнаружили, что это делается с помощью Gradle, а не MSBuild, который используется в движке Xamarin.Android.
Пример
Давайте возьмём File -> New Blank Android Project. Затем рекомпилируем его с самого начала и посмотрим на окончательный AndroidManifest.xml. Мы найдём этот файл в obj\Debug\android\AndroidManifest.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="IDontWantYourPermission.IDontWantYourPermission" android:versionCode="1" android:versionName="1.0"> <!--suppress UsesMinSdkAttributes--> <uses-sdk android:minSdkVersion="16" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:label="IDontWantYourPermission" android:name="android.app.Application" android:allowBackup="true" android:icon="@drawable/icon" android:debuggable="true"> <activity android:icon="@drawable/icon" android:label="IDontWantYourPermission" android:name="md5bdb5a298d3d71fd07b60a60955b14ddd.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="2147483647" android:authorities="IDontWantYourPermission.IDontWantYourPermission.mono.MonoRuntimeProvider.__mono_init__" /> <!--suppress ExportedReceiver--> <receiver android:name="mono.android.Seppuku"> <intent-filter> <action android:name="mono.android.intent.action.SEPPUKU" /> <category android:name="mono.android.intent.category.SEPPUKU.IDontWantYourPermission.IDontWantYourPermission" /> </intent-filter> </receiver> </application> </manifest> |
Как мы можем видеть, по умолчанию только два разрешения добавляются в Debug configuration:
1 2 | <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
Как бы то ни было, давайте теперь добавим пакет NuGet, который, по нашему убеждению, запускает в проект нежелательные разрешения. Для этого примера я собираюсь использовать плагин Джеймса Монтемагно http://www.nuget.org/packages/Xam.Plugin.Geolocator
После того как он будет добавлен, рекомпилируйте решение и изучите новый obj\Debug\android\AndroidManifest.xml:
1 2 | <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
Так что, несомненно, мы бы никогда не узнали о том, что объекты были добавлены в наш проект, если не рассмотрели сгенерированный в итоге AndroidManifest.xml.
Отлично… Но это не поможет мне понять, откуда приходит разрешение, если мой проект огромен!
Справедливо. Давайте подумаем, что мы можем сделать, чтобы облегчить нашу задачу.
Вот ряд способов, посредством которых можно вычислить эту информацию:
1) Провести поиск среди всех сторонних зависимых объектов с помощью декомпилятора, такого как dotPeek, и просмотреть информацию сборки на предмет того, происходит ли добавление разрешения.
Пример: (Использование dotPeek)
2) Используйте инструмент grep для поиска следующих строк в коде uses-permission и UsesPermission.
Пример: (Использование grepWin — https://sourceforge.net/projects/grepwin/files/)
Автор: Jon Douglas
Источник: Статья в блоге автора
Написать ответ