Androidモジュール化プロセスにおけるマルチチャネルコンパイル

6251 ワード

ある賛微商城APPグループはモジュール化の過程でPOS機関連の業務をすべて抽出する必要があるが、POS機の適合コードは複数の業務moduleの中に散らばっているので、モジュール化の過程で本当のマルチチャネルコンパイルに触れた.
余計なことは言わないで、本題に入って、解決策をみんなに分かち合って、友达が回り道をしないことを望んでいます.
では、いつ仲間は私が直面した問題に直面しますか?
  • あなたのプロジェクトはモジュール化され、ビジネスコードは独立したlibraryの
  • に抽出されました.
  • libraryコードでは、BuildConfig.FLAVORでビジネスを区別する必要があります.たとえば、
    if (BuildConfig.FLAVOR.equals("weipos")) {
        // weipos related source
    } else {
        //
    }
    
  • まず、現在のソリューションを出します.
    現在、プロジェクトには多くのルートがありますが、ここでは主にプロジェクトに接続されているPOS機ルート-iboxpay、sunmi、weiposに注目します.私たちのビジネスコードでは、異なるflavorによって異なる機能を実現する必要があります.
    メインエンジニアリングのbuild.gradleファイルでは、以下のflavorを定義します.
    productFlavors {
        def customFlavors = getCustomFlavors()
        if (customFlavors instanceof List) {
            customFlavors.each {
                flavor ->
                    "$flavor"{
                    }
            }
        }
    
        full {
            buildConfigField"boolean","POS","false"
            buildConfigField"String","DEVICE_TYPE","\"android\""
        }
    
        iboxpay {
            buildConfigField"boolean","POS","true"
            buildConfigField"String","DEVICE_TYPE","\"android-iboxpay\""
        }
    
        sunmi {
           buildConfigField"boolean","POS","true"
           buildConfigField"String","DEVICE_TYPE","\"android-sunmi\""
        }
        
        weipos {
            buildConfigField"boolean","POS","true"
            buildConfigField"String","DEVICE_TYPE","\"android-weipos\""
        }
    }
    

    POS機業務と一般業務を区別するためには、コンパイル時に具体的なtask nameに従って区別する必要がある.例えばtaskがassembleSumiDebugであればgroupPosPrefixの値はSummi、buildType Prefixの値はDebugであり、groupPosPrefixの値が私が定義したflavorのIboxpay、Summi、WeiposであればgroupPosの値は「pos」であり、そうでなければ空の文字列である.
    注意:ここでは大文字と小文字の問題に注意し、Summiはsunmiで代用できません.
    // global variables
    ext{
        buildType = ""
        groupPos=""
    }
    
    //start parameters
    println "Start parameters:tasks=" + gradle.startParameter.getTaskNames();
    gradle.startParameter.getTaskNames().each { task->
        def taskParts = splitCamelCase(task.split(":").last());
        def groupPosPrefix = taskParts[taskParts.size() - 2];
        def buildTypePrefix = taskParts[taskParts.size() - 1];
    
        if ("Debug".startsWith(buildTypePrefix)) {
            buildType = 'debug';
        } else if ("Release".startsWith(buildTypePrefix)) {
            buildType = 'release';
        } else { 
            return; // do not process tasks that are not ending with proper build type.
        }
    
        if ("Iboxpay".startsWith(groupPosPrefix)) {
            groupPos = 'pos';
        } else if ("Sunmi".startsWith(groupPosPrefix)) {
            groupPos = 'pos';
        } else if ("Weipos".startsWith(groupPosPrefix)) {
            groupPos = "pos"
        } else {
            groupPos = ""
        }
    }
    
    def splitCamelCase(String word) {
        def result = []
        int nextStart = 0;
        for (int i = 1; i < word.length(); i++) {
            if(word.charAt(i).isUpperCase()) {
                result.add(word.substring(nextStart, i));
                nextStart = i;
            }
        }
    
        result.add(word.substring(nextStart));
        return result;
    }
    
    dependencies {
        if (groupPos =="pos") {
            iboxpayCompile project(':pos_iboxpay')
            iboxpayCompile project(path:':wsc_goods',configuration:'iboxpayRelease')
        
            sunmiCompile project(':pos_sunmi')
            sunmiCompile project(path:':wsc_goods',configuration:'sunmiRelease')
        
            weiposCompile project(':pos_wei')
            weiposCompile project(path:':wsc_goods',configuration:'weiposRelease')
        } else {
            compile project(path:':wsc_goods',configuration:'fullRelease')
        }
    

    このようにgroupPosという変数により,一般業務とPOS業務と他のmoduleとの依存関係を自由に制御でき,一般業務とPOS機業務のコンパイル上の分離が容易に実現できる.
    くりを一つあげる
    この例は商品moduleです.このlibraryではbuildです.gradleでもappのgradleと同じProductFlavorを定義する必要があります.
    productFlavors {
    
        full {
            buildConfigField"boolean","POS","false"
            buildConfigField"String","DEVICE_TYPE","\"android\""
        }
        
        iboxpay {
            buildConfigField"boolean","POS","true"
            buildConfigField"String","DEVICE_TYPE","\"android-iboxpay\""
        }
        
        sunmi {
            buildConfigField"boolean","POS","true"
            buildConfigField"String","DEVICE_TYPE","\"android-sunmi\""
        }
        
        weipos {
            buildConfigField"boolean","POS","true"
            buildConfigField"String","DEVICE_TYPE","\"android-weipos\""
        }
    }
    

    これらのflavorを書き終わったら、publishNonDefault trueという言葉を忘れないでください.そうしないと、対応するconfigurationが見つかりません.
    android {
        publicNonDefault true
    }
    

    なぜcustomFlavorがないのかという仲間がいるかもしれませんが、baidu、wandoujiaなどのカスタムチャネルで使用されているビジネスコードはfullというflavorと同じなので、moduleのbuildでは再び必要ありません.gradleで定義しました.
    appのbuild.gradleと商品libraryのbuild.gradleが上記のように構成されている場合、terminalで実行します./gradlew assembleDebugは、full、sunmi、iboxpay、weiposの4つのチャネルのapkをスムーズにパッケージ化できます.
    まとめ
    ソリューション全体の説明はこれで終わりました.ここにはいくつかの小さな知識点があります.
    どのように自分のプロジェクトの中でどれらのtaskがあることを知っていますか?
    ASでterminalを開き、./を入力します.gradlew tasks,buildが成功するとすべてのtaskが印刷されます
    Build Variantとは何ですか?
  • Build Type + Product Flavor = Build Variant
  • flavorはsunmi、build typeはdebug、build variantはsunmiDebug
  • プロジェクトにflavorがあると、より多くのtaskが作成されますか?
    yesは、次のように作成されます.
    assemble
    assemble
    assemble
    

    library publishって何ですか?
    例えば次の依存
    dependencies {
        flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
    }
    

    lib 1をコンパイルする場合、flavor 1 Releaseバージョンがデフォルトでパッケージされます.
    他に質問があれば、交流を歓迎します.