サーチ…


前書き

このトピックでは、Xamarin.Androidアプリのリリースモードの準備方法と最適化方法について説明します。

Visual StudioでのAPKの準備

あなたはあなたのアプリを終了し、デバッグモードでテストし、完璧に動作しています。これで、Google Playストアで公開する準備を整えます。

Xamarinのドキュメントは、ここに良い情報を提供しています:

https://developer.xamarin.com/guides/android/deployment,_testing,_and_metrics/publishing_an_application/


Androidマニフェスト

まず、Visual Studioで、ソリューションエクスプローラでXamarin.Androidプロジェクトを右クリックし、[プロパティ]を選択します。次に、Android Manifestタブに移動してこの画面を表示します:

Androidマニフェスト設定

Android StudioやEclipseとは異なり、AndroidManifest.xmlファイルを作成する必要はありません。 XamarinとVisual Studioはこれを行います。アクティビティ、ブロードキャスト受信者、サービスは、クラス内の特定の属性を宣言することによって、Androidマニフェストに挿入されます

この画面では、次のオプションがあります。

  • アプリケーション名 :これはユーザーに表示されるアプリ名です。
  • パッケージ名 :これはパッケージ名です。これは一意である必要があります。つまり、Google Playストア内の他のアプリと同じパッケージ名を使用してはいけません。
  • アプリケーションアイコン :これは、AndroidスタジオまたはEclipseプロジェクトで使用される@ drawable / ic_launcherと同等の、ユーザーに表示されるアイコンです。
  • バージョン番号 :バージョン番号はGoogle Playでバージョン管理に使用されます。アップデートされたバージョンのAPKを公開する場合は、新しいアップグレードごとにこの番号に1を追加する必要があります。
  • バージョン名 :これはユーザーに表示されるバージョン名です。
  • インストール先 :APKのインストール先をデバイスストレージまたはSDカードに指定します。
  • 必要な権限 :ここでは、あなたのアプリケーションに必要な権限を決定します。

Androidオプション

以下の画面では、コンパイラオプションを設定できます。ここで適切なオプションを使用すると、APKサイズを大幅に削減し、エラーを防ぐことができます。

Androidオプションの設定

  • 設定アクティブ(リリース)
  • プラットフォームアクティブ(任意のCPU) 。これらはGoogle Playストア向けにAPKを構築するために必要です。設定が[デバッグ]に設定されている場合は、Google Playで受け付けられません。
  • 共有ランタイムを使用するfalse 。これをtrueに設定すると、APKはMono Runtimeを使用して実行します。 Monoランタイムは、USB経由でデバッグすると自動的にインストールされますが、リリースAPKではインストールされません。 Mono Runtimeがデバイスにインストールされておらず、リリースAPKでこのオプションがtrueに設定されていると、アプリがクラッシュします。
  • 選択したABIあたり一つのパッケージ(の.apk)を生成します。互換性の理由から、可能な限り多くのプラットフォーム用にAPKを作成してください。
  • Enable Multi-Dextrueですが、アプリがあまり複雑でない場合(つまり、65536未満のメソッドがある場合は、ここを参照 )、falseに設定できます。
  • :ProGuardの有効にします 。これにより、アプリ内のJavaコードを難読化するProguardツールが有効になります。 .NETコードには適用されません。 .NETコードを難読化する場合は、 Dotfuscatorを使用する必要があります 。 Proguard for Xamarin.Androidの詳細はこちらをご覧ください
  • 開発者計測(デバッグとプロファイリング)を有効にする :APKをリリースする場合はfalse
  • リンクSDKとユーザーアセンブリこれにより、Xamarin LinkerはSDKおよびコードから未使用のクラスをすべて削除し、APKサイズを縮小します。

重要

Xamarin.Linkerは、特にプロジェクトのコア(PCLライブラリ)にある場合、コードで使用されていないようなクラスを削除することがあります。これを避けるには、リンクを「Sdkアセンブリのみ」に設定するか、クラスのPreserve属性を使用します(例:

PreserveAttribute.cs

namespace My_App_Core.Models
{
    public sealed class PreserveAttribute : System.Attribute
    {
        public bool AllMembers;
        public bool Conditional;
    }
}

クラス内:

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;
        }
    }
}
  • サポートされているアーキテクチャ :互換性の理由から、 すべてを選択します

