Xamarin.Android
Publicera din Xamarin.Android APK
Sök…
Introduktion
Det här ämnet visar information om hur du förbereder din Xamarin.Android-app för släppläge och hur du optimerar den.
Förbereda din APK i Visual Studio
Du har slutfört din app, testat i felsökningsläge och den fungerar perfekt. Nu vill du förbereda den för att publiceras i Google Play Store.
Xamarin dokumentation ger bra information här:
Android manifest
Högerklicka på ditt Xamarin.Android-projekt i Solution Explorer först i Visual Studio och välj Egenskaper. Gå sedan till fliken Android Manifest för att se den här skärmen:
Till skillnad från i Android Studio eller Eclipse, behöver du inte ställa in filen AndroidManifest.xml genom att skriva; Xamarin och Visual Studio gör det åt dig. Aktiviteter, BroadcastReceivers och Services införs i Android Manifest genom att deklarera specifika attribut i sina klasser .
På den här skärmen är alternativen:
- Programnamn : Detta är appnamnet som kommer att vara synligt för användaren.
- Paketnamn : Detta är paketnamnet. Det måste vara unikt, vilket innebär att det inte får använda samma paketnamn för andra appar i Google Play Store.
- Programikon : Det här är den ikon som kommer att vara synlig för användaren, motsvarande @ drawable / ic_launcher som används i Android Studio eller Eclipse-projekt.
- Versionsnummer : Versionsnumret används av Google Play för versionskontroll. När du vill publicera en APK för en uppdaterad version av din app, måste du lägga till 1 till detta nummer för varje ny uppgradering.
- Versionsnamn : Detta är det versionnamn som visas för användaren.
- Installera plats : Detta avgör var din APK kommer att installeras, i enhetslagring eller SD-kort.
- Obligatoriska behörigheter : Här avgör du vilka behörigheter som är nödvändiga för din app.
Android-alternativ
På skärmen nedan kan du konfigurera kompilatoralternativen. Om du använder rätt alternativ här kan du minska APK-storleken mycket och även förhindra fel.
- Konfiguration : Aktiv (släpp) .
- Plattform : Aktiv (valfri CPU) . Dessa är nödvändiga för att bygga din APK för Google Play Store. Om konfigurationen är inställd på Debug accepteras den inte av Google Play.
- Använd Shared Runtime : false . Om du ställer in det till sant kommer APK att använda Mono Runtime för att köra. Mono Runtime installeras automatiskt vid felsökning via USB, men inte i Release APK. Om Mono Runtime inte är installerat i enheten och detta alternativ är inställt på true i Release APK kommer appen att krascha.
- Generera ett paket (.apk) per vald ABI : falsk . Skapa din APK för så många plattformar som möjligt av kompatibilitetsskäl.
- Aktivera Multi-Dex : sant , men du kan ställa in den till falsk om din app inte är särskilt komplex (det vill säga har mindre än 65536 metoder, se här ).
- Aktivera Proguard : true . Detta möjliggör Proguard-verktyget som döljer Java-kod i din app. Observera att den inte gäller .NET-kod; Om du vill dölja .NET-kod måste du använda Dotfuscator . Mer information om Proguard för Xamarin.Android kan hittas här .
- Aktivera utvecklarinstrumentation (felsökning och profilering) : falskt för release APK.
- Länkning : SDK och användarförsamlingar . Detta gör att Xamarin Linker tar bort alla oanvända klasser från SDK och din kod, vilket minskar APK-storleken.
Viktig
Xamarin.Linker kan ibland ta bort klasser som inte tycks användas av din kod, särskilt om de finns i projektets Core (PCL-bibliotek). För att undvika det kan du antingen ställa in länken till "Sdk Assemblies Only" eller använda attributet Bevara i dina klasser, exempel:
PreserveAttribute.cs
namespace My_App_Core.Models
{
public sealed class PreserveAttribute : System.Attribute
{
public bool AllMembers;
public bool Conditional;
}
}
I en klass:
using System;
namespace My_App_Core.Models
{
[Preserve(AllMembers = true)]
public class ServiceException : Exception
{
public int errorCode;
[Preserve(AllMembers = true)]
public ServiceException() { }
[Preserve(AllMembers = true)]
public ServiceException(int errorCode)
{
this.errorCode = errorCode;
}
}
}
- Arkitekturer som stöds : Välj alla av kompatibilitetsskäl.
När du har konfigurerat allt, bygga om projektet igen för att se till att det bygger framgångsrikt.
Skapa APK för släppläge
Du är klar med att konfigurera ditt Android-projekt för release. Handledningen nedan visar hur man genererar APK i Visual Studio. En fullständig handledning från Xamarin-dokumentation kan hittas här:
För att skapa APK-filen, högerklicka på Xamarin.Android-projektet i Lösningsutforskaren och välj Arkiv ...
Detta öppnar arkivhanteraren och börjar arkivera projektet och förbereder sig för att skapa APK-filen.
När det är klart arkivering av projektet klickar du på Distribuera ... för att fortsätta.
Skärmen Distribuera visar två alternativ: Ad-hoc och Google Play. Den första skapar en APK och sparar den på din dator. Den andra publicerar appen direkt i Google Play.
Att välja det första rekommenderas, så att du kan testa APK på andra enheter om du vill.
På följande skärm behövs en Android Key Store för att signera APK. Om du redan har en kan du använda den genom att klicka på Importera ...; Om du inte gör det kan du skapa en ny Android Key Store genom att klicka i +.
Skapa en ny skärm för Android Key Store:
För att skapa APK klickar du på Spara som. Du kan bli ombedd att skriva in Key Store-lösenordet.
När det är klart kan du klicka i Öppna mapp på arkivskärmen för att se din genererade APK-fil.
Aktivera MultiDex i din Xamarin.Android APK
MultiDex är ett bibliotek i Android APK som gör att appen kan ha mer än 65 536 metoder.
Android-APK: erna har Dalvik Exekverbara filer (.dex) som innehåller de genererade bytekoder som kompilerats från din Java-kod. Varje .dex-fil kan innehålla upp till 65 536 metoder (2 ^ 16).
Android OS-versioner före Android 5.0 Lollipop (API 21) använder Dalvik-runtime, som bara stöder en .dex-fil per APK, begränsande till 65 536 metoder per APK. Från och med Android 5.0 använder Android OS ART-runtime, som kan stödja mer än en .dex-fil per APK, så att gränsen undviks.
För att överträffa 65k-metodgränsen i Android-versioner under API 21 måste utvecklarna använda MultiDex-supportbiblioteket. MultiDex skapar extra klasser.dex-filer (klasser2.dex, klasser3.dex, ...) som refererar till dem i klassen.dex-filen. När appen börjar laddas använder den en MultiDexApplication-klass för att ladda de extra .dex-filerna.
Om din Android-app siktar på en minsta SDK-version över eller lika med API 21 (Android 5.0 Lollipop) är det inte nödvändigt att använda MultiDex-biblioteket, eftersom OS hanterar naturligtvis de extra .dex-filerna. Om utvecklaren av kompatibilitetsskäl vill stödja äldre Android OS bör han / hon dock använda MultiDex-biblioteket.
Hur man använder MultiDex i din Xamarin.Android-app
Först att aktivera MultiDex i din Xamarin.Android-app, gå till projektets Egenskaper -> Android-alternativ -> Förpackning -> Aktivera Multi-Dex, som på utskriftsskärmen nedan:
Sedan måste du skapa en MultiDexApplication-klass i din app. I projektets rot skapar du en ny klass (i Solution Explorer högerklickar du i projektet, Lägg till .. -> Klass eller Shift + Alt + C). I den nya klassfilen kopierar du följande kod och ersätter namnsytansprovet med namnet på ditt Xamarin.Android-projektets namnutrymme.
using System;
using Android.App;
using Android.Runtime;
using Java.Interop;
namespace Sample
{
[Register("android/support/multidex/MultiDexApplication", DoNotGenerateAcw = true)]
public class MultiDexApplication : Application
{
internal static readonly JniPeerMembers _members =
new XAPeerMembers("android/support/multidex/MultiDexApplication", typeof (MultiDexApplication));
internal static IntPtr java_class_handle;
private static IntPtr id_ctor;
[Register(".ctor", "()V", "", DoNotGenerateAcw = true)]
public MultiDexApplication()
: base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
{
if (Handle != IntPtr.Zero)
return;
try
{
if (GetType() != typeof (MultiDexApplication))
{
SetHandle(
JNIEnv.StartCreateInstance(GetType(), "()V"),
JniHandleOwnership.TransferLocalRef);
JNIEnv.FinishCreateInstance(Handle, "()V");
return;
}
if (id_ctor == IntPtr.Zero)
id_ctor = JNIEnv.GetMethodID(class_ref, "<init>", "()V");
SetHandle(
JNIEnv.StartCreateInstance(class_ref, id_ctor),
JniHandleOwnership.TransferLocalRef);
JNIEnv.FinishCreateInstance(Handle, class_ref, id_ctor);
}
finally
{
}
}
protected MultiDexApplication(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
internal static IntPtr class_ref
{
get { return JNIEnv.FindClass("android/support/multidex/MultiDexApplication", ref java_class_handle); }
}
protected override IntPtr ThresholdClass
{
get { return class_ref; }
}
protected override Type ThresholdType
{
get { return typeof (MultiDexApplication); }
}
}
}
Om du utvecklar i Visual Studio för Windows finns det också ett fel i Android SDK-byggverktygen som du behöver fixa för att ordentligt skapa klasserna.de-filer när du bygger ditt projekt.
Gå till din Android SDK-mapp, öppna mappen build-tools så kommer det att finnas mappar med antalet Android SDK-kompilatorer, till exempel:
C: \ android-sdk \ build-verktyg \ 23.0.3 \
C: \ android-sdk \ build-verktyg \ 24.0.1 \
C: \ android-sdk \ build-verktyg \ 25.0.2 \
Inuti var och en av dessa mappar finns det en fil som heter mainClassesDex.bat , ett batchskript som används för att skapa klassen.dex-filer. Öppna varje mainClassesDex.bat-fil med en textredigerare (Notepad eller Notepad ++) och i dess skript, hitta och ersätt blocket:
if DEFINED output goto redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder "%disableKeepAnnotated%" "%tmpJar%" "%params%"
goto afterClassReferenceListBuilder
:redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder "%disableKeepAnnotated%" "%tmpJar%" "%params%" 1>"%output%"
:afterClassReferenceListBuilder
Med blocket:
SET params=%params:'=%
if DEFINED output goto redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder %disableKeepAnnotated% "%tmpJar%" %params%
goto afterClassReferenceListBuilder
:redirect
call "%java_exe%" -Djava.ext.dirs="%frameworkdir%" com.android.multidex.MainDexListBuilder %disableKeepAnnotated% "%tmpJar%" %params% 1>"%output%"
:afterClassReferenceListBuilder
Spara varje mainClassesDex.bat i textredigeraren efter ändringar.
Efter stegen ovan bör du kunna bygga din Xamarin.Android-app med MultiDex.
Aktivera ProGuard i din Xamarin.Android APK
ProGuard är ett verktyg som används i byggprocessen för att optimera och dölja Java-koden för din APK, och även ta bort oanvända klasser. Den resulterande APK när du använder ProGuard kommer att ha en mindre storlek och kommer att vara svårare att bakåt konstruera (dekompilering).
ProGuard kan också användas i Xamarin.Android-appar och kommer också att minska APK-filstorleken och dölja Java-koden. Tänk dock på att ProGuard-obfuskningen endast gäller Java-kod. För att dölja .NET-kod bör utvecklaren använda Dotfuscator eller liknande verktyg.
Hur man använder ProGuard i din Xamarin.Android-app
Först, för att aktivera ProGuard i din Xamarin.Android-app, gå till projektets Egenskaper -> Android-alternativ -> Förpackning -> Aktivera ProGuard, som på utskriftsskärmen nedan:
Detta gör det möjligt för ProGuard när du bygger din app.
Xamarin.Android ställer som standard in sina egna konfigurationer för ProGuard, som kan hittas i mapparna obj/Debug/proguard
eller obj/Release/proguard
, i filerna proguard_project_primary.cfg
, proguard_project_references.cfg
och proguard_xamarin.cfg
. De tre filerna kombineras som konfigurationer för ProGuard och de skapas automatiskt av Xamarin när man bygger.
Om utvecklaren vill anpassa ProGuard-alternativen ytterligare kan han / hon skapa en fil i projektets rot med namnet proguard.cfg
(andra namn är också giltiga, så länge tillägget är .cfg) och sätter sin Build Action till ProguardConfiguration, som på bilden nedan:
I filen kan anpassade ProGuard-alternativ sättas in, t.ex. -dontwarn
, -keep class
och andra .
Viktig
Som nu (april / 2017) har Android SDK som vanligtvis laddas ner en gammal version av ProGuard, vilket kan orsaka fel när appen byggs med Java 1.8. När du bygger visar fellistan följande meddelande:
Error
Can't read [C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v7.0\mono.android.jar]
(Can't process class [android/app/ActivityTracker.class] (Unsupported class version number [52.0] (maximum 51.0, Java 1.7))) [CREATEMULTIDEXMAINDEXCLASSLIST]
För att åtgärda problemet måste du ladda ner den senaste versionen av ProGuard ( här ) och kopiera innehållet i .zip-filen till android-sdk\tools\proguard\
. Det kommer att uppdatera ProGuard och byggprocessen bör köras utan problem.
Efter det borde du kunna bygga din Xamarin.Android-app med ProGuard framgångsrikt.
"Mystiska" buggar relaterade till ProGuard och Linker
Du gjorde en bra app och testade den i Debug, med bra resultat. Allt fungerade bra!
Men sedan bestämde du dig för att förbereda din app för släppning. Du skapade MultiDex, ProGuard och Linker, och sedan slutade det fungera.
Denna tutorial syftar till att hjälpa dig ta reda på vanliga problem relaterade till ProGuard och Linker som kan orsaka mystiska buggar.
Förstå Xamarin.Linker
Xamarin.Linker är ett verktyg i byggprocessen som tar bort oanvänd kod och klasser från din .NET-kod (inte Java-kod) . I ditt projekt Egenskaper -> Android-alternativ -> Linker kommer det att finnas en valruta Länka med alternativen:
Inget : Ingen kod tas bort.
Sdk Assemblies Only : Detta alternativ gör att Xamarin.Linker endast kan kontrollera om oanvänd kod inte finns i Xamarin-biblioteken. Det här alternativet är säkert.
Sdk- och användarförsamlingar : Detta alternativ gör att Xamarin.Linker ska kontrollera om oanvänd kod i Xamarin-biblioteken och i projektkoden (inklusive PCL: er, Xamarin-komponenter och NuGet-paket). Det här alternativet är inte alltid säkert!
När du använder alternativet Sdk och User Assemblies kan Xamarin.Linker tro att delar av koden är oanvända när de faktiskt används mycket! Det kan leda till att vissa bibliotek slutar fungera korrekt och orsaka fel i din app.
För att göra att Xamarin.Linker inte tar bort kod finns det tre alternativ:
- Ställa in länkalternativet till Inget eller Sdk Assemblies Only;
- Hoppa över länkande enheter;
- Använd attributet Bevara.
Exempel för 2. Hoppa över länkande enheter:
I exemplet nedan orsakade användning av Xamarin.Linker ett NuGet-paket ( Octokit ) som fungerar bra för att sluta fungera, eftersom det inte kunde ansluta till internet längre:
[0:] ERROR
[0:] SOURCE: mscorlib
[0:] MESSAGE: Object reference not set to an instance of an object.
[0:] STACK TRACE: at Octokit.PocoJsonSerializerStrategy.DeserializeObject (System.Object value, System.Type type) [0x003d8] in D:\repos\octokit.net\Octokit\SimpleJson.cs:1472
at Octokit.Internal.SimpleJsonSerializer+GitHubSerializerStrategy.DeserializeObject (System.Object value, System.Type type) [0x001c3] in D:\repos\octokit.net\Octokit\Http\SimpleJsonSerializer.cs:165
at Octokit.SimpleJson.DeserializeObject (System.String json, System.Type type, Octokit.IJsonSerializerStrategy jsonSerializerStrategy) [0x00007] in D:\repos\octokit.net\Octokit\SimpleJson.cs:583
at Octokit.SimpleJson.DeserializeObject[T] (System.String json, Octokit.IJsonSerializerStrategy jsonSerializerStrategy) [0x00000] in D:\repos\octokit.net\Octokit\SimpleJson.cs:595
at Octokit.Internal.SimpleJsonSerializer.Deserialize[T] (System.String json) [0x00000] in D:\repos\octokit.net\Octokit\Http\SimpleJsonSerializer.cs:21
at Octokit.Internal.JsonHttpPipeline.DeserializeResponse[T] (Octokit.IResponse response) [0x000a7] in D:\repos\octokit.net\Octokit\Http\JsonHttpPipeline.cs:62
at Octokit.Connection+<Run>d__54`1[T].MoveNext () [0x0009c] in D:\repos\octokit.net\Octokit\Http\Connection.cs:574
--- End of stack trace from previous location where exception was thrown ---
För att få biblioteket att börja fungera igen, var det nödvändigt att lägga till paketets referensnamn i fältet Hoppa över länkaggregat, som finns i projektet -> Egenskaper -> Android-alternativ -> Linker, som på bilden nedan:
Efter det började biblioteket fungera utan problem.
Exempel för 3. Använd attributet Bevara:
Xamarin.Linker uppfattar som oanvänd kod mestadels kod från modellklasser i projektets kärna.
För att klassen ska bevaras under länkprocessen kan du använda attributet Bevara.
Skapa först i din projektkärna en klass som heter PreserveAttribute.cs , sätt in följande kod och ersätt namnområdet med projektets namnområde:
PreserveAttribute.cs:
namespace My_App_Core.Models
{
public sealed class PreserveAttribute : System.Attribute
{
public bool AllMembers;
public bool Conditional;
}
}
I varje modellklass i projektets kärna, infoga attributet Spara som i exemplet nedan:
Country.cs:
using System;
using System.Collections.Generic;
namespace My_App_Core.Models
{
[Preserve(AllMembers = true)]
public class Country
{
public String name { get; set; }
public String ISOcode { get; set; }
[Preserve(AllMembers = true)]
public Country(String name, String ISOCode)
{
this.name = name;
this.ISOCode = ISOCode;
}
}
}
Efter det kommer länkningen inte längre att ta bort den bevarade koden.
Förstå ProGuard
ProGuard är ett verktyg i byggprocessen som tar bort oanvänd kod och klasser från din Java-kod . Det döljer också och optimerar koden.
ProGuard kan emellertid ibland ta bort kod som den uppfattar som oanvänd när den inte är det. För att undvika det måste utvecklaren felsöka appen (i Android Device Monitor och i Visual Studio Debug) och upptäcka vilken klass som har tagits bort för att sedan konfigurera ProGuard-konfigurationsfilen för att behålla klassen.
Exempel
I exemplet nedan tog ProGuard bort två klasser (Android.Support.V7.Widget.FitWindowsLinearLayout och Android.Support.Design.Widget.AppBarLayout) som används i AXML-layoutfiler, men som upplevdes som oanvända i koden. Avlägsnandet orsakade ClassNotFoundException i Java-koden vid rendering av aktivitetslayouten:
layout_activitymain.axml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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/activitymain_drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" <!-- ### HERE ### -->
tools:openDrawer="start">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- ### HERE ## -->
<android.support.design.widget.AppBarLayout
android:id="@+id/activitymain_appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
...
LogCat visar fel när du skapar layouten i SetContentView:
För att åtgärda det här felet var det nödvändigt att lägga till följande rader i ProGuard-konfigurationsfilen för projektet:
-keep public class android.support.v7.widget.FitWindowsLinearLayout
-keep public class android.support.design.widget.AppBarLayout
Efter det visades inga fler fel när layouten skapades.
ProGuard-varningar
ProGuard visar ibland varningar i fellistan efter att du har byggt ditt projekt. Även om de ställer en fråga om din app är OK eller inte, indikerar inte alla deras varningar problem, särskilt om din app framgångsrikt bygger.
Ett exempel för detta är när du använder Picasso- biblioteket: när du använder ProGuard kan det här visa varningar som okio.Okio: can't find referenced class (...)
eller can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [okhttp.jar:META-INF/MANIFEST.MF]) (...)
, men appen bygger och biblioteket fungerar utan problem.