web-dev-qa-db-ja.com

Gradle Androidさまざまなプロセッサアーキテクチャ向けのビルド

Gradleを使用して、4つの異なるAndroid CPUプロセッサアーキテクチャ(armeabi armeabi-v7a x86 mips)用に4つの個別のapkを構築したい。

libsフォルダーに4つのCPUアーキテクチャ用に構築されたネイティブOpenCVライブラリがあります。

libs
    -armeabi
    -armeabi-v7a
    -x86
    -mips

各apkには、正しいCPUアーキテクチャに対応するOpenCVライブラリのみが含まれるようにします。

現在のビルドスクリプトは次のとおりです。

apply plugin: 'Android'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile project(':workspace:OpenCV4Android:sdk:Java')
}

Android {
    compileSdkVersion 11
    buildToolsVersion "18.1.0"

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            Java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        // Move the tests to tests/Java, tests/res, etc...
        instrumentTest.setRoot('tests')

        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')

        flavorGroups "abi", "version"
        productFlavors {
            x86 {
                flavorGroup "abi"
            }
            arm {
                flavorGroup "abi"
            }
            mips {
                flavorGroup "abi"
            }
        }

    }
}

誰かがこれを解決するのを手伝ってくれますか?

乾杯、

32
Blukee

Android Gradleプラグインバージョン13の時点で、新しい「分割」メカニズムを使用して個別のAPKを生成できるようになりました。これについて読むことができます here

.soファイルを配置するためのデフォルトのファイル構造は次のとおりです。

src
-main
  -jniLibs
    -armeabi
      -arm.so
    -armeabi-v7a
      -armv7.so
    -x86
      -x86.so
    -mips
      -mips.so

.soファイルの名前は、拡張子が.soである限り重要ではないことに注意してください。

その後、Gradleビルドファイルで:

Android {
...
splits {
abi {
  enable true
  reset()
  include 'x86', 'armeabi-v7a', 'mips', 'armeabi'
  universalApk false
  }
 }
}

そして

// map for the version code
ext.versionCodes = ['armeabi-v7a':1, mips:2, x86:3]

import com.Android.build.OutputFile

Android.applicationVariants.all { variant ->
    // assign different version code for each output
    variant.outputs.each { output ->
        output.versionCodeOverride =
            project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000000 + Android.defaultConfig.versionCode
    }
}

上記のext.versionCodesのバージョンコードはほとんど無関係であることに注意してください。これは、各ABIタイプに一意のオフセットを追加して、バージョンコードが衝突しないようにするためのものです。

25
withoutclass

Gradle用の分割ABI APKソリューションは、私がこれまでに見つけた最も単純なものです。 @withoutclassはここに良い記事があります: https://stackoverflow.com/a/26129447/254573 Androidドキュメントは新しい機能なので参照しなければなりませんでした引き続き変更可能: http://tools.Android.com/tech-docs/new-build-system/user-guide/apk-splits

ただし、太ったビルドとアーキテクチャ固有のビルドの両方をサポートする必要があるため、この単純な実装を放棄することになりました。 Google Playストア(アーキテクチャ固有のAPKをサポート)とAmazon Appstore(ファットAPKのみをサポート)の両方をサポートしている場合、この同じ問題が発生する可能性があります。

フレーバーコンポーネントを追加できる場合は、分割APKでこれを行うことが可能かもしれませんが、現在のところsplit + flavorはまだサポートされていません: https://code.google.com/p/Android/issues/detail?id = 76469

最終的にabiFilterを使用しました。以下のサンプルコードを参照してください。

Android {
    flavorDimensions "abi"

    productFlavors {
        fat {
            flavorDimension "abi"
            ndk {
                abiFilters "x86", "armeabi-v7a", "armeabi"
                versionCode = 0;
            }
        }
        arm {
            flavorDimension "abi"
            ndk {
                abiFilter "armeabi"
                versionCode = 1;
            }
        }
        armv7a {
            flavorDimension "abi"
            ndk {
                abiFilter "armeabi-v7a"
                versionCode = 3;
            }
        }
        x86 {
            flavorDimension "abi"
            ndk {
                abiFilter "x86"
                versionCode = 6;
            }
        }
    }
}