すべてを構成したら、プロジェクトを再ビルドして、ビルドが正常に行われたことを確認します。


リリースモードでのAPKの作成

リリース用のAndroidプロジェクトの設定が完了しました。以下のチュートリアルでは、Visual StudioでAPKを生成する方法を示します。 Xamarinのドキュメンテーションの完全なチュートリアルはここにあります:

https:/ / / / / /

APKファイルを作成するには、ソリューションエクスプローラでXamarin.Androidプロジェクトを右クリックし、[アーカイブ...]を選択します。

ソリューションエクスプローラ - > Xamarin.Androidプロジェクト - >アーカイブ...を右クリックします。

これにより、アーカイブマネージャが開き、プロジェクトのアーカイブが開始され、APKファイルの作成が準備されます。

アーカイブプロジェクト

プロジェクトのアーカイブが完了したら、[配布...]をクリックして続行します。

分配します...

[配信]画面には、Ad-hocとGoogle Playという2つのオプションが表示されます。最初にAPKが作成され、コンピュータに保存されます。 2番目はGoogle Playでアプリを直接公開します。

最初のものを選択することをお勧めします。必要に応じて他のデバイスでAPKをテストできます。

流通経路

次の画面では、APKに署名するためにAndroid Key Storeが必要です。既に持っている場合は、[インポート...]をクリックして使用できます。そうでない場合は、+をクリックして新しいAndroid Key Storeを作成することができます。

署名アイデンティティ

新しいAndroid Key Store画面の作成:

新しいAndroidキーストアの作成

APKを作成するには、[名前を付けて保存]をクリックします。キーストアパスワードの入力を求められることがあります。

名前を付けて保存

名前を付けて保存 - >フォルダを検索

Enterキーストアパスワード

完了したら、Archives画面のOpen Folderをクリックして、生成されたAPKファイルを確認することができます。

開いたフォルダ

フォルダ内のAPK

Xamarin.Android APKでMultiDexを有効にする

MultiDexは、アプリが65,536以上のメソッドを持つことを可能にするAndroid APKのライブラリです。

Android APKには、Javaコードからコンパイルされた生成されたバイトコードを含むDalvik実行可能ファイル(.dex)があります。各.dexファイルには、最大65,536のメソッド(2 ^ 16)を含めることができます。

Android 5.0 Lollipop(API 21)より前のAndroid OSのバージョンでは、APKあたり1つの.dexファイルしかサポートしないDalvikランタイムが使用され、APKあたり65,536メソッドに制限されています。 Android 5.0以降、Android OSはARTランタイムを使用します.ARTランタイムは、APKごとに複数の.dexファイルをサポートし、制限を回避します。

API 21以下のAndroidバージョンで65kメソッド制限を超えるには、開発者はMultiDexサポートライブラリを使用する必要があります。 MultiDexはclasses.dexファイルでそれらを参照する余分なclasses.dexファイル(classes2.dex、classes3.dex、...)を作成します。アプリは読み込みを開始すると、MultiDexApplicationクラスを使用して余分な.dexファイルを読み込みます。

あなたのAndroidアプリがAPI 21以上(Android 5.0 Lollipop)以上の最小SDKバージョンを目指している場合は、MultiDexライブラリを使用する必要はありません。これは、OSがネイティブに余分な.dexファイルを処理するためです。しかし、互換性の理由から、開発者が古いAndroid OSをサポートしたい場合は、MultiDexライブラリを使用する必要があります。


Xamarin.AndroidアプリでMultiDexを使用する方法

まず、Xamarin.AndroidアプリでMultiDexを有効にするには、以下の印刷画面のように、プロジェクトのプロパティ - > Androidオプション - >パッケージ - >マルチデクスを有効にします。

MultiDexオプションを有効にする

次に、アプリでMultiDexApplicationクラスを作成する必要があります。プロジェクトのルートで、新しいクラスを作成します(ソリューションエクスプローラで、プロジェクトを右クリックし、Add - > Class、またはShift + Alt + C)。新しいクラスファイルで、次のコードをコピーし、名前空間SampleをXamarin.Androidプロジェクト名前空間の名前に置き換えます。

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); }
        }
    }
}

コードソースはこちら。

Visual Studio for Windowsで開発している場合は、プロジェクトをビルドするときにclasses.dexファイルを正しく作成するために修正する必要があるAndroid SDKビルドツールにもバグがあります。

あなたのAndroid SDKフォルダに移動し、build-toolsフォルダを開き、以下のようなAndroid SDKコンパイラの番号のフォルダがあります:

C:\ android-sdk \ build-tools \ 23.0.3 \

C:\ android-sdk \ build-tools \ 24.0.1 \

C:\ android-sdk \ build-tools \ 25.0.2 \

これらのフォルダのそれぞれの内部では、mainClassesDex.batと呼ばれるファイル、classes.dexファイルを作成するために使用されるバッチスクリプトがあります。各mainClassesDex.batファイルをテキストエディタ(メモ帳またはメモ帳++)で開き、スクリプト内でブロックを検索して置き換えます。

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

ブロックの場合:

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

ソースはこちら。

変更後、各mainClassesDex.batをテキストエディタに保存します。

上記の手順を完了すると、MultiDexでXamarin.Androidアプリを正常に構築できるはずです。

Xamarin.Android APKでProGuardを有効にする

ProGuardは、ビルドプロセスでAPKのJavaコードを最適化および難読化し、未使用のクラスを削除するために使用されるツールです。 ProGuardを使用すると、結果として得られるAPKのサイズが小さくなり、リバースエンジニアリング(デコンパイル)が難しくなります。

ProGuardは、Xamarin.Androidアプリでも使用できます。また、APKファイルサイズを縮小し、Javaコードを難読化します。ただし、ProGuardの難読化はJavaコードにのみ適用されます。 .NETコードを難読化するために、開発者はDotfuscatorまたは類似のツールを使用する必要があります。


Xamarin.AndroidアプリでProGuardを使用する方法

まず、Xamarin.AndroidアプリでProGuardを有効にするには、以下の印刷画面のように、プロジェクトのプロパティ - > Androidオプション - >パッケージ - > ProGuardを有効にします。

ProGuardを有効にする

これにより、アプリケーションを構築する際にProGuardが有効になります。

デフォルトでXamarin.Androidは、 obj/Debug/proguard独自の設定を行います。これは、 obj/Debug/proguardまたはobj/Release/proguardフォルダ内のproguard_project_primary.cfgproguard_project_references.cfgおよびproguard_xamarin.cfgファイルにあります。 3つのファイルはProGuardの構成として結合され、構築時にXamarinによって自動的に作成されます。

開発者がProGuardオプションをさらにカスタマイズしたい場合は、プロジェクトのルートproguard.cfgファイルを作成できます(拡張子が.cfgであれば他の名前も有効です)。ビルドアクションをProguardConfigurationに設定すると、下の図のように:

ビルドアクションをProguardConfigurationに設定する

ファイルには、カスタムProGuardのオプションは、次のような、挿入することができます-dontwarn-keep classおよび

重要

今のところ(April / 2017)、通常ダウンロードされるAndroid SDKにはProGuardの旧バージョンが含まれており、Java 1.8を使用してアプリケーションを構築するときにエラーが発生する可能性があります。作成時に、エラーリストに次のメッセージが表示されます。

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]

ソースはこちら。

この問題を解決するには、ProGuardの最新バージョン( ここ )をダウンロードし、.zipファイルの内容をandroid-sdk\tools\proguard\コピーする必要があります。これによりProGuardが更新され、ビルドプロセスは問題なく実行されます。

その後、ProGuardを使用してXamarin.Androidアプリを正常に構築できるはずです。

ProGuardとLinkerに関連する "不思議な"バグ

素晴らしいアプリを作り、デバッグでテストしたところ、良い結果が得られました。すべてがうまくいっていた!

しかし、その後、あなたのアプリをリリースする準備をすることにしました。 MultiDex、ProGuard、Linkerを設定した後、動作を停止します。

このチュートリアルでは、不思議なバグを引き起こす可能性のあるProGuardやLinkerに関連する一般的な問題を見つけるのを支援することを目的としています。


Xamarin.Linkerについて

Xamarin.Linkerは、 Javaコードではなく、.NETコードから未使用のコードとクラスを削除するビルドプロセスのツールです。プロジェクトの[プロパティ] - > [Androidオプション] - > [リンカ]に、オプションとリンクする選択ボックスが表示されます。

リンカオプション

なし :コードは削除されません。

Sdkアセンブリのみ :このオプションを使用すると、Xamarin.LinkerはXamarinライブラリ内の未使用コードをチェックします。 このオプションは安全です。

Sdkとユーザーアセンブリ :このオプションを使用すると、Xamarin.LinkerはXamarinライブラリとプロジェクトコード(PCL、Xamarinコンポーネント、NuGetパッケージを含む)の未使用コードをチェックします。 このオプションは必ずしも安全ではありません!

SdkとUser Assembliesオプションを使用する場合、Xamarin.Linkerは実際にコードが使用されているときにコードの一部が使用されていないと考えるかもしれません。そのため、一部のライブラリが正常に動作しなくなり、アプリにバグが発生する可能性があります。

Xamarin.Linkerがコードを削除できないようにするには、3つのオプションがあります:

  1. リンクオプションを[なし]または[SDアセンブリのみ]に設定する。
  2. アセンブリをスキップする。
  3. Preserve属性の使用。

2.結合アセンブリをスキップする:

下の例では、Xamarin.Linkerを使用すると、もう動作しなくなったNuGet Package( Octokit )が正常に機能しなくなりました。

[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 ---

ライブラリを再び動作させるためには、下の図のように、プロジェクト - >プロパティ - > Androidオプション - >リンカにあるアセンブリのスキップフィールドにパッケージ参照名を追加する必要がありました:

アセンブリをスキップするためのプロジェクト参照の追加

その後、図書館は何の問題もなく仕事を始めました。

3. Preserve属性を使用する例

Xamarin.Linkerは、未使用のコードがプロジェクトのコアにあるモデルクラスのコードのほとんどを認識します。

リンク処理中にクラスを保持するには、Preserve属性を使用します。

まず、プロジェクトのコアにPreserveAttribute.csという名前のクラスを作成し、次のコードを挿入して名前空間をプロジェクトの名前空間に置き換えます。

PreserveAttribute.cs:

namespace My_App_Core.Models
{
    public sealed class PreserveAttribute : System.Attribute
    {
        public bool AllMembers;
        public bool Conditional;
    }
}

プロジェクトのコアの各モデルクラスに、以下の例のようにPreserve属性を挿入します。

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;
        }
    }
}

その後、リンク処理では保存されたコードは削除されません。


ProGuardについて

ProGuardは、 Javaコードから未使用のコードとクラスを削除するビルドプロセスのツールです 。また、コードを難読化して最適化します。

しかし、ProGuardは時には未使用であると認識するコードを削除することがあります。これを避けるには、開発者はAndroidデバイスモニタとVisual Studio Debugでアプリをデバッグし、削除されたクラスを検出してProGuard構成ファイルを設定してクラスを維持する必要があります。

以下の例では、ProGuardはAXMLレイアウトファイルで使用される2つのクラス(Android.Support.V7.Widget.FitWindowsLinearLayoutおよびAndroid.Support.Design.Widget.AppBarLayout)を削除しましたが、コードでは未使用と認識されていました。アクティビティレイアウトのレンダリング時に、JavaコードでClassNotFoundExceptionが削除されました。

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">
...

SetContentViewでレイアウトを作成するときのLogCatのエラー表示:

LogCatでエラーが表示される

このエラーを修正するには、プロジェクトのProGuard構成ファイルに次の行を追加する必要がありました。

-keep public class android.support.v7.widget.FitWindowsLinearLayout
-keep public class android.support.design.widget.AppBarLayout

その後、レイアウトを作成するときにエラーは表示されなくなりました。

ProGuardの警告

ProGuardは、プロジェクトをビルドした後、エラーリストに警告を表示することがあります。彼らはあなたのアプリがOKかどうかの問題を提起しますが、特にあなたのアプリがうまく構築されている場合は、警告のすべてが問題を示しているわけではありません。

使用する際にそのための一つの例は、 ピカソのライブラリを:ProGuardのを使用している場合、これは以下のような警告が表示されることがありokio.Okio: can't find referenced class (...)か、 can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [okhttp.jar:META-INF/MANIFEST.MF]) (...) 、しかし、アプリケーションはビルドし、ライブラリは問題なく動作します。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow