web-dev-qa-db-ja.com

Gradle exclude Java libのクラスは、重複を避けるために独自のクラスに置き換えられました

Android Studio)には、Gradle(src/org/luaj/vm2/lib/jse/JavaMethod.Java)を介してプルされたパッケージから上書きする必要がある特定のファイル(dependencies {compile 'org.luaj:luaj-jse:3.0.1'})があります。

まったく同じパスでファイルをソースディレクトリにコピーし、変更を加えました。これは、それを使用していた個々のJUnitテストケースでは正常に機能していました。また、私のプロジェクトの通常のコンパイルで機能しているように見えます(現時点では簡単に確認できません)。

ただし、ProjectType = "Android Tests"の構成を使用してすべてのテストを一度に実行しようとすると、Error:Error converting bytecode to dex: Cause: com.Android.dex.DexException: Multiple dex files define Lorg/luaj/vm2/lib/jse/JavaMethod$Overload;が表示されます。

プロジェクトがローカルソースディレクトリ内のファイルを確実に選択するために、Gradleファイルに追加する必要のある特定のタスクまたはコマンドはありますか? コピータスクsourceSets->main->Java->excludeコマンドを試しましたが、どちらも機能していないようです(間違って行った可能性があります)。また、「コンパイル」の下にある「モジュール/グループを除外」ディレクティブを この投稿 から試しました。

実行/デバッグ確認のデフォルト以外の設定:

  • Type = Androidテスト
  • モジュール=私のモジュール
  • テスト:すべてパッケージ
  • パッケージ:「テスト」

私のすべてのJUnitテストケースは「テスト」パッケージに含まれています。

これを機能させるどんな答えでも問題ありません。 Gradleでない場合は、おそらくAndroidマニフェストまたはローカルソースファイル自体に何かがあります。