// Each APK needs a different version code when submitted to Google,
// bump the versionCode we set in defaultConfig
Android.applicationVariants.all { variant ->
    // Ugly hard coded flavorDimensions position
    // If you have more than one flavorDimension, make sure to target the position for "abi"
    def abiVersion = variant.productFlavors.get(0).versionCode

    variant.mergedFlavor.versionCode = abiVersion * 1000 + Android.defaultConfig.versionCode
}

Updatetrueに設定されたuniversalApkを使用すると、このソリューションが解決され、単に各apkをビルドする時間が追加されます。

Android {
    // Rest of Gradle file
        splits {
            abi {
            enable true
            reset()
            include 'armeabi', 'armeabi-v7a', 'x86'
            universalApk true
        }
    }
}

//Ensures architecture specific APKs have a higher version code
//(otherwise an x86 build would end up using the arm build, which x86 devices can run)
ext.versionCodes = [armeabi:1, 'armeabi-v7a':3, x86:6]

Android.applicationVariants.all { variant ->
    // assign different version code for each output
    variant.outputs.each { output ->
        int abiVersionCode = project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) ?: 0
        output.versionCodeOverride = (abiVersionCode * 1000) + Android.defaultConfig.versionCode
    }
}
14

更新-この投稿の時点から、gradleビルドプロセスには多くの進歩があったため、この回答は推奨されるベストプラクティスではない可能性があり、新しい変更がブレーキをかけることさえあります。独自の裁量を使用してください。

そのためには、まず、ネイティブライブラリを次のフォルダー階層に個別に配置する必要があります。

lib
 -armeabi
  -arm.so
  -*.so

-

lib
 -x86
  -x86.so
  -*.so

次に、lib( 's'なし)フォルダー(例:arm.Zipおよびx86.Zip)をZip圧縮し、 'Zip'拡張子を 'jar'(たとえば、arm.jarおよびx86.jar)に変更します。これらのjarを適切なフォルダー(例:armeabi/libsおよびx86/libs)に入れます。次に、各フレーバーの依存関係を含めます。ただし、「コンパイルファイル '....'」は使用できません。 「flavorCompile file '...'」を使用する必要があります

例えば.

    flavorGroups 'abi'
        productFlavors {
            arm {
                flavorGroup 'abi'
                dependencies {
                    armCompile files('arm/libs/armeabi.jar')
                }
            }
            x86 {
                flavorGroup 'abi'
                dependencies {
                    x86Compile files('x86/libs/x86.jar')
                }
            }

    }

====

ここに、より複雑な環境があります。プロセッサアーキテクチャのバリアントだけでなく、プロセッサ用のデバッグライブラリ(。jar、。so)もあります。この例には、Armデバッグ用のDebug.jarおよびArmリリース用のNonDebug.jarがあります。そして、ArmとX86の両方の* .so。このような構成は、gradleを使用することで実現できます ExtraPropertiesExtension 読んでくださいSOここに答えてください https://stackoverflow.com/a/19941684/319058 、デバッグフォルダーの構造化方法を理解します。

Android {
compileSdkVersion 18
buildToolsVersion "19.0.0"

final DEBUG_ROOT = "build-types/debug"
final RELEASE_ROOT = "build-types/release"
project.ext.set("projRoot", "")
buildTypes {
    debug {
        project.projRoot = DEBUG_ROOT

        dependencies {
            debugCompile files(DEBUG_ROOT+"/libs/Debug.jar")
        }
    }

    release {
        project.projRoot = RELEASE_ROOT
        dependencies {
            releaseCompile files(RELEASE_ROOT+"/libs/NonDebug.jar")
        }
        runProguard true
        proguardFile 'proguard.cfg'
    }
}
sourceSets {

    final PROJ_ROOT = project.ext.get("projRoot")
    final BUILD_TYPE_RES = PROJ_ROOT + "/res"
    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        Java.srcDirs = ['src/main/Java']
        //resources.srcDirs = ['src/main']
        //aidl.srcDirs = ['src/main']
        //renderscript.srcDirs = ['src/main']
        res.srcDirs = ['src/main/res',BUILD_TYPE_RES]
        assets.srcDirs = ['src/main/assets']
    }

    flavorGroups 'abi'
    productFlavors {
        arm {
            flavorGroup 'abi'
            final ARM_LIB_PATH = PROJ_ROOT + "/arm/libs/armeabi.jar"
            dependencies {
                armCompile files(ARM_LIB_PATH)
            }
        }
        x86 {
            flavorGroup 'abi'
            final X86_LIB_PATH = PROJ_ROOT + "/x86/libs/x86.jar"
            dependencies {
                x86Compile files(X86_LIB_PATH)
            }
        }

    }

    // Move the tests to tests/Java, tests/res, etc...
    instrumentTest.setRoot('tests')

    // Move the build types to build-types/<type>
    // For instance, build-types/debug/Java, build-types/debug/AndroidManifest.xml, ...
    // This moves them out of them default location under src/<type>/... which would
    // conflict with src/ being used by the main source set.
    // Adding new build types or product flavors should be accompanied
    // by a similar customization.
    debug.setRoot(DEBUG_ROOT)
    release.setRoot(RELEASE_ROOT)
}

}

4
Win Myo Htet

私はgradleの答えを持っていませんが、私は今、任意のAndroidビルドツールのための一般的な答えを持っていると思います。サポートされているプロセッサアーキテクチャごとに別々のAPKファイルを作成する方法に関する私のアイデアは次のとおりです:

  1. サポートしているすべてのネイティブコードライブラリを含む、使用するツールでAPKをビルドします。 armeabi、armeabi-v7a、x86、およびmips。 「元の」APKファイルと呼びます。

  2. Zip/unzipユーティリティを使用して元のAPKを空のフォルダーに解凍します。コマンドラインツールを使用すると、シェルスクリプトまたはバッチファイルで後で自動化できます。

  3. 元のAPKが圧縮解除されたフォルダーで、META-INFサブフォルダーを削除します(これには署名が含まれます。すべての変更後にAPKに再署名する必要があるため、元のMETA-INFを削除する必要があります)。

  4. Libサブフォルダーに変更し、新しいAPKファイルで不要なプロセッサーアーキテクチャのサブフォルダーを削除します。たとえば、Intel Atomプロセッサ用のAPKを作成するには、 'x86'サブフォルダのみを残します。

  5. 重要:異なるアーキテクチャの各APKには、AndroidManifest.xmlの異なる「versionCode」番号と、たとえばarmeabi-v7aはarmeabiのそれよりもわずかに高い必要があります(複数のAPKを作成するためのGoogleの指示はこちら: http://developer.Android.com/google/play/publishing/multiple-apks.html )。残念ながら、マニフェストファイルはAPK内でコンパイルされたバイナリ形式です。 versionCodeを変更するための特別なツールが必要です。下記参照。

  6. マニフェストが新しいバージョンコードで変更され、不要なディレクトリとファイルが削除されたら、小さなAPKを再圧縮し、署名し、調整します(Android SDK)のjarsignerおよびzipalignツールを使用します。

  7. サポートする必要がある他のすべてのアーキテクチャに対してこのプロセスを繰り返し、わずかに異なるバージョンコード(ただし同じバージョン名)で小さなAPKファイルを作成します。

唯一の顕著な問題は、バイナリマニフェストファイルの「versionCode」を変更する方法です。私はこれに対する解決策を長い間見つけることができなかったので、最終的に座ってこれを行うために自分のコードをクランクする必要がありました。出発点として、Javaで書かれた http://code.google.com/p/apk-extractor/ のPrasanta PaulによるAPKExtractorを使用しました。私は古い学校であり、C++にまだ慣れているので、C++で書かれた小さなユーティリティプログラム「aminc」がGitHubの次のサイトにあります

https://github.com/gregko/aminc

Visual Studio 2012ソリューション全体を投稿しましたが、プログラム全体は単一の.cppファイルであり、おそらくどのプラットフォームでもコンパイルできます。次に、atVoice.apkという名前の「脂肪」apkをatVoice_armeabi.apk、atVoice_armeabi-v7a.apk、atVoice_x86.apk、atVoice_mips.apkという4つの小さなファイルに分割するために使用するサンプルのWindows .batファイルを示します。実際にこれらのファイルをGoogle Playに送信し(私のアプリを https://play.google.com/store/apps/details?id=com.hyperionics.avar で参照してください)、すべて正常に動作します。 JorgeSuárezde LisによるこのGithubプロジェクト もご覧ください。Linux向けの同様のスクリプトを投稿しています。

@echo off
REM    My "fat" apk is named atVoice.apk. Change below to whatever or set from %1
set apkfile=atVoice
del *.apk

REM    My tools build atVoice-release.apk in bin project sub-dir. 
REM    Copy it here for splitting.
copy ..\bin\%apkfile%-release.apk %apkfile%.apk

Zip -d %apkfile%.apk META-INF/*

REM ------------------- armeabi ------------------------
unzip %apkfile%.apk AndroidManifest.xml
copy/y %apkfile%.apk %apkfile%.Zip
zip -d %apkfile%.Zip lib/armeabi-v7a/* lib/x86/* lib/mips/*
aminc AndroidManifest.xml 1
Zip -f %apkfile%.Zip
ren %apkfile%.Zip %apkfile%_armeabi.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.Android\Hyperionics.keystore -storepass MyPass %apkfile%_armeabi.apk MyKeyName
zipalign 4 %apkfile%_armeabi.apk %apkfile%_armeabi-aligned.apk
del %apkfile%_armeabi.apk
ren %apkfile%_armeabi-aligned.apk %apkfile%_armeabi.apk

REM ------------------- armeabi-v7a ---------------------
copy/y %apkfile%.apk %apkfile%.Zip
zip -d %apkfile%.Zip lib/armeabi/* lib/x86/* lib/mips/*
aminc AndroidManifest.xml 1
Zip -f %apkfile%.Zip
ren %apkfile%.Zip %apkfile%_armeabi-v7a.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.Android\Hyperionics.keystore -storepass MyPass %apkfile%_armeabi-v7a.apk MyKeyName
zipalign 4 %apkfile%_armeabi-v7a.apk %apkfile%_armeabi-v7a-aligned.apk
del %apkfile%_armeabi-v7a.apk
ren %apkfile%_armeabi-v7a-aligned.apk %apkfile%_armeabi-v7a.apk

REM ------------------- x86 ---------------------
copy/y %apkfile%.apk %apkfile%.Zip
zip -d %apkfile%.Zip lib/armeabi/* lib/armeabi-v7a/* lib/mips/*
aminc AndroidManifest.xml 9
Zip -f %apkfile%.Zip
ren %apkfile%.Zip %apkfile%_x86.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.Android\Hyperionics.keystore -storepass MyPass %apkfile%_x86.apk MyKeyName
zipalign 4 %apkfile%_x86.apk %apkfile%_x86-aligned.apk
del %apkfile%_x86.apk
ren %apkfile%_x86-aligned.apk %apkfile%_x86.apk

REM ------------------- MIPS ---------------------
copy/y %apkfile%.apk %apkfile%.Zip
zip -d %apkfile%.Zip lib/armeabi/* lib/armeabi-v7a/* lib/x86/*
aminc AndroidManifest.xml 10
Zip -f %apkfile%.Zip
ren %apkfile%.Zip %apkfile%_mips.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.Android\Hyperionics.keystore -storepass MyPass %apkfile%_mips.apk MyKeyName
zipalign 4 %apkfile%_mips.apk %apkfile%_mips-aligned.apk
del %apkfile%_mips.apk
ren %apkfile%_mips-aligned.apk %apkfile%_mips.apk


del AndroidManifest.xml
del %apkfile%.apk
:done

グレッグ

3
gregko