web-dev-qa-db-ja.com

Gradleを使用して外部ライブラリを分割されたdexファイルに分割して解決するAndroid Dalvik 64kメソッドの制限

Gradleを使用して64kメソッドの制限を解決するproper/easyの方法はありますか?

つまり、単一のclasses.dexの代わりに、事前に定義されたjarを使用して個別のdexファイルを作成するカスタムGradleタスクを意味します。

ありがとうございました

イワン

現在の状態

現在、私はGMSと格闘中です。GMSはAnalyticsを使用するための2万の方法を取り入れています。私はProguardを使用して不要なものを取り除きますが、それでも... 72kのメソッドとカウント...

dxパラメータ-multi-dexを使用して、classes.dexを2つのファイルに分割できます。手動編集で実現しました

sdk/build-tools/Android-4.4W/dx

そしてこのように最後の行を編集します:

exec Java $javaOpts -jar "$jarpath" --multi-dex "$@"

APKファイルに__classes.dex__ and __classes2.dex__が含まれるようになりました。

私はいくつかの方法で2番目のファイルを動的にロードしようとしています:

残念ながら、まだ運がありません。 Google/Facebook/Squareの第一人者が適切な解決策を提供できることを本当に望んでいます。

22
Ivan Morgillo

Android Gradleプラグイン2.2.0の更新:dexタスクにアクセスできませんもう、しかし代わりにadditionalParametersdexOptionsの一部として導入されました。

Android {
  dexOptions {
    additionalParameters += '--minimal-main-dex'
    // additionalParameters += '--main-dex-list=$projectDir/<filename>'.toString()
    // additionalParameters += '--set-max-idx-number=55000'
  }
}

Android Gradleプラグイン0.14.0の更新:新しいmultiDexEnabled trueディレクティブを介した直接マルチdexサポート( build-tools 21.1.0、サポートリポジトリリビジョン8、およびAndroid Studio 0.9)が必要です。

元の回答:Gradle Androidプラグイン0.9.0以降、実際にはできますこれをアプリの--multi-dexファイルに追加して、build.gradledxに渡します。

afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = ['--multi-dex']
        } else {
            dx.additionalParameters += '--multi-dex'
        }

        // Add more additional parameters like this:
        dx.additionalParameters += '--main-dex-list=class-list.txt'
        dx.additionalParameters += '--minimal-main-dex'
    }
}

これまでのところ、作成については、複数のdexファイルがあります。複数のdexファイルを実際に使用するには、 https://github.com/casidiablo/multidex (これはGoogleの今後のフォークです)を見てください。 MultiDexサポートライブラリ)。

24
sschuberth

Gmsが問題で、gradleを使用している場合

Gmsバージョン6.5以降、個々のAPIライブラリを選択できます

たとえば、MapsAPIのみを含めるには:

compile 'com.google.Android.gms:play-services-maps:6.5.87'

そしてここに完全なリストがあります:

      com.google.Android.gms:play-services-base:6.5.87
      com.google.Android.gms:play-services-ads:6.5.87
      com.google.Android.gms:play-services-appindexing:6.5.87
      com.google.Android.gms:play-services-maps:6.5.87
      com.google.Android.gms:play-services-location:6.5.87
      com.google.Android.gms:play-services-fitness:6.5.87
      com.google.Android.gms:play-services-panorama:6.5.87
      com.google.Android.gms:play-services-drive:6.5.87
      com.google.Android.gms:play-services-games:6.5.87
      com.google.Android.gms:play-services-wallet:6.5.87
      com.google.Android.gms:play-services-identity:6.5.87
      com.google.Android.gms:play-services-cast:6.5.87
      com.google.Android.gms:play-services-plus:6.5.87
      com.google.Android.gms:play-services-appstate:6.5.87
      com.google.Android.gms:play-services-wearable:6.5.87
      com.google.Android.gms:play-services-all-wear:6.5.87
8
idanakav

さまざまなdexファイルを分割してロードするプロジェクトの例は次の場所にあります。

https://code.google.com/p/Android-custom-class-loading-sample/

編集:Gradleについてはすでに答えがあります

Gradleを使用したDalvikでのカスタムクラスの読み込み(Android New Build System)

2
kikoso

私は https://github.com/creativepsyco/secondary-dex-gradle/ のメンテナーであり、gradle n00bなので、BASHスクリプトのパスを選択しましたが、実行できると思います。ビルドファイルに直接。 ORプラグインとして実行するようにリファクタリングすることができますが、Gradleに慣れ親しんでいるときにそうするかもしれません。これが私のロジックの理由です。

DEXを分割する方法を理解するには、ビルドシステムのタスク順序を知っている必要があります。 gradleを使用している場合は、ビルドサイクル内に一連のタスクが挿入されていることを知っておく必要があります。

例えば:

:sdk:processReleaseJavaRes UP-TO-DATE
:sdk:packageReleaseJar
:sdk:compileReleaseNdk UP-TO-DATE
:sdk:packageReleaseJniLibs UP-TO-DATE
:sdk:packageReleaseLocalJar UP-TO-DATE
:sdk:packageReleaseRenderscript UP-TO-DATE
:sdk:packageReleaseResources UP-TO-DATE
:sdk:bundleRelease
:app:prepareComAndroidSupportAppcompatV71910Library UP-TO-DATE
:app:prepareComFacebookAndroidFacebook3141Library UP-TO-DATE
:app:prepareDebugDependencies
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:compileDebugJava
:app:preDexDebug
:app:dexDebug
:app:processDebugJavaRes UP-TO-DATE
:app:validateReleaseConfigSigning
:app:packageDebug
:app:zipalignDebug
:app:assembleDebug

Dexingを実行するには、dex *タスクとprocess *タスクの間にカスタムタスクを挿入できる必要があります。これができれば、Multiple DEXingが簡単になります。

Bashスクリプト here は基本的にこれを実行します。デバッグタスクを調べると、基本的に次のようになります。

  • Library Jarファイルをdexに取得します。通常、これはビルド固有であり、Android Librariesのexploded-aarフォルダーに存在し、DEXツールを実行します
  • これを、アプリ内にパッケージ化される最終的なlibsフォルダーにあるassetsフォルダーにコピーします。
  • すべてのライブラリリソースなどはすでにマージされています。つまり、ファイルを再度解凍して圧縮する必要があります。

gradle build script

 // For Debug simply remove the library from getting dex and create it
                //----------------------- Extra Debug Step ----------------//
                def libraryFiles = new ArrayList<?>()
                def secondaryFile = new ArrayList<?>()

                variant.dex.libraries.each {
                    File file ->
                        if (!file.absolutePath.contains("lib/unspecified/classes.jar")) {
                            libraryFiles.add(file)
                        } else {
                            secondaryFile.add(file)
                        }
                }
                variant.dex.libraries = libraryFiles
                //----------------------- Extra Debug Step ----------------//

                packagingTask.dependsOn variant.javaCompile
            }

これは手動でライブラリをdexedから削除し、bashスクリプトを介して生成できるようにします。

リリースプロセス中のデキシングも同じように理解できると思います。注意すべき他の重要なことは、ProguardタスクがAndroid gradleプラグインによって制御されており、それについてあまり変更できないことです。Proguardルールの問題:

  • プロガードの各パスは異なります。2つのDEXが異なるプロガードマッピングを持つ状況になりたくありません。
  • これにより、ライブラリを保護できない状況に陥りますが、これはあまり望ましくありません。
  • マッピングが同じであることを確認するために、proguardの後にdexファイルを生成する必要があります。 Gradleは、Proguard後のアセットのマージをサポートしていません(dexファイルをアセットフォルダーに配置したいと考えています)

他の重要なコードチャンクは SecondaryDex.Java にあり、これは基本的に2番目のdexファイルをロードし、DEXファイルのパスをランタイムクラスパスに挿入します。これを最適化して、アプリが再開されるたびにDEXファイルを読み取る代わりに、パスを挿入するだけで済みます。

Google Play開発者サービス(20Kメソッドを追加)で2番目のDex実験を行い、別のDEXファイルに分離することができました。このようにして、私のメインのdexファイルはGooglePlay開発者サービスの肥大化の影響を受けません。

Gradleタスクサイクルがどのように機能するかを理解するには、 BasePlugin.groovy ソースを参照してください。バリアントオブジェクトにアクセスしてタスクをビルドするための適切なAPIが存在するまで、一部の側面を制御するのが難しいことがわかります。 。

2
redDragonzz