[2016-07-24に編集]エラーは、normalコンパイルでも発生しています(私のAndroidエミュレーターはより低いAPIを実行しています。API16および19はエラーになりますが、API23はエラーになりません。

7
Dakusan

これは、Fabioの提案の後に私が追加したものです:

//Get LUAJ
buildscript { dependencies { classpath 'de.undercouch:gradle-download-task:3.1.1' }}
apply plugin: 'de.undercouch.download'
task GetLuaJ {
    //Configure
    def JARDownloadURL='http://central.maven.org/maven2/org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1.jar' //compile 'org.luaj:luaj-jse:3.0.1'
    def BaseDir="$projectDir/luaj"
    def ExtractToDir='class'
    def ConfirmAlreadyDownloadedFile="$BaseDir/$ExtractToDir/lua.class"
    def JarFileName=JARDownloadURL.substring(JARDownloadURL.lastIndexOf('/')+1)
    def ClassesToDeleteDir="$BaseDir/$ExtractToDir/org/luaj/vm2/lib/jse"
    def ClassNamesToDelete=["JavaMethod", "LuajavaLib"]

    //Only run if LuaJ does not already exist
    if (!file(ConfirmAlreadyDownloadedFile).exists()) {
        //Download and extract the source files to /luaj
        println 'Setting up LuaJ' //TODO: For some reason, print statements are not working when the "copy" directive is included below
        mkdir BaseDir
        download {
            src JARDownloadURL
            dest BaseDir
        }
        copy {
            from(zipTree("$BaseDir/$JarFileName"))
            into("$BaseDir/$ExtractToDir")
        }

        //Remove the unneeded class files
        ClassNamesToDelete=ClassNamesToDelete.join("|")
        file(ClassesToDeleteDir).listFiles().each {
            if(it.getPath().replace('\\', '/').matches('^.*?/(?:'+ClassNamesToDelete+')[^/]*\\.class$')) {
                println "Deleting: $it"
                it.delete()
            }
        }
    }
}

後でjarで直接動作するバージョンをアップロードします。

2
Dakusan

問題:アプリをリンクすると、リンカーは2つのバージョンを見つけます

  • org.luaj:luaj-jse:3.0.1:org.luaj.vm2.lib.jse.JavaMethodおよび
  • {localProject}:org.luaj.vm2.lib.jse.JavaMethod

修正方法:gradleにexclude org.luaj:luaj-jse:3.0.1:org.luaj.vm2.lib.jse.JavaMethodをビルドから指示する

Android {
    packagingOptions {
        exclude '**/JavaMethod.class'
    }
}

私はこれを「excludeclass」で試していませんが、「COPYING」で重複するgplライセンスファイルを削除するために機能します。

この「除外」が機能しない場合は、

  • lib org.luaj:luaj-jse:3.0.1をローカルのlibsフォルダーにダウンロードします。
  • zipアプリでjar/aarを開き、重複するクラスを手動で削除します。
  • org.luaj:luaj-jse:3.0.1がlibフォルダーからロードされるようになったため、依存関係から削除します
7
k3b

私はあなたの問題を完全に理解しているとは思いません。ただし、これはクラスパスの順序の問題のように聞こえますが、実際にはファイルが問題を上書きするわけではありません。

AFAIK、gradleは、「依存関係」セクションからの注文に対して「保証」を行いません。ただし、繰り返し可能になることを除けば。カスタマイズするファイルのバージョンをコンパイルするときに、テスト/システムでそのファイルを使用できるようにするには、複製元のjarファイルよりもクラスパスの前にある必要があります。

幸い、gradleを使用すると、クラスパスの前に「追加」する非常に簡単な方法が可能になります。

sourceSets.main.compileClasspath = file("path/to/builddir/named/classes") + sourceSets.main.compileClasspath

私はあなたのシステムについてそれをよりよく定義するのに十分なことを知りません。ただし、ニーズに合わせて簡単にカスタマイズできるはずです。つまり、必要に応じて、「コンパイル」を他のクラスパス(runtime、testRuntimeなど)の1つに変更できます。また、それがより良い解決策である場合は、classesディレクトリではなく作成するjarfileを指定できます。最適ではないかもしれませんが、クラスパス定義で2回指定することはかなり無害であることを覚えておいてください。

3
JoeG

これはかなり複雑ですが、技術的には実現可能です。しかし、ポスターが尋ねたように、それは単一のタスクではありません:

  1. 上記の依存関係をbuild.gradleから除外し、別のjarに間接的に含まれていないことを確認します(ヒント:./gradlew dependenciesを使用して確認してください)
  2. 上記の依存関係を既知のフォルダーにダウンロードするgradleタスクを作成します
  3. そのようなjarを解凍し、問題のある.classファイルを削除します
  4. コンパイル依存関係としてフォルダーを含める

Linux/Macを使用していると想定しても安全な場合は、項目3で簡単なコマンドラインを実行できます。これは、広く利用可能なコマンドのみを使用しています。

mkdir newFolder ; cd newFolder ; jar xf $filename ; rm $offendingFilePath

自動依存関係管理を気にしない場合は、curlを使用してjarファイルをダウンロードできます。これはLinuxとMacの両方で広く利用できると思います。

curl http://somehost.com/some.jar -o some.jar

より堅牢な実装のために、このような単純なコマンドラインをgroovy/Javaコードに置き換えることができます。 GradleはGroovyのスーパーセットと見なすことができることを知っているのは興味深いことです。これは、ほとんどの点でJavaのスーパーセットであると言えます。つまり、Java/GroovyコードをGradleのほぼどこにでも配置できます。 .buildファイル。クリーンではありませんが、効果的であり、単なる別のオプションです。

4の場合、どちらかに沿って何かを持つことができます

sourceSets.main.Java.srcDirs += ["newFolder/class"]

build.gradleのルートレベル、または

dependencies {
. . . 
   compile fileTree(dir: 'newFolder', include: ['*.class'])
. . . 
2
Fabio