Я создал проект в Xamarin с помощью Visual Studio Professional 2017, проект очищается/собирается/компилируется в обычном режиме и устанавливается на Android 7.0, 7.1, 8.0, 8.1 и 9.0 (эмулятор и устройства).
Однако не устанавливайте/создавайте на Android 6.0 и 6.1 (эмулятор или устройство), я пытаюсь установить в эмуляторе и на устройстве, выдает ошибку:
1>C:\Program Files\Android\jdk\microsoft_dist_openjdk_1.8.0.25\\bin\keytool.exe -list -alias androiddebugkey -storepass android -keypass android -keystore "C:\Users\Claudio\AppData\Local\Xamarin\Mono for Android\debug.keystore"
1>C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\zipalign.exe 4 "C:\Workspace\htdocs\Projetos\aprepara-xamarin-raksha\Ishpia.Droid\obj\Debug\81\android\bin\com.bergmannsoft.aprepara.apk" "bin\Debug\\com.bergmannsoft.aprepara-Signed.apk"
1>C:\Program Files\Android\jdk\microsoft_dist_openjdk_1.8.0.25\\bin\java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar" sign --ks "C:\Users\Claudio\AppData\Local\Xamarin\Mono for Android\debug.keystore" --ks-pass pass:android --ks-key-alias androiddebugkey --key-pass pass:android --min-sdk-version 22 --max-sdk-version 27 C:\Workspace\htdocs\Projetos\aprepara-xamarin-raksha\Ishpia.Droid\bin\Debug\com.bergmannsoft.aprepara-Signed.apk
1>ADB0000: Deployment failed
1>Mono.AndroidTools.InstallFailedException: Unexpected install output: pkg: /data/local/tmp/com.bergmannsoft.aprepara-Signed.apk
1>Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED]
1>
1> em Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) na E:\A\_work\1824\s\External\androidtools\Mono.AndroidTools\Internal\AdbOutputParsing.cs:linha 345
1> em Mono.AndroidTools.AndroidDevice.<>c__DisplayClass95_0.<InstallPackage>b__0(Task`1 t) na E:\A\_work\1824\s\External\androidtools\Mono.AndroidTools\AndroidDevice.cs:linha 753
1> em System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
1> em System.Threading.Tasks.Task.Execute()
1>ADB0010: Unexpected install output: pkg: /data/local/tmp/com.bergmannsoft.aprepara-Signed.apk
1>Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED]
1>
1> em Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) na E:\A\_work\1824\s\External\androidtools\Mono.AndroidTools\Internal\AdbOutputParsing.cs:linha 345
1> em Mono.AndroidTools.AndroidDevice.<>c__DisplayClass95_0.<InstallPackage>b__0(Task`1 t) na E:\A\_work\1824\s\External\androidtools\Mono.AndroidTools\AndroidDevice.cs:linha 753
1> em System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
1> em System.Threading.Tasks.Task.Execute()
1>Projeto de compilação pronto "Ishpia.Droid.csproj" -- FALHA.
1>FALHA da compilação.
1>Deployment failed to nexus_5x_api_23.
========== Compilar: 0 com êxito, 0 com falha, 2 atualizados, 0 ignorados ==========
========== Implantação: 0 com êxito, 1 com falha, 0 ignorados ==========
Уже чистил, много раз удалял папки "bin" и "obj", чистил кеши пакетов, nuget и всегда показывает ошибку.
Может ли кто-нибудь помочь мне понять, почему ошибка возникает только в Android 6.0/6.1?
Мой манифест:
<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android" android:versionCode = "150" android:versionName = "3.2" package = "com.bergmannsoft.aprepara" android:installLocation = "auto">
<uses-sdk android:minSdkVersion = "22" android:targetSdkVersion = "27" />
<!-- Google Maps for Android v2 requires OpenGL ES v2 -->
<uses-feature android:glEsVersion = "0x00020000" android:required = "true" />
<!-- We need to be able to download map tiles and access Google Play Services-->
<uses-permission android:name = "android.permission.INTERNET" android:required = "true" />
<uses-permission android:name = "android.permission.CAMERA" android:required = "true" />
<!-- Allow the application to access Google web-based services. -->
<uses-permission android:name = "com.google.android.providers.gsf.permission.READ_GSERVICES" />
<!-- Google Maps for Android v2 will cache map tiles on external storage -->
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" android:required = "true" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" android:required = "true" />
<!-- Google Maps for Android v2 needs this permission so that it may check the connection state as it must download data -->
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" android:required = "true" />
<!-- These are optional, but recommended. They will allow Maps to use the My Location provider. -->
<uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" android:required = "true" />
<!-- Outras permissoes-->
<uses-permission android:name = "android.permission.CALL_PHONE" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" android:required = "true" />
<!-- Permission to receive remote notifications from Google Play Services -->
<!-- Notice here that we have the package name of our application as a prefix on the permissions. -->
<uses-permission android:name = "com.bergmannsoft.aprepara.permission.MAPS_RECEIVE" android:required = "true" />
<uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" android:required = "true" />
<uses-permission android:name = "android.permission.READ_USER_DICTIONARY" android:required = "true" />
<!-- GCM-->
<uses-permission android:name = "com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name = "android.permission.WAKE_LOCK" />
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<uses-permission android:name = "com.bergmannsoft.aprepara.permission.C2D_MESSAGE" />
<permission android:name = "com.bergmannsoft.aprepara.permission.C2D_MESSAGE" android:protectionLevel = "signature" />
<!-- BOOT -->
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- MAP-->
<permission android:name = "com.bergmannsoft.aprepara.permission.MAPS_RECEIVE" android:protectionLevel = "signature" />
<!-- Declaring Service in Manifest -->
<service android:name = "Ishpia.Droid.Activities.Services.Order.PostService" android:exported = "false" />
<service android:name = "Ishpia.Droid.Activities.Services.Order.OrderService" android:exported = "false" />
<service android:name = "Ishpia.Droid.Activities.Services.Periodic.PeriodicService" android:exported = "false" />
<!-- APLICATION -->
<application android:allowBackup = "true" android:label = "@string/app_title" android:icon = "@mipmap/icon" android:roundIcon = "@mipmap/icon_round" android:largeHeap = "true" android:supportsRtl = "true" android:theme = "@style/AppTheme.NoActionBarNotExtended">
<!-- Put your Google Maps V2 API Key here. -->
<meta-data android:name = "com.google.android.geo.API_KEY" android:value = "XXXXXXXXXXXXXXXXXXXXX" />
<meta-data android:name = "com.google.android.gms.version" android:value = "@integer/google_play_services_version" />
<!-- FCM/GCM -->
<meta-data android:name = "com.google.firebase.messaging.default_notification_icon" android:resource = "@drawable/ic_stat_ic_notification" />
<meta-data android:name = "com.google.firebase.messaging.default_notification_color" android:resource = "@color/background" />
<!-- [END fcm_default_icon] -->
<receiver android:name = "com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported = "false" />
<receiver android:name = "com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported = "true" android:permission = "com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name = "com.google.android.c2dm.intent.RECEIVE" />
<action android:name = "com.google.android.c2dm.intent.REGISTRATION" />
<category android:name = "${applicationId}" />
</intent-filter>
</receiver>
<!-- BOOT DEVICE -->
<receiver android:name = "Ishpia.Droid.Activities.Services.Boot.BootReceiver" android:enabled = "true" android:permission = "android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
<category android:name = "android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- FILE PROVIDER -->
<provider android:name = "android.support.v4.content.FileProvider" android:grantUriPermissions = "true" android:exported = "false" android:authorities = "${applicationId}.fileprovider">
<meta-data android:name = "android.support.FILE_PROVIDER_PATHS" android:resource = "@xml/file_provider_paths" />
</provider>
</application>
</manifest>
@SushiHangover Спасибо, Android Lint — хороший инструмент, который помог мне найти решение.
Рад, что помог ?




Ошибка гласит, что у вас искаженный манифест:
"INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"
Если я попытаюсь загрузить ваш манифест в Chrome, там тоже возникнет ошибка.
Для этого комментария нет закрывающего тега:
<!-- Set color used with incoming notification messages. This is used when no
Я считаю, что это может быть ваша проблема.
Если это так, интересно, что другие версии Android игнорируют эту ошибку форматирования XML.
Я протестировал xml в Chrome и не обнаружил ошибок формата. Судя по всему, с xml все в порядке, и приложение нормально устанавливается на Android 7/8/9. Ошибка возникает только в Android 6.0
Если я вырезаю и вставляю ваш точный манифест из этого поста, сохраняю его как файл XML и загружаю в Chrome, возникает ошибка. Я предполагаю, что ваш манифест отличается от того, который вы опубликовали. На самом деле, я уверен, что это потому, что я вижу, что вы изменили значение API_KEY на "XXXXXXXXXXXXXXXXXXXXXXXX". И я предполагаю, что вы, вероятно, случайно удалили конечный тег комментария в той строке, которую я цитировал. Если у вас нет закрывающего тега комментария в этой строке «Установить цвет ...» в вашем фактическом манифесте, добавьте его и повторите попытку установки.
Вы правы, я отредактировал значение ключа и удалил часть кода. Извиняюсь.
Честно говоря, эта проблема меня очень смущала. Однако Роберт Брюс (@6157192) был прав, проблема была в Manifest.xml, а не в конфигурации Manifest.Xml, в Manifest.Xml, сгенерированном после сборки.
Я опишу шаги по поиску наилучшего для меня «решения»:
1. Я запускал Android Lint (@SushiHangover / @4984832) несколько раз, внося необходимые коррективы, просматривая и очищая основной Manifest.xml.
C:\Workspace\Android\sdk\tools\bin>lint.bat C:\Workspace\htdocs\Projetos\aprepara-xamarin-raksha\Ishpia.Droid\
2. Очищен, перекомпилирован и развернут с помощью Visual Studio 2017 и Androi Emulator Nexus 5x (API 23).
Очевидно, произошла ошибка, однако, если вы посмотрите на вывод терминала, он генерирует apk для установки.
C:\Program Files\Android\jdk\microsoft_dist_openjdk_1.8.0.25\\bin\java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools\27.0.3\lib\apksigner.jar" sign --ks "C:\Users\Claudio\AppData\Local\Xamarin\Mono for Android\debug.keystore" --ks-pass pass:android --ks-key-alias androiddebugkey --key-pass pass:android --min-sdk-version 22 --max-sdk-version 27 C:\Workspace\htdocs\Projetos\aprepara-xamarin-raksha\Ishpia.Droid\bin\Debug\ **com.bergmannsoft.aprepara-Signed.apk**
com.bergmannsoft.aprepara-Signed.apk
3. Используя апканализатор в win, я экспортировал сгенерированный manifest.xml после компиляции.
apkanalyzer.cmd manifest print C:\Workspace\htdocs\Projetos\aprepara-xamarin-raksha\Ishpia.Droid\bin\Debug\com.bergmannsoft.aprepara-Signed.apk > android.xml
Теперь игра была веселой, потому что после нескольких дней просмотра и переделки Manifest.xml я обнаружил, что ошибка была в Manifest.xml, сгенерированном после компиляции, потому что в зависимости от реализации его сорт, Xamarin (не уверен, что это просто Xamarin) будет манипулировать XML и добавлять другую информацию.
И ошибка была на самом деле в Manifest.xml, а не в том, что редактировалось, в сгенерированном после компиляции.
Разрешения и классы Boot Receiver генерировались дважды.
4. Теперь, когда я наконец нашел, где была ошибка, мы вернулись к тестам.. тестам.. тестам.. множеству тестов.
ТЕСТ А (НЕУДАЧА):
Удалив классы атрибутов, которые манипулировали Manifest.xml и выдавали ошибку, и поместив все имена пакетов в «Манифест» в нижнем регистре, приложение было правильно установлено на Android 6.0 и других версиях (7.8 и 9).
<!-- BOOT DEVICE -->
<receiver android:name = "ishpia.droid.activities.services.boot.bootreceiver" android:enabled = "true" android:permission = "android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name = "android.intent.action.BOOT_COMPLETED" />
<category android:name = "android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- SERVICE -->
<service android:name = "ishpia.droid.activities.services.order.postdervice" android:exported = "false" />
<service android:name = "ishpia.droid.activities.services.order.orderservice" android:exported = "false" />
<service android:name = "ishpia.droid.activities.services.periodic.periodicservice" android:exported = "false" />
Но это породило новую проблему, потому что в некоторых реальных устройствах (не во всех, всего в нескольких моделях) возникала ошибка:
Fatal Exception: java.lang.RuntimeException: Unable to instantiate receiver ishpia.droid.activities.services.boot.bootreceiver: java.lang.ClassNotFoundException: Didn't find class "ishpia.droid.activities.services.boot.bootreceiver" on path: DexPathList[[zip file "/data/app/com.bergmannsoft.aprepara-x12fO8j-m_szPmi4Kc9Kyg==/base.apk"],nativeLibraryDirectories=[/data/app/com.bergmannsoft.aprepara-x12fO8j-m_szPmi4Kc9Kyg==/lib/arm, /data/app/com.bergmannsoft.aprepara-x12fO8j-m_szPmi4Kc9Kyg==/base.apk!/lib/armeabi-v7a, /system/lib, /system/vendor/lib]]
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3374)
at android.app.ActivityThread.-wrap18(Unknown Source)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1807)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
Видимо некоторые устройства не нашли класс BootReceiver.
ТЕСТ B (НЕУДАЧА):
Размещение имен классов в Manifest.xml с заглавной буквы работало в версиях (7,8 и 9), кроме версии Android 6. Собственно, не в состоянии понять, почему ошибка возникает только в версии 6.
<!-- BOOT DEVICE -->
<receiver android:name = "Ishpia.Droid.Activities.Services.Boot.Bootreceiver" android:enabled = "true" android:permission = "android.permission.RECEIVE_BOOT_COMPLETED">
..
</receiver>
ТЕСТ N (на данный момент все в порядке):
Это было лучшее решение, которое я нашел для своего приложения.
Удалите все службы и приемник из Manifest.xml, таким образом:
<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:tools = "http://schemas.android.com/tools"
tools:ignore = "GoogleAppIndexingWarning"
android:versionCode = "152"
android:versionName = "3.2"
package = "com.bergmannsoft.aprepara"
android:installLocation = "auto">
<uses-sdk android:minSdkVersion = "22" android:targetSdkVersion = "27" />
<!-- Google Maps for Android v2 requires OpenGL ES v2 -->
<uses-feature android:glEsVersion = "0x00020000" android:required = "true" />
<!-- USER PERMISSION-->
<uses-permission android:name = "android.permission.INTERNET" android:required = "true" />
<uses-permission android:name = "android.permission.CAMERA" android:required = "true" />
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" android:required = "true" />
<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" android:required = "true" />
<uses-permission android:name = "android.permission.CALL_PHONE" android:required = "true" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" android:required = "true" />
<uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" android:required = "true" />
<uses-permission android:name = "android.permission.READ_USER_DICTIONARY" android:required = "true" />
<uses-permission android:name = "android.permission.WAKE_LOCK" />
<uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<!-- PERMISSION-->
<uses-permission android:name = "com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name = "com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name = "com.bergmannsoft.aprepara.permission.MAPS_RECEIVE" android:required = "true" />
<uses-permission android:name = "com.bergmannsoft.aprepara.permission.C2D_MESSAGE" />
<permission android:name = "com.bergmannsoft.aprepara.permission.MAPS_RECEIVE" android:protectionLevel = "signature" />
<permission android:name = "com.bergmannsoft.aprepara.permission.C2D_MESSAGE" android:protectionLevel = "signature" />
<!-- APLICATION -->
<application android:allowBackup = "false" android:label = "@string/app_title" android:icon = "@mipmap/icon" android:roundIcon = "@mipmap/icon_round" android:largeHeap = "true" android:supportsRtl = "true" android:theme = "@style/AppTheme.NoActionBarNotExtended">
<!-- Put your Google Maps V2 API Key here. -->
<meta-data android:name = "com.google.android.geo.API_KEY" android:value = "XXXXXXXXXXXXXXX" />
<meta-data android:name = "com.google.android.gms.version" android:value = "@integer/google_play_services_version" />
<!-- FCM/GCM -->
<meta-data android:name = "com.google.firebase.messaging.default_notification_icon" android:resource = "@drawable/ic_stat_ic_notification" />
<meta-data android:name = "com.google.firebase.messaging.default_notification_color" android:resource = "@color/background" />
<receiver android:name = "com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported = "false" />
<receiver android:name = "com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported = "true" android:permission = "com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name = "com.google.android.c2dm.intent.RECEIVE" />
<action android:name = "com.google.android.c2dm.intent.REGISTRATION" />
<category android:name = "${applicationId}" />
</intent-filter>
</receiver>
<!-- FILE PROVIDER -->
<provider android:name = "android.support.v4.content.FileProvider" android:grantUriPermissions = "true" android:exported = "false" android:authorities = "${applicationId}.fileprovider">
<meta-data android:name = "android.support.FILE_PROVIDER_PATHS" android:resource = "@xml/file_provider_paths" />
</provider>
</application>
</manifest>
И вставляйте атрибуты непосредственно в классы Xamarin (после того, как xamarin вставит их в манифест во время компиляции).
Широковещательный приемник
namespace Ishpia.Droid.Activities.Services.Boot
{
[BroadcastReceiver(Enabled = true, Exported = false, Permission = "android.permission.RECEIVE_BOOT_COMPLETED")]
[IntentFilter(new[] { Intent.ActionBootCompleted }, Priority = (int)IntentFilterPriority.LowPriority, Categories = new[] { Intent.CategoryDefault })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent i = new Intent(context, typeof(SplashActivity));
i.AddFlags(ActivityFlags.NewTask);
context.StartActivity(i);
}
}
}
ЗаказСервис
namespace Ishpia.Droid.Activities.Services.Order
{
[Service (Exported = false)]
public class OrderService : IntentService
{
...
}
}
Постсервис
namespace Ishpia.Droid.Activities.Services.Order
{
[Service(Exported = false)]
class PostService : IntentService
{
..
}
}
периодическая служба
namespace Ishpia.Droid.Activities.Services.Periodic
{
[Service(Exported = false)]
class PeriodicService : Service
{
...
}
}
Xamarin экспортирует Manifest.xml после компиляции:
<service
android:name = "md556d51780b7ddda82c5xxxxxxxxxxxxx.RegistrationIntentService"
android:exported = "false" />
<service
android:name = "md527cd63edec29ae2b7xxxxxxxxxxxxx.PeriodicService"
android:exported = "false" />
<service
android:name = "md51a4cc6308c061c7f0xxxxxxxxxxxxx.OrderService"
android:exported = "false" />
<service
android:name = "md51a4cc6308c061c7fxxxxxxxxxxxxx.PostService"
android:exported = "false" />
<receiver
android:name = "md53c9e18cf96d129xxxxxxxxxxxxx.BootReceiver"
android:permission = "android.permission.RECEIVE_BOOT_COMPLETED"
android:enabled = "true"
android:exported = "false">
<intent-filter
android:priority = "-1000">
<action
android:name = "android.intent.action.BOOT_COMPLETED" />
<category
android:name = "android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Это были шаги, предпринятые в моем приложении для решения возникшей проблемы, я думаю, что это непростая проблема. Возможно, мне не хватало опыта работы с Xamarin, но я добавляю свое решение на случай, если смогу помочь другим людям.
Вы можете найти файл AndroidManifest.xml в папке project/obj/Debug/xxx/android. Это должно сохранить шаг извлечения манифеста из apk.
Я часами ломал голову над приложением, которое отлично работает на Android 8+, но отказывалось устанавливать его на что-то ниже.
Утилита Android lint также не сделала меня мудрее, поскольку сообщила, что ошибок не было.
В конце концов проблема оказалась в названии действия, начинающемся с прописной буквы.
К сожалению, только эмулятор Android 7.0 дал мне достойное описание ошибки (с указанием строки в файле манифеста и атрибута)
Эмулятор Android 6.0 выдал мне общую ошибку, как упоминалось в ОП.
Я понимаю ваше разочарование, я также потратил несколько часов, чтобы найти причину ошибки. Иногда это очень скучно и разочарование.
Вы можете использовать Android
lintдля проверки своего манифеста, он уже установлен как часть инструментов Android и его можно найти по адресуtools/bin. Он сообщил о нескольких ошибках/предупреждениях в вашем манифесте: сайты.google.com/a/android.com/tools/tips/lint